{"id":13437842,"url":"https://github.com/matthewwithanm/monorouter","last_synced_at":"2026-03-05T22:09:20.510Z","repository":{"id":18078496,"uuid":"21141714","full_name":"matthewwithanm/monorouter","owner":"matthewwithanm","description":"An isomorphic JS router","archived":false,"fork":false,"pushed_at":"2015-06-04T00:29:19.000Z","size":1186,"stargazers_count":141,"open_issues_count":8,"forks_count":2,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-08-09T11:22:59.647Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matthewwithanm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-06-23T20:44:30.000Z","updated_at":"2023-07-01T00:54:25.000Z","dependencies_parsed_at":"2022-09-13T13:01:48.437Z","dependency_job_id":null,"html_url":"https://github.com/matthewwithanm/monorouter","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/matthewwithanm/monorouter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewwithanm%2Fmonorouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewwithanm%2Fmonorouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewwithanm%2Fmonorouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewwithanm%2Fmonorouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matthewwithanm","download_url":"https://codeload.github.com/matthewwithanm/monorouter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewwithanm%2Fmonorouter/sbom","scorecard":{"id":626957,"data":{"date":"2025-08-11","repo":{"name":"github.com/matthewwithanm/monorouter","commit":"4173f267ca65f4d222865903e441b4d6b00f669d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-21T06:45:30.032Z","repository_id":18078496,"created_at":"2025-08-21T06:45:30.032Z","updated_at":"2025-08-21T06:45:30.032Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30152100,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T21:15:50.531Z","status":"ssl_error","status_checked_at":"2026-03-05T21:15:11.173Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-07-31T03:01:00.634Z","updated_at":"2026-03-05T22:09:20.489Z","avatar_url":"https://github.com/matthewwithanm.png","language":"JavaScript","funding_links":[],"categories":["Uncategorized","Awesome React","Code Design"],"sub_categories":["Uncategorized","Tools","Router"],"readme":"monorouter\n==========\n\nmonorouter is an isomorphic JavaScript router by [@matthewwithanm] and\n[@lettertwo]. It was designed for use with ReactJS but doesn't have any direct\ndependencies on it and should be easily adaptable to other virtual DOM\nlibraries.\n\nWhile it can be used for both browser-only and server-only routing, it was\ndesigned from the ground up to be able to route apps on both sides of the wire.\n\n**Note: This project is in beta and we consider the API in flux. Let us know if\nyou have any ideas for improvement!**\n\n\nUsage\n-----\n\nDefining a router looks like this:\n\n```javascript\nvar monorouter = require('monorouter');\nvar reactRouting = require('monorouter-react');\n\nmonorouter()\n  .setup(reactRouting())\n  .route('/', function(req) {\n    this.render(MyView);\n  })\n  .route('/pets/:name/', function(req) {\n    this.render(PetView, {petName: req.params.name});\n  });\n```\n\nHere, we're simply rendering views for two different routes. With monorouter, a\n\"view\" is any function that returns a DOM descriptor.\n\nThe router can be used on the server with express and [connect-monorouter]:\n\n```javascript\nvar express = require('express');\nvar router = require('./path/to/my/router');\nvar monorouterMiddleware = require('connect-monorouter');\n\nvar app = express();\napp.use(monorouterMiddleware(router));\n\nvar server = app.listen(3000, function() {\n    console.log('Listening on port %d', server.address().port);\n});\n```\n\nAnd in the browser:\n\n```javascript\nrouter\n  .attach(document)\n  .captureClicks(); // This is optional—it uses the router to handle normal links.\n```\n\nSee [the examples][monorouter examples] for a more in-depth look and more\ntricks!\n\n\n### Handling errors\n\nError handling with monorouter is similar to [Express]—just add a middleware\nwith an arity of 3:\n\n```javascript\nrouter.use(function(err, req, next) {\n  if (err.status === 404) {\n    this.render(My404Template);\n  }\n});\n```\n\n\nAPI\n---\n\nIn addition to the router itself, monorouter has two important objects. The\nfirst one is the request object, and it's passed as the first argument to your\nhandler. The second is the context (`this`) of your route handler, and it's used\nto interface with your application's state (you can think of this as being\nsimilar to a Response object in server-only routers). This section summarizes\ntheir APIs.\n\n\n### Request\n\n- **param(name:String)**: Get the value for one of the dynamic parts of your\n  route:\n\n  ```javascript\n  monorouter()\n    .route('/pets/:name', function(req) {\n      console.log(req.param('name'));\n      // snip\n    });\n  ```\n\n- **params:Object**: A hash of the params used in your route.\n- **canceled:Boolean**: A boolean that represents whether the request has been\n  canceled. This is useful for preventing further action in async callbacks:\n\n  ```javascript\n  monorouter()\n    .route('/', function(req) {\n      http('...', function(err, result) {\n        if (req.canceled) return;\n        this.render(MyView, {person: result.people[0]});\n      }.bind(this));\n    });\n  ```\n\n  Note that it's not necessary to check this value if all you're doing is\n  rendering since those operations are no-ops when the request has been\n  canceled. The request is also an EventEmitter that emits a \"cancel\" event so,\n  if you'd like to take action immediately when a request is canceled (and abort\n  an XHR request, for example), you can do that:\n\n  ```javascript\n  monorouter()\n    .route('/', function(req) {\n      var xhr = http('...', function(err, result) {\n        if (req.canceled) return;\n        this.render(MyView, {person: result.people[0]});\n      }.bind(this));\n      this.on('cancel', function() {\n        xhr.abort();\n      });\n    });\n  ```\n\n- **initialOnly:Boolean**: Indicates whether the request is only for the initial\n  state of the app. `true` when rendering on the server.\n- **location:Object**: A parsed version of the requested URL, in a format based\n  on the [`document.location` interface][document.location].\n- **url:String**: The requested URL.\n- **protocol:String**: The protocol of the requested URL, without the colon.\n  e.g. `\"http\"`\n- **hostname:String**: The hostname of the requested URL, e.g. `'mysite.com'`\n- **host:String**: The full host of the requested URL, e.g. `'mysite.com:5000'`\n- **search:String**: The search portion of the requested URL, including the\n  question mark, e.g. `'?hello=5\u0026goodbye=a'`\n- **querystring:String**: The search portion of the requested URL, excluding the\n  question mark, e.g. `'hello=5\u0026goodbye=a'`\n- **query:Object**: A version of the query string that's been parsed using\n  @sindresorhus's [query-string].\n- **hash:String**: The hash portion of the requested URL, including the hash\n  mark. e.g. `'#this-is-the-hash'`\n- **fragment:String**: The hash portion of the requested URL, excluding the hash\n  mark. e.g. `'this-is-the-hash'`\n- **first:Boolean**: Is this the first request being handled by this router?\n- **from(causes:String...):Boolean**: Check the cause of the request. Causes\n  that monorouter sends are:\n\n  * `\"startup\"` - When a request is triggered by the router initialization in\n    the browser.\n  * `\"popstate\"` - When a request is triggered by a popstate event\n  * `\"link\"` - When a request is triggered by a link click captured by the link\n    hijacker\n\n  You may also send custom causes. For example, [connect-monorouter] uses the\n  string '\"httprequest\"'. Generally, causes shouldn't be used to affect routing\n  behavior—they are meant primarily for logging.\n\n\n### Handler Context\n\nWithin a route handler, you use properties and methods of `this` to define the\napplication state. Here are some of those:\n\n- **render(view:Function?, vars:Object?, callback:Function?)**: Render the view\n  and consider the request complete. The `view` is a function that returns a\n  virtual DOM instance. It may be omitted if you've previously set one for this\n  request using `setView` (e.g. in middleware). \"vars\" are arguments for this\n  function that will be bound to it for as long as it's rendered.\n- **renderIntermediate(view:Function?, vars:Object?, callback:Function?)**: Like\n  `render`, but doesn't end the request. This is useful if you'd like to render\n  several different states during the course of handling a single route.\n- **renderInitial(view:Function?, vars:Object?, callback:Function?)**: Like\n  `render`, but only ends \"initialOnly\" requests.\n- **setView(view:Function)**: Sets the view to be rendered for this response.\n  The application won't actually be updated until/unless one of the `render*`\n  methods is called.\n- **setVars(vars:Object)**: Add vars for any subsequent renders in this request.\n  \"vars\" are passed to the view function for rendering.\n- **setState(state:Object)**: \"state\" is similar to vars in that its values are\n  passed to the view for rendering. Unlike \"vars\", however, \"state\" is preserved\n  between requests. Setting state also triggers a rerender of the current view.\n  The state and vars are merged and the result passed to the view function.\n- **notFound()**: A function that tells the server to send a 404 status code\n  with this view.\n- **doctype:String**: The doctype for the document. Defaults to the HTML5\n  doctype.\n- **contentType:String**: The content type of the document. Defaults to\n  `'text/html; charset=utf-8'`\n- **beforeRender(hook:Function)**: An interface for adding before-render hooks.\n  All hooks are executed in parallel immediately prior to rendering.\n- **ended:Boolean**: Specifies whether the response has ended.\n- **initialEnded:Boolean**: Specifies whether the initial state has been rendered.\n\n\nPhilosophy\n----------\n\nIf the original idea for [react-nested-router] was \"[Ember] got it mostly\nright,\" monorouter's can be said to be \"[Express] got it mostly right.\" (Or\n[koa]. Or [Flask]. Or [Django]. Or [Rails]…) Server-side routing is very easy: a\nrequest comes in and, in response, you render a template. Each time this\nhappens, you render the entire document. Until recently, this approach seemed\nincongruent with client-side rendering, but ReactJS and the virtual DOM have\nchanged that.\n\nStill, client-side routing is fundamentally different than server-side in some\nways—most notably in that state can be shared between routes. monorouter aims to\nexpose the functionality related to GUI routing that's common to the server and\nbrowser. Some principles of the project are:\n\n1. The same routing that's used in the browser should be used to render the\n   server response.\n2. Routing is (at least potentially) an asynchronous process while rendering a\n   view is a synchronous one.\n3. Routes need not map to a single state (or view), but may result in any number\n   of them throughout their life.\n    * Two of these states are special: the \"initial\" state (which will be\n      serialized and sent by the server and which the browser app must begin in)\n      and the final state (which the app is in once the handling of a route is\n      completed).\n4. A view is any JavaScript function that returns a DOM descriptor.\n5. Each view should represent the entire document at a given state—not just a\n   portion of it.\n   * Not only does this make reasoning about the application easier, it's very\n     important when dealing with `\u003chead\u003e`s\n6. We think monorouter covers all the possible use cases, and we see it as a\n   foundation on which to build—both via extensions (i.e. middleware) and\n   additional abstractions (i.e. JSX-friendly interfaces and declarative,\n   lifecycle-centric route declarations).\n\n\n\n\n[@matthewwithanm]: http://github.com/matthewwithanm\n[@lettertwo]: http://github.com/lettertwo\n[react-nested-router]: https://github.com/rpflorence/react-router\n[Ember]: https://github.com/emberjs/ember.js\n[Express]: https://github.com/visionmedia/express\n[koa]: https://github.com/koajs/koa\n[Flask]: https://github.com/mitsuhiko/flask\n[Django]: https://github.com/django/django\n[Rails]: https://github.com/rails/rails\n[react-router-component]: https://github.com/andreypopp/react-router-component\n[connect-monorouter]: https://github.com/matthewwithanm/connect-monorouter\n[monorouter-react]: https://github.com/matthewwithanm/monorouter-react\n[monorouter examples]: https://github.com/matthewwithanm/monorouter/tree/master/examples\n[document.location]: https://developer.mozilla.org/en-US/docs/Web/API/document.location\n[query-string]: https://github.com/sindresorhus/query-string\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewwithanm%2Fmonorouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatthewwithanm%2Fmonorouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewwithanm%2Fmonorouter/lists"}