{"id":15414808,"url":"https://github.com/aidenybai/hacky","last_synced_at":"2025-07-26T10:15:31.705Z","repository":{"id":47075274,"uuid":"393504171","full_name":"aidenybai/hacky","owner":"aidenybai","description":"⚙️ Crank.js with tagged templates","archived":false,"fork":false,"pushed_at":"2022-03-06T10:13:41.000Z","size":366,"stargazers_count":45,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-24T10:49:08.395Z","etag":null,"topics":["component","crankjs","dom","fun","functional","javascript","million","react","ui-library","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aidenybai.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":"2021-08-06T21:11:34.000Z","updated_at":"2024-09-12T23:25:24.000Z","dependencies_parsed_at":"2022-09-26T21:41:05.370Z","dependency_job_id":null,"html_url":"https://github.com/aidenybai/hacky","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/aidenybai/hacky","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidenybai%2Fhacky","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidenybai%2Fhacky/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidenybai%2Fhacky/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidenybai%2Fhacky/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aidenybai","download_url":"https://codeload.github.com/aidenybai/hacky/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidenybai%2Fhacky/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266992971,"owners_count":24018063,"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","status":"online","status_checked_at":"2025-07-25T02:00:09.625Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["component","crankjs","dom","fun","functional","javascript","million","react","ui-library","virtual-dom"],"created_at":"2024-10-01T17:04:54.829Z","updated_at":"2025-07-26T10:15:31.687Z","avatar_url":"https://github.com/aidenybai.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ⚙️ Hacky \u003cimg src=\"https://badgen.net/badgesize/brotli/https/unpkg.com/hacky?color=000000\u0026labelColor=00000\u0026label=bundle%20size\" alt=\"Code Size\" /\u003e \u003ca href=\"https://www.npmjs.com/package/hacky\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/hacky?style=flat\u0026colorA=000000\u0026colorB=000000\" alt=\"NPM Version\" /\u003e\u003c/a\u003e\n\n### `\u003c2kb` tagged template alternative for Crank.js\n\nHacky is something that I've always wanted. I've used React previously, but I find **hooks too magical** and JSX a **finicky process** that requires a build step.\n\nWhen I discovered Crank.js, I fell in love because of how intuitive it was to understand. Imagine Hacky as **Crank.js with tagged templates**, but with a lightweight core and simplistic API.\n\n\u003e If you're looking for something a bit more comprehensive, check out [**Million**](https://github.com/aidenybai/million) — Virtual DOM into the future! 💥🦁✨\n\u003e\n\u003e -Aiden ([@aidenybai](https://github.com/aidenybai))\n\n## `random.cat` API Example\n\nBelow is an implementation of a `random.cat` API fetcher example using Hacky ([Live Demo](https://codesandbox.io/s/data-fetching-hacky-75mvi?file=/index.html)).\n\n```js\nimport { html, render } from 'https://cdn.skypack.dev/hacky';\n\nconst fetchCat = async (url = 'https://aws.random.cat/meow') =\u003e {\n  const res = await fetch(url);\n  const { file } = await res.json();\n  return file;\n};\n\nfunction* Cats({ width, height }) {\n  const [cats, setCats] = this.createState([]);\n  const [message, setMessage] = this.createState('Fetch cat image');\n  const [disabled, setDisabled] = this.createState(false);\n\n  const addCat = async () =\u003e {\n    setMessage('Fetching...');\n    setDisabled(true);\n\n    try {\n      const newCat = await fetchCat();\n      setCats([...cats(), newCat]);\n      setMessage('Fetch cat image');\n      setDisabled(false);\n    } catch (err) {\n      console.error(err);\n      setMessage('Failed to fetch. Retrying...');\n      setTimeout(() =\u003e addCat(), 1000);\n    }\n  };\n\n  while (true) {\n    const catImages = cats().map(\n      (cat) =\u003e html`\u003cimg key=${cat} src=${cat} width=${width} height=${height} /\u003e`,\n    );\n    yield html`\n      \u003cbutton disabled=${disabled()} onClick=${addCat} style=\"width: 100%\"\u003e${message()}\u003c/button\u003e\n      \u003cdiv\u003e${catImages}\u003c/div\u003e\n    `;\n  }\n}\n\nrender(html`\u003c${Cats} width=${100} height=${100} /\u003e`, document.body);\n```\n\n`render()` function has a standard interface that is used in many Virtual DOM libraries. First argument is a Virtual DOM to render, and the second one is a DOM node that will be used as the live DOM reference.\n\n`html` tagged templates can produce Virtual DOM nodes, which define your DOM view.\n\n`this.createState()` function will instantiate a new state reference, in which you can mutate by destructuring the getter (index `0`) and setter (index `1`).\n\n## Acknowledgments\n\nHacky takes heavy inspiration from [Crank.js](https://github.com/bikeshaving/crank), and depends on [Million](https://million.js.org). Feel free to check them out if you interested in an alternative library to use.\n\n## License\n\nMillion is [MIT-licensed](https://github.com/aidenybai/hacky/blob/master/LICENSE) open-source software by [Aiden Bai](https://github.com/aidenybai).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faidenybai%2Fhacky","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faidenybai%2Fhacky","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faidenybai%2Fhacky/lists"}