{"id":13422462,"url":"https://github.com/rill-js/rill","last_synced_at":"2025-05-16T17:07:06.481Z","repository":{"id":57355387,"uuid":"44075730","full_name":"rill-js/rill","owner":"rill-js","description":"🗺 Universal router for web applications.","archived":false,"fork":false,"pushed_at":"2020-12-20T16:35:16.000Z","size":795,"stargazers_count":616,"open_issues_count":0,"forks_count":10,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-05-12T20:41:10.397Z","etag":null,"topics":["isomorphic","middleware","nodejs","router","universal"],"latest_commit_sha":null,"homepage":"https://github.com/rill-js/rill","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rill-js.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-12T00:44:31.000Z","updated_at":"2025-05-05T19:32:48.000Z","dependencies_parsed_at":"2022-08-30T20:00:59.788Z","dependency_job_id":null,"html_url":"https://github.com/rill-js/rill","commit_stats":null,"previous_names":[],"tags_count":61,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rill-js%2Frill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rill-js%2Frill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rill-js%2Frill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rill-js%2Frill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rill-js","download_url":"https://codeload.github.com/rill-js/rill/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254573588,"owners_count":22093731,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["isomorphic","middleware","nodejs","router","universal"],"created_at":"2024-07-30T23:00:45.530Z","updated_at":"2025-05-16T17:07:06.435Z","avatar_url":"https://github.com/rill-js.png","language":"TypeScript","readme":"\u003ch1 align=\"center\"\u003e\n  \u003c!-- Logo --\u003e\n  \u003cimg src=\"https://cdn.rawgit.com/rill-js/rill/master/Rill-Logo.svg\" width=\"300\" alt=\"Rill Logo\"/\u003e\n\n  \u003cbr/\u003e\n\n  \u003c!-- Stability --\u003e\n  \u003ca href=\"https://nodejs.org/api/documentation.html#documentation_stability_index\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/stability-stable-brightgreen.svg?style=flat-square\" alt=\"API stability\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- TypeScript --\u003e\n  \u003ca href=\"http://typescriptlang.org\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/%3C%2F%3E-typescript-blue.svg\" alt=\"TypeScript\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- NPM version --\u003e\n  \u003ca href=\"https://npmjs.org/package/rill\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/rill.svg?style=flat-square\" alt=\"NPM version\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Travis build --\u003e\n  \u003ca href=\"https://travis-ci.org/rill-js/rill\"\u003e\n  \u003cimg src=\"https://img.shields.io/travis/rill-js/rill.svg?style=flat-square\" alt=\"Build status\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Coveralls coverage --\u003e\n  \u003ca href=\"https://coveralls.io/github/rill-js/rill\"\u003e\n    \u003cimg src=\"https://img.shields.io/coveralls/rill-js/rill.svg?style=flat-square\" alt=\"Test Coverage\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Downloads --\u003e\n  \u003ca href=\"https://npmjs.org/package/rill\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dm/rill.svg?style=flat-square\" alt=\"Downloads\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Size --\u003e\n  \u003ca href=\"https://npmjs.org/package/rill\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/gzipped-12.2kb-green.svg\" alt=\"Browser Bundle Size (Gzipped)\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Gitter chat --\u003e\n  \u003ca href=\"https://gitter.im/rill-js/rill\"\u003e\n    \u003cimg src=\"https://img.shields.io/gitter/room/rill-js/rill.svg?style=flat-square\" alt=\"Gitter Chat\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Saucelabs --\u003e\n  \u003ca href=\"https://saucelabs.com/u/rill-js\"\u003e\n    \u003cimg src=\"https://saucelabs.com/browser-matrix/rill-js.svg\" alt=\"Sauce Test Status\"/\u003e\n  \u003c/a\u003e\n\u003c/h1\u003e\n\nExpressive router for [nodejs](https://nodejs.org) and the browser.\nRill brings cascading middleware to the browser and enables a familiar routing solution for web applications.\n\nRill provides the minimum for abstractions over [nodejs](https://nodejs.org) and the browser enabling things like routing (with redirecting, refreshes and more), cookies, and middleware with the same api.\n\nIt supports many view engines including [Marko](http://markojs.com), [React](https://reactjs.org), [Svelte](https://svelte.technology) and even html only template engines such as [Pug](https://pugjs.org).\n\n# Installation\n\n```console\nnpm install rill\n```\n\n# Browser support\nAll modern browsers are supported including IE10 and above.\nOlder browsers will need to polyfill the Promise API, checkout [es6-promise](https://github.com/stefanpenner/es6-promise) for a good polyfill, babel-polyfill also covers this.\n\n# Community\n\n* [API Documentation](https://github.com/rill-js/rill/blob/master/docs/api/index.md#introduction)\n* Examples\n  * [React](https://github.com/rill-js/todomvc-react)\n  * [Marko](https://github.com/rill-js/todomvc-marko)\n  * [Svelte](https://github.com/rill-js/todomvc-svelte)\n* [Wiki](https://github.com/rill-js/rill/wiki)\n* [FAQ](https://github.com/rill-js/rill/wiki/FAQ)\n* [Middleware List](https://github.com/rill-js/rill/wiki/Middleware)\n* [Gitter Community](https://gitter.im/rill-js/rill)\n* [Reddit Community](https://www.reddit.com/r/Rill)\n\n# Articles\n\n* [Universal web application framework - Interview with Dylan Piercey](https://survivejs.com/blog/rill-interview/)\n* [Isomorphic Javascript, let’s make it easier.](https://medium.com/@pierceydylan/isomorphic-javascript-it-just-has-to-work-b9da5b0c8035)\n* [How to make universal JavaScript applications — Part 1](https://medium.com/@pierceydylan/how-to-make-universal-javascript-applications-part-1-90e9032bc471)\n* [Browsers, Servers, and APIs](https://medium.com/@iamjohnhenry/browsers-servers-and-apis-2f7b10523f39)\n* [Why Everyone is Talking About Isomorphic](https://medium.com/capital-one-developers/why-everyone-is-talking-about-isomorphic-universal-javascript-and-why-it-matters-38c07c87905#.mdd84j28m)\n* [Isomorphic JavaScript: The Future of Web Apps](https://medium.com/airbnb-engineering/isomorphic-javascript-the-future-of-web-apps-10882b7a2ebc)\n\n# Why Rill?\nRill is the answer to a simple question; Can I run my [Express](https://github.com/expressjs/express) style router in the browser? Turns out you can and it works awesome.\n\nIt brings a common interface to many typical app like features in both the browser and [nodejs](https://nodejs.org). Many isomorphic frameworks and routers have crazy abstractions and learning curves but with Rill, if you understand [Express](https://github.com/expressjs/express) or [Koa](https://github.com/koajs/koa), you already know how the routing works! In Rill you get to program much of your application logic using the same api (client or server) including routing, rendering, data fetching and more are easily shared.\n\nRill also works perfectly as a stand alone router for [nodejs](https://nodejs.org) or in the browser. This allows for easy progressive enhancement. If all is well the browser can handle much of your application logic and if JavaScript fails for any reason your server knows exactly what to do.\n\n# How does this thing work?\nIf you look at the source for Rill [here](https://github.com/rill-js/rill/tree/master/src) you will quickly notice there is ZERO browser specific code. This is all thanks to [@rill/http](https://github.com/rill-js/http) which is node's [HTTP.createServer](https://nodejs.org/api/http.html#http_http_createserver_requestlistener) ported to the browser.\n\nIn the browser it works by listening for internal link clicks, form submissions and browser history changes. It will then create a [Rill Context](https://github.com/rill-js/rill/blob/master/docs/api/context.md#context) for each of these events and emit it through the router, similar to how receiving a request works in [nodejs](https://nodejs.org).\n\nIt supports everything you'd expect from a client side [nodejs](https://nodejs.org) server. This includes redirects, refreshes, cookies, scrolling and url updates using the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History).\n\n# Example\n\n### Create an app\n\n```javascript\n/**\n * The following code can run 100% in the browser or in nodejs.\n * Examples use es2015/2016 with Babel and JSX but this is optional.\n */\n\nimport Rill from 'rill'\nconst app = new Rill() // You can call Rill without new, but autocomplete will not work.\n```\n\n### Setup middleware\n\n```javascript\n// Universal form data parsing middleware.\nimport bodyParser from '@rill/body'\napp.use(bodyParser())\n\n// Universal react rendering middleware.\nimport reactRenderer from '@rill/react'\napp.use(reactRenderer())\n\n// Example Logger\napp.use(async ({ req }, next)=\u003e {\n  const start = Date.now()\n\n  // Rill uses promises for control flow.\n  // ES2016 async functions work great as well!\n  await next()\n\n  const ms = Date.now() - start\n  console.log(`${req.method} ${req.url} - ${ms}`)\n})\n```\n\n### Setup a page\n\n```javascript\n// Respond to a GET request.\napp.get('/todos', async ({ res })=\u003e {\n  // Fetch a todolist from some service.\n  const todolist = await MyTodoListService.getAllTodos()\n\n  // Directly set React virtual dom to the body thanks to @rill/react.\n  // (Checkout @rill/html for universal html diffing).\n  res.body = (\n    \u003chtml\u003e\n      \u003chead\u003e\n        \u003ctitle\u003eMy App\u003c/title\u003e\n        \u003cmeta name=\"description\" content=\"Rill Application\"\u003e\n      \u003c/head\u003e\n      \u003cbody\u003e\n        \u003cform action=\"/add-todo\" method=\"POST\"\u003e\n          \u003ch1\u003eJust a plain old form\u003c/h1\u003e\n          \u003cinput type=\"text\" name=\"todo\"/\u003e\n          \u003cbutton type=\"submit\"\u003eAdd Todo\u003c/button\u003e\n        \u003c/form\u003e\n\n        {todolist.length\n          ? todolist.map(renderTodo)\n          : 'No todos to display.'\n        }\n        \u003cscript src=\"/app.js\"/\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  )\n})\n```\n\n### Handle a form submission\n```javascript\n// Respond to a POST request.\napp.post('/add-todo', async ({ req, res })=\u003e {\n  // We handle form submissions with Rill the same way one would express or koa.\n  // Here we are simply adding the todo via some service.\n  await MyTodoListService.addTodo({ text: req.body.todo })\n  // And then we redirect back (same as res.redirect('/todos'))\n  res.redirect('back')\n})\n```\n\n### Start app\n\n```javascript\n// Start a regular http server.\n// In the browser any form submissions or link clicks will intercepted by @rill/http.\napp.listen({ port: 80 })\n```\n\n## See Also\n\n* [isbrowser](https://github.com/DylanPiercey/isbrowser) - A browserify transform to remove server-side code.\n* [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch) - Universal http requests using WHATWG fetch.\n* [isomorphic-form-data](https://github.com/form-data/isomorphic-form-data) - Send multipart form data universally (able to send files and works with fetch).\n* [scroll-behavior](https://github.com/DylanPiercey/scroll-behaviour) - @rill/http will automatically try to use the \"smooth\" [scroll-behavior](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior) when scrolling to targets on link clicks. This will polyfill that across modern browsers.\n* [submit-form](https://github.com/DylanPiercey/submit-form) - Manually trigger Rill navigation in the browser.\n\n## Prior Art\n\n* [koa-client](https://github.com/kentjs/koa-client) - Koa clone that runs in the browser, inspired this package.\n* [monorouter](https://github.com/matthewwithanm/monorouter) - Another isomorphic router that partially inspired this package.\n\n## Contributions\n\n* Use `npm test` to build and run tests.\n\n## License\n\n[MIT](https://tldrlegal.com/license/mit-license)\n","funding_links":[],"categories":["Code Design","Uncategorized","TypeScript"],"sub_categories":["Isomorphic Apps","Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frill-js%2Frill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frill-js%2Frill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frill-js%2Frill/lists"}