{"id":15011820,"url":"https://github.com/huynhducduy/refuse","last_synced_at":"2025-04-12T04:12:27.446Z","repository":{"id":45387299,"uuid":"502749790","full_name":"huynhducduy/refuse","owner":"huynhducduy","description":"Yet another fast and lightweight alternative of React.js","archived":false,"fork":false,"pushed_at":"2024-03-08T22:17:03.000Z","size":255,"stargazers_count":6,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-12T04:12:20.996Z","etag":null,"topics":["dom","hooks","hyperscript","jsx","preact","react","reactjs","reconciliation","solid","virtual-dom"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/huynhducduy.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}},"created_at":"2022-06-12T23:22:16.000Z","updated_at":"2023-07-26T03:50:09.000Z","dependencies_parsed_at":"2024-03-08T23:29:40.353Z","dependency_job_id":"c60bd23c-b983-422d-9588-331f03ddad3f","html_url":"https://github.com/huynhducduy/refuse","commit_stats":{"total_commits":47,"total_committers":2,"mean_commits":23.5,"dds":0.276595744680851,"last_synced_commit":"67fc7079f2cc3ce0bf542810cc31b93df5ba418a"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huynhducduy%2Frefuse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huynhducduy%2Frefuse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huynhducduy%2Frefuse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huynhducduy%2Frefuse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/huynhducduy","download_url":"https://codeload.github.com/huynhducduy/refuse/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248514205,"owners_count":21116903,"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":["dom","hooks","hyperscript","jsx","preact","react","reactjs","reconciliation","solid","virtual-dom"],"created_at":"2024-09-24T19:41:45.698Z","updated_at":"2025-04-12T04:12:27.419Z","avatar_url":"https://github.com/huynhducduy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Refuse [![npm version](https://badge.fury.io/js/refusejs.svg)](https://badge.fury.io/js/refusejs)\n\n![Refuse](https://user-images.githubusercontent.com/12293622/219362480-f01fec20-f405-44e4-af0f-10cfc5712c30.png)\nThe name of `refuse` comes from its main action: `fuse` (join or blend) multiple components to form a single working app. Fun fact: it also means `trash`, or refers to the action of `being not willing to do something` in English)\n\u003e **Note**: This library is a work-in-progress. Some features are not available yet. See [Feature lists](#feature-lists) for more details.\n\n[![Built with WeBuild](https://raw.githubusercontent.com/webuild-community/badge/master/svg/WeBuild.svg)](https://webuild.community) [![From Vietnam with \u003c3](https://raw.githubusercontent.com/webuild-community/badge/master/svg/love.svg)](https://webuild.community)\n\nKey points:\n- Same modern API as React.js\n- Full typescript support\n- No JSX\n- No build tool, no bundler, no transpiler required\n\nDifferent from React:\n- No class component supported\n- No longer need to return single root element, so `Fragment` use cases now narrow down to key-ed diff only.\n- Ref works on component as well, and auto assign to the root element of the component.\n  - If the component have multiple root, it will point to the `DocumentFragment`, which will be empty (and useless) after moving its child to the DOM. [Read more](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment#usage_notes)\n  - (Don't need to wrap component in forwardRef, just) use the second parameter of component to assign it to a specific element.\n- Component can return `number[]`,`string[]`,`fuse[]` or even `string[][]` to render multiple elements.\n  - Component can return `null`,`undefined`,`false` to skip rendering.\n\nAbout syntax:\n- Spread props: `\u003cdiv ...${props}\u003e` instead of `\u003cdiv {...props}\u003e`\n- HTML's quotes now optional: `\u003cdiv class=foo\u003e`\n- Shorthand for component end-tags: `\u003c${Foo}\u003ebar\u003c//\u003e`\n- Comment: `\u003c!-- comment --\u003e`\n\nSyntax highlighting support:\n- Intellij IDEA (WebStorm,...): supported by default\n- VSCode: [lit-html](https://marketplace.visualstudio.com/items?itemName=bierner.lit-html)\n\n\u003e Have you ever wondered how React.js works internally? Reading the source code of `refuse` is a good way to learn how it works.\n\n## Try it out now\n\n[![Whac-a-mole with Refuse](https://user-images.githubusercontent.com/12293622/219870837-306fd0ae-479c-442f-a402-325a7d2f72bd.png)](https://codepen.io/huynhducduy/pen/VwGvjbv)\n\n[Whac-a-mole with Refuse](https://codepen.io/huynhducduy/pen/VwGvjbv)\n\n[With Vite](https://codesandbox.io/p/sandbox/refuse-vite-beb3gc)\n\n[Without bundler](https://codepen.io/huynhducduy/pen/wvEBNPo)\n\n## Getting started\n```\nnpm i -S refusejs\n```\n\n```ts\nimport {useState, fuse,render} from \"refusejs\"\nimport type {RefuseComponent} from \"refusejs\"\n\ninterface Props {\n  someThing: string\n}\n\nconst Component: RefuseComponent\u003cProps\u003e = (props, ref) =\u003e {\n\tconst [state, setState] = useState(0)\n\n\tuseEffect(() =\u003e {\n\t\tconst timer = setInterval(() =\u003e setState(state + 1), 1000)\n\t\treturn () =\u003e clearInterval(timer)\n\t}, [])\n\n\treturn fuse`\n\t\t\u003cdiv class=foo ...${props} foo=${state}\u003e\n\t\t\t${props.children}\n\t\t\t\u003c${A}\u003eSomething...\u003c//\u003e\n\t\t\t\u003cbutton onclick=${() =\u003e setState(state + 1)}\u003eClick me\u003c/button\u003e\n\t\t\t${state \u003e 300 \u0026\u0026 fuse`\u003cdiv\u003e\n\t\t\t\tYeah\n\t\t\t\u003c/div\u003e`}\n\t\t\t\u003c!-- some comment --\u003e\n\t\t\u003c/div\u003e\n\t`\n}\n\nrender(Component, document.getElementById('root'))\n```\n\nOr\n\n```html\n\u003cscript src=\"https://unpkg.com/refusejs@latest/dist/refuse.umd.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n\tconst {render, fuse} = Refuse;\n\trender(\n\t\t() =\u003e fuse`\n\t\t\t\u003cdiv\u003e\n\t\t\t\t\u003ch1\u003eHello, world!\u003c/h1\u003e\n\t\t\t\t\u003cp\u003eIt's a beautiful day.\u003c/p\u003e\n\t\t\t\u003c/div\u003e\n\t\t`,\n\t\tdocument.getElementById('root2')\n\t);\n\u003c/script\u003e\n```\n\nor\n\n```html\n\u003cscript type=\"module\"\u003e\n\timport * as Refuse from 'https://unpkg.com/refusejs@latest/dist/refuse.modern.js'; // Support only modern browsers\n\t// import * as Refuse from 'https://unpkg.com/refusejs@latest/dist/refuse.module.js'; // Support all browsers\n\n\tRefuse.render(\n\t\t() =\u003e Refuse.fuse`\n\t\t\t\u003cdiv\u003e\n\t\t\t\t\u003ch1\u003eHello, world!\u003c/h1\u003e\n\t\t\t\t\u003cp\u003eIt's a beautiful day.\u003c/p\u003e\n\t\t\t\u003c/div\u003e\n\t\t`,\n\t\tdocument.getElementById('root')\n\t);\n\u003c/script\u003e\n```\n\n## Feature lists:\n- [x] TypeScript\n- [x] Jsx to HyperScript using `htm`\n- [x] render\n- [x] Custom components with props\n- [x] Custom components with children\n- [x] useState\n- [X] Automatic state update batching\n- [ ] flushSync\n- [x] useEffect with cleanup\n- [x] Unmount components\n- [x] Component Tree\n- [x] Render: dirty mark, compare\n- [ ] Render: keys\n- [x] Conditional rendering\n- [x] DOM diffing/patching\n- [x] useLayoutEffect\n- [x] useMemo, useCallback, useRef\n- [x] memo\n- [x] Fragment\n- [x] JSX Embedding Expression\n- [x] DOM Ref\n- [x] React.forwardRef\n- [ ] Render multiple Refuse instances\n- [ ] Error Boundary\n- [ ] Concurrent Mode, useTransition\n- [ ] useContext\n- [ ] useReducer\n- [ ] Test utils, write tests\n- [ ] Portal\n- [ ] Server-side rendering\n- [ ] Synthetic Event\n- [ ] Devtools, debugger, HMR - Hot reload\n- [ ] Router\n- [ ] useDeferredValue\n- [ ] Suspense\n- [ ] useImperativeHandle\n- [ ] useDebugValue\n- [ ] useId\n- [ ] useSyncExternalStore\n- [ ] Dynamic import, React.lazy\n- [ ] Production build\n- [ ] Profiler\n- [ ] Linter\n- [ ] Type checker on tagged template\n- [ ] useEvent\n\n## Development\nWatch `refuse` package\n```\nnpm i --lockfile-only\nnpm link\nnpm run dev\n```\n\nRun `example1`\n```\ncd demo/example1\nnpm i --lockfile-only\nnpm link refusejs\nnpm run dev\n```\n\nAnd follow instructions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuynhducduy%2Frefuse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuynhducduy%2Frefuse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuynhducduy%2Frefuse/lists"}