{"id":13393033,"url":"https://github.com/ohager/stappo","last_synced_at":"2025-10-30T23:18:09.510Z","repository":{"id":57369430,"uuid":"77463901","full_name":"ohager/stappo","owner":"ohager","description":"Maybe the smallest application state manager ever","archived":false,"fork":false,"pushed_at":"2017-01-27T12:09:59.000Z","size":74,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-28T15:06:34.918Z","etag":null,"topics":["application-state","component-driven","flux-architecture","micro-library","ng2","reactjs","riotjs","state-management"],"latest_commit_sha":null,"homepage":null,"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/ohager.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":"2016-12-27T15:11:53.000Z","updated_at":"2024-06-27T08:33:56.000Z","dependencies_parsed_at":"2022-08-26T06:00:42.351Z","dependency_job_id":null,"html_url":"https://github.com/ohager/stappo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ohager%2Fstappo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ohager%2Fstappo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ohager%2Fstappo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ohager%2Fstappo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ohager","download_url":"https://codeload.github.com/ohager/stappo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251336388,"owners_count":21573188,"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":["application-state","component-driven","flux-architecture","micro-library","ng2","reactjs","riotjs","state-management"],"created_at":"2024-07-30T17:00:41.437Z","updated_at":"2025-10-30T23:18:09.431Z","avatar_url":"https://github.com/ohager.png","language":"JavaScript","readme":"# stappo\n\nMaybe the worlds smallest Application State Manager written in Javascript (less than 300 bytes ).\n\nThis project is just to checkout the limits on optimization. The aim is to squeeze out the last bytes and create the worlds smallest\n application state manager written in Javascript.\n\nBesides all that fun, it is meant to be fully functional and usable for real-world applications. \n\n[ONLINE DEMO](https://rawgit.com/ohager/stappo/master/demo/index.html)\n\n## Installation\n\nAs NPM module (larger version due to module overhead --- see below) \n\n`npm i -S stappo` \n\nAs plain script (smallest build possible) in your web application \n\n`\u003cscript type=\"text/javascript\" src=\"https://cdn.rawgit.com/ohager/stappo/master/dist/stappo.web.min.js\"\u003e\u003c/script\u003e`\n\n### Versions\n\n1. __Generic Bundle__ `./dist/stappo.bundle.js` - A browserified bundle usable either on client- (Browser) or server-side (NodeJS). The bundles supports AMD/UMD/CommonJS/ES6 module importation.\n2. __Generic__ `.dist/stappo.min.js` - Usable on client or server-side, but without any module support (plain ES5 class)\n3. __Web-Only Bundle__ `./dist/stappo.web.bundle.js` - Only for browsers, supports AMD/UMD/CommonJS/ES6 module  \n4. __Web-Only__ `./dist/stappo.web.min.js` - Plain class, for browsers only...no overhead at all!    \n\n### Generic vs Web-Only\n\nThe generic version implements its own observer (aka pub/sub) pattern, and therefore doesn't rely on specific platform.\nThe web-only version uses custom events of the browsers event system (addEventListener). The web-only version is smaller than the generic version.\n\n\n## A brief introduction to Application State Management\n\nNowadays, web applications can be quite complex and the big challenge of such complex (web) applications how to manage their complexity. State-of-the-art is component based development; \nLibraries/Frameworks like ReactJS, Angular2, Aurelia, VueJS, RiotJS and others applies this concept. This allows the devs to break down everything in more or less decoupled and (hopefully) \nreusable parts, which can be put together like Lego(tm).\n\nBesides the composition feature a web application needs to communicate with the backend to store or fetch persistent data. The common approach to interoperate with the backend is a REST-like/-ful API, \nor even more recent techniques like GraphQL (Relay). Such backend-state must be handled somehow by the client application, especially because the requests are asynchronous. This makes data arrival unpredictable \nand adds even more complexity.\n\nEach application of a certain complexity (usually the complexity doesn't need to be high, as you may see in the demo) needs to maintain some shared data among its components. This data represents a specific situation at a specific moment of that application while a user interacts with it. \nThis is considered as application state. That state should be\n\n1. accessible by all components of an application\n2. ideally, stored in a single place (_Single Source of Truth_)\n3. mutable by a well-defined interface only \n\n\u003e __Definition__: An application state is a deterministic situation at a certain moment of an application within the context of user interaction.\n\nAs one can see in the [ONLINE DEMO](https://rawgit.com/ohager/stappo/master/demo/index.html), even very simple applications must share states among its components. \nThe demo consists of very few components (\u003c10), but has to share a item list and a search term:\n\nOn adding a new item via the single input field, the item list must be updated. Additionally, the search bar allows text-based filtering; the item list is being updated on changed search term and changed item. \nThis is still a very simple scenario, but it shows that _three components interoperate with two shared states_.\n      \n\n## Very easy to use\n\nThe overall concept is deadly simple. _Stappo_ maintains an Application State, where interested modules/components \n can listen to, while others may update the state. \n On state updates the subscribed listeners are called, receiving the new state. The state is __immutable__.\n \n### Example Generic Bundle\n\n```javascript\n\t// stappo must be instantiated\n\t// this could be useful to manage large states (e.g one instance per domain) \n\tconst StappoClass = require('stappo');\n\tconst stappo = new StappoClass()\n\t// \n\tconst listener = stappo.listen( state =\u003e {\n\t\tconsole.log(\"Updated State\", JSON.stringify(state, \"  \"));\n\t});\n\t \n\t// update the state --- it'll be merged into the application state\n\tstappo.update(() =\u003e ({\n\t\tfoo: { \n\t\t\tbar : { \n\t\t\t\ta: 42, \n\t\t\t\tb : [0,1,2]\n\t\t\t}\n\t}}));\n\t// stop listen to state changes\n\tstappo.unlisten(listener);\n```\n\n[TRY IT NOW!](https://runkit.com/ohager/stappo)\n\n# API (Generic Version)\n\n### `stappo.listen(functionObj, context?):number`\n \nThe listen function accepts a `functionObj` of the following signature `function(state){}`. The state is the updated state and it is __immutable__.\nThe `functionObj` is being called on each update of the application state. The second optional argument is the calling context, also referred as the _thisArg_.\nIt is used to give the called functionObj its calling context (where `this` references to -- similar to `Object.prototype.call`)\n\nThe function returns an id, which can/should be used on `stappo.unlisten`.\n\n### `stappo.unlisten(listenerId)`\n \nRevokes the subscription established on `stappo.listen`. The `listenerId` is the return value from `stappo.listen`.\n\n### `stappo.update(fn)`\n\nUpdates the application state, i.e. calls the passed function that *must* return a JSON and merges it into the application state.\nOn update all listeners are notified.\n\n`fn` is of type `(currentState) =\u003e { return newStateObj }`\n\n### `stappo.get()`\n\nReturns the current state\n\n# API (Web-only Version)\n\nThe web only version uses the browser's event system, while the generic version implements its own observer.\nTherefore, no `listen` and `unlisten` method exist. Listening to the event works like this:\n\n```javascript\nwindow.addEventListener('stappo', e =\u003e { console.log('state updated', e.detail)} )\nconst stappo = new Stappo();\n\nstappo.update(() =\u003e ({poo: 'fart'})); // emits 'stappo' event\n\nwindow.removeEventListener('stappo');\n```\n\n### `new Stappo(eventTypeName?)` - constructor  \n  \nCreates a new Stappo instance. When using more than one instance (e.g. for differnt domains/contexts) you need to define an custom event type name.\n  \nExample for multiple instances:\n```javascript\nconst stappoProducts = new Stappo('stappo.products');\nconst stappoOrders = new Stappo('stappo.orders');\n\nwindow.addEventListener('stappo.products', e =\u003e { console.log('state updated', e.detail)} )\nwindow.addEventListener('stappo.orders', e =\u003e { console.log('state updated', e.detail)} )\n\nstappoProducts.update(() =\u003e ({products: newProducts})) // emits 'stappo.products'\nstappoOrders.update(() =\u003e ({orders: newOrders})) // emits 'stappo.orders'\n\n```\n  \n### `stappo.update(fn)`\n  \nUpdates the application state, i.e. calls the passed function that *must* return a JSON and merges it into the application state.\nOn update all listeners are notified.\n\n`fn` is of type `(currentState) =\u003e { return newStateObj }`\n\n### `stappo.get()`\n \nReturns the current state\n\n\n# Roadmap\n\n- Cleanup unused dev dependencies\n- Pimp up the demo\n- Try to reduce sizes even more!!!\n","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fohager%2Fstappo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fohager%2Fstappo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fohager%2Fstappo/lists"}