{"id":20170142,"url":"https://github.com/marcodpt/wand","last_synced_at":"2026-04-11T11:35:27.687Z","repository":{"id":257608505,"uuid":"858780790","full_name":"marcodpt/wand","owner":"marcodpt","description":"A tiny JS router that makes no assumptions about its usage.","archived":false,"fork":false,"pushed_at":"2024-10-06T22:47:01.000Z","size":54,"stargazers_count":0,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-13T15:26:42.222Z","etag":null,"topics":["browser","deno","es6","esm","esmodule","express","functional-programming","hashrouter","javascript","microfrontend","microjs","microlibrary","node","plugins","queryparser","querystring","router","spa","universal-router","url"],"latest_commit_sha":null,"homepage":"https://marcodpt.github.io/wand/","language":"JavaScript","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/marcodpt.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-17T14:20:33.000Z","updated_at":"2024-10-06T22:47:05.000Z","dependencies_parsed_at":"2025-01-13T15:24:33.434Z","dependency_job_id":"0b748240-6f36-4913-b6b1-7f19d3d46e41","html_url":"https://github.com/marcodpt/wand","commit_stats":null,"previous_names":["marcodpt/wand"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fwand","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fwand/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fwand/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fwand/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcodpt","download_url":"https://codeload.github.com/marcodpt/wand/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241605820,"owners_count":19989612,"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":["browser","deno","es6","esm","esmodule","express","functional-programming","hashrouter","javascript","microfrontend","microjs","microlibrary","node","plugins","queryparser","querystring","router","spa","universal-router","url"],"created_at":"2024-11-14T01:17:24.976Z","updated_at":"2025-11-28T17:07:35.151Z","avatar_url":"https://github.com/marcodpt.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ![](favicon.ico) Wand\n\n  A tiny JS router that makes no assumptions about its usage.\n\n  [![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/wand/)\n  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n  [![GitHub Tag](https://img.shields.io/github/v/tag/marcodpt/wand)](https://github.com/marcodpt/wand/tags)\n  [![bundlejs](https://deno.bundlejs.com/badge?q=https://raw.githubusercontent.com/marcodpt/wand/main/index.js\u0026treeshake=[*])](https://bundlejs.com/?q=https://raw.githubusercontent.com/marcodpt/wand/main/index.js\u0026treeshake=[*])\n\n## ❤️ Features\n - [ES6 module](https://github.com/marcodpt/wand/blob/main/index.js).\n - Support\n[browser](https://github.com/marcodpt/wand/blob/main/src/runtimes/hashRouter.js),\n[node](https://nodejs.org/en), [deno](https://deno.com/).\n - Pure functional design.\n - [Tiny codebase](https://github.com/marcodpt/wand/blob/main/src/index.js),\nvery understandable.\n - Everything is a\n[plugin](https://github.com/marcodpt/wand/blob/main/src/plugins/).\n - Pre-built\n[runtimes](https://github.com/marcodpt/wand/blob/main/src/runtimes/)\nfor easy use.\n - Designed following the principles of\n[UNIX philosophy](https://en.wikipedia.org/wiki/Unix_philosophy).\n - Very well [tested](https://marcodpt.github.io/wand/tests/).\n - Ridiculously small [API](#-api). After reading this file you will\nunderstand `Wand` better than me.\n\n## 💡 Showcase: A hash router\n\n`Wand` makes no assumptions about the environment it will be used in, and this\nexample can be easily migrated to a server-side router or any other type of\napplication.\n\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/wand/)\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/wand/blob/main/index.html)\n\n```html\n\u003cbody\u003e\n  \u003cnav\u003e\n    \u003ca href=\"#/\"\u003eHome\u003c/a\u003e |\n    \u003ca href=\"#/hello/Mary\"\u003eHello Mary\u003c/a\u003e |\n    \u003ca\n      href=\"#/hello/John?age=25\u0026pets[]=dog\u0026pets[]=cat\"\n    \u003eHello John\u003c/a\u003e |\n    \u003ca href=\"#/goodbye?name=stranger\"\u003eGoodbye\u003c/a\u003e |\n    \u003ca href=\"#/clock\"\u003eClock\u003c/a\u003e |\n    \u003ca href=\"#/wrong/route\"\u003e404\u003c/a\u003e |\n    \u003ca href=\"javascript:stop()\"\u003eStop Router\u003c/a\u003e |\n    \u003ca href=\"https://github.com/marcodpt/wand\"\u003eRepository\u003c/a\u003e\n  \u003c/nav\u003e\n  \u003cmain\u003e\n    \u003ch1\u003eHome Page\u003c/h1\u003e\n  \u003c/main\u003e\n  \u003cpre\u003e\n    \u003ccode\u003e\u003c/code\u003e\n  \u003c/pre\u003e\n  \u003cscript type=\"module\"\u003e\n    import {hashRouter} from \"https://cdn.jsdelivr.net/gh/marcodpt/wand/index.js\"\n\n    window.stop = hashRouter({\n      init: () =\u003e {\n        const main = document.body.querySelector('main')\n        return {\n          index: 0,\n          home: main.innerHTML.trim(),\n          render: html =\u003e {main.innerHTML = html}\n        }\n      },\n      routes: {\n        '/': ({\n          render, home\n        }) =\u003e render(home),\n        '/hello/:name': ({\n          render, Params\n        }) =\u003e render(`\u003ch1\u003eHello ${Params.name}\u003c/h1\u003e`),\n        '/clock': ({render}) =\u003e {\n          const tick = () =\u003e {\n            console.log('tick')\n            const time = new Date()\n            render(`\u003ch1\u003e${[\n              time.getHours(),\n              time.getMinutes(),\n              time.getSeconds()\n            ].map(n =\u003e (n \u003c 10 ? '0' : '')+n).join(':')}\u003c/h1\u003e`)\n          }\n          const itv = setInterval(tick, 100)\n          return () =\u003e {clearInterval(itv)}\n        },\n        '/goodbye': ({render, Query}) =\u003e {\n          render(`\u003ch1\u003eGoodbye message before leaving!\u003c/h1\u003e`)\n          return () =\u003e {window.alert(`Goodbye ${Query.name}!`)}\n        },\n        '*': ({\n          render\n        }) =\u003e render(`\u003ch1\u003e404: Page Not Found\u003c/h1\u003e`) \n      },\n      plugins: [\n        state =\u003e {\n          state.index++\n        },\n        state =\u003e {\n          document.body.querySelector('code').\n            textContent = JSON.stringify(state, undefined, 2)\n        }\n      ]\n    })\n  \u003c/script\u003e\n\u003c/body\u003e\n```\n\n## 💻 Usage\n\n### Hash router in the browser.\nThis example already makes use of the `queryParser` `plugin` and\nimplements the `runtime` of a hash router.\n\n```js\nimport {hashRouter} from \"https://cdn.jsdelivr.net/gh/marcodpt/wand/index.js\"\n```\n\n### Building your own runtime\nThis example is for those who want a more customized experience to create\ntheir own `runtime` and eventually make use of `plugins`.\n\n```js\nimport {wand, queryParser} from \"https://cdn.jsdelivr.net/gh/marcodpt/wand/index.js\"\n```\n\n## 📖 API\n\n### runtimes: ({init?, routes, plugins?}) =\u003e stop\n`Runtimes` are thin layers built on top of `Wand` with the aim of bringing\nsimplicity to a specific use, they are open to contributions.\n\n#### hashRouter\nMade to be used in the browser, it already has the `queryParser` plugin by\ndefault.\n\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/wand/blob/main/src/runtimes/hashRouter.js)\n\n### plugin: state =\u003e ()\n`Plugins` can modify the `state` with each `change` of route, and were designed\nto be easy to develop without changing the way the `Wand` core works.\n\nEnabling maximum flexibility and contributions.\n\n#### queryParser\nThe default parser for query string due to its simplicity.\nAdds the `Query` property to the `state`.\n\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/wand/blob/main/src/plugins/queryParser.js)\n\n##### Query: object\nParsed query string.\n\n### wand: ({init?, routes, plugins?, runtime}) =\u003e stop\n`Runtimes` are built on top of the library.\nAnd the `plugins` are designed for it.\n\nThe idea is to bring a simple router to your core but at the same time with a\ncomplete `plugin` system and easy-to-use `runtimes`.\n\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/wand/blob/main/src/index.js)\n\n#### init: () =\u003e state\nOptional function called once to create the initial `state`\n(this must be an `object`).\n\n#### routes: {route: action}\nObject that defines the possible `routes`.\n\n##### route: string\nAccepts `*` to match any path and `:param` to declare variable.\n\n##### action: (state, ...args) =\u003e done | response\nA function that will be called whenever `route` is matched in a route `change`.\n\nAll other `args` passed by the `change` function will be passed to the\n`action`.\n\n##### done: state =\u003e ()\nAn optional function that will be called before the new `route` `action`, with\nthe `state` of the new `route` to end the current `route`.\n\n##### response: any\nIf it is not a `done` function, it will be treated as a `response` and\nreturned in the `change` function.\n\n#### plugins: [state =\u003e ()]\nAn optional array of `plugins`, which are executed sequentially with each\n`route` `change` and which can modify the `state` before the `action`\nassociated with the new `route` or the `done` function associated with the old\n`route` are called.\n\n#### runtime: change =\u003e finish?\nThe router `runtime`.\n\n##### change: (url, ...args) =\u003e response\nWhenever called, it will trigger a `change` of `route`, with the\n`url` (`string`) being associated with the `state`.\n\nAll other `args` will be passed to the `action`.\n\n##### finish: state =\u003e ()\nOptional function to terminate the `runtime`, receives the current `state` of\nthe `route` as a parameter.\n\n#### stop: () =\u003e ()\nCalls the `finish` function of the `runtime` with the contents of the current\n`state`, and from then on any call to the `change` function within the\n`runtime` will be ignored.\n\n### state: object\nThe state is initialized by the `init` function or as an empty `object`\n(if `init` is not passed).\n\nListed here are the `state` properties that are modified with each `route`\n`change`. Note that `plugins` can also modify `state` properties.\n\n#### url: string\nThe `url` as passed to the `change` function.\n\n#### route: string\nThe `route` that matched as declared.\n\n#### path: string\nThe part of the `url` before the `?`.\n\n#### Params: object\nObject containing the variables declared in the `route` with the associated\nvalues in the current `path`.\n\n#### query: string\nThe part of `url` after the `?`.\n\n## ⭐ Support\nIf this project was useful to you, consider giving it a star on github, it's a\nway to increase evidence and attract more contributors.\n\n## 📦 Projects using this module\nIf your project is not on the list, submit a pull request, it is a way to\nincrease awareness of your project and this module.\n\n - [Merlin](https://github.com/marcodpt/merlin): A functional JS framework that\nvalues elegance, simplicity and minimalism. \n - [Paw](https://github.com/marcodpt/paw): A low-code, vdom-free hyperscript\nframework.\n\n## 🪟 Alternatives\nThis list of alternatives serves to find the most suitable module for your\nproject but also and mainly to serve as a reference for implementation ideas\nand improvements. All contributions are welcome.\n\n - [universal-router](https://github.com/kriasoft/universal-router): A simple middleware-style router for isomorphic JavaScript web apps \n - [director](https://github.com/flatiron/director): A tiny and isomorphic URL router for JavaScript.\n - [page.js](https://github.com/visionmedia/page.js): Micro client-side router inspired by the Express router (~1200 bytes).\n - [pathjs](https://github.com/mtrpcic/pathjs): Simple, lightweight routing for web browsers.\n - [crossroads](https://github.com/millermedeiros/crossroads.js): JavaScript Routes.\n - [davis.js](https://github.com/olivernn/davis.js): RESTful degradable JavaScript routing using pushState.\n - [router](https://github.com/progrape/router): A very simple router for the demo of WeUI\n - [navigo](https://github.com/krasimir/navigo): A simple vanilla JavaScript router.\n - [router.js](https://github.com/tildeio/router.js/)\n - [slim-router](https://github.com/haithembelhaj/slim-router): A Javascript Router based on History.js\n - [router.js](https://github.com/ramiel/router.js/): Router.js is a simple and powerful javascript library to handle routing\n - [router](https://github.com/vaadin/router): Small and powerful client-side router for Web Components. Framework-agnostic.\n - [react-router](https://github.com/remix-run/react-router): Declarative routing for React\n - [vue-router](https://github.com/vuejs/vue-router): The official router for Vue 2\n - [ui-router](https://github.com/ui-router/angular): UI-Router for Angular: State-based routing for Angular (v2+)\n - [express](https://github.com/expressjs/express): Fast, unopinionated, minimalist web framework for node.\n - [koa-route](https://github.com/koajs/route): Simple route middleware\n\n## 🤝 Contributing\nIt's a very simple project.\nAny contribution, any feedback is greatly appreciated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcodpt%2Fwand","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcodpt%2Fwand","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcodpt%2Fwand/lists"}