{"id":17855590,"url":"https://github.com/nebrius/flvx","last_synced_at":"2026-03-12T00:02:46.356Z","repository":{"id":21558230,"uuid":"24877967","full_name":"nebrius/flvx","owner":"nebrius","description":"A lightweight web framework based on Facebook's Flux paradigm","archived":false,"fork":false,"pushed_at":"2017-04-21T07:28:15.000Z","size":111,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-08T13:17:06.036Z","etag":null,"topics":[],"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/nebrius.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-10-07T05:31:14.000Z","updated_at":"2017-04-21T07:28:17.000Z","dependencies_parsed_at":"2022-08-21T18:20:51.823Z","dependency_job_id":null,"html_url":"https://github.com/nebrius/flvx","commit_stats":null,"previous_names":["bryan-m-hughes/flvx"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fflvx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fflvx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fflvx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fflvx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nebrius","download_url":"https://codeload.github.com/nebrius/flvx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246866099,"owners_count":20846496,"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":[],"created_at":"2024-10-28T02:23:42.257Z","updated_at":"2025-12-12T03:31:34.516Z","avatar_url":"https://github.com/nebrius.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Flvx\n====\n\n[![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/)\n\n_Note:_ I started this as an experiment to see what I could do with the flux concept, but it never really took off, so consider this project abandonware.\n\nA lightweight web framework derived from Facebook's [Flux](http://facebook.github.io/react/docs/flux-overview.html) application architecture and is intended to be used with Facebook's [React](http://facebook.github.io/react/) UI library.\n\nFlvx modifies the Flux paradigm slightly to give it a little more structure, and to help enforce the immutable nature of the Flux philosophy. Flvx is written in ECMAScript 6 and can be used directly, or can be compiled to AMD or CommonJS compatible ECMAScript 5 code.\n\n# Installation\n\nYou can download the library in the following formats using the links below:\n\n* [ES6](https://raw.githubusercontent.com/bryan-m-hughes/flvx/master/flvx.js)\n* [AMD](https://raw.githubusercontent.com/bryan-m-hughes/flvx/master/dist/flvx.amd.js)\n* [Minified AMD](https://raw.githubusercontent.com/bryan-m-hughes/flvx/master/dist/flvx.amd.min.js)\n* [CommonJS](https://raw.githubusercontent.com/bryan-m-hughes/flvx/master/dist/flvx.commonjs.js)\n* [Minified CommonJS](https://raw.githubusercontent.com/bryan-m-hughes/flvx/master/dist/flvx.commonjs.min.js)\n\nAlternatively, you can use bower to install the ES6 version of the code:\n\n```\nbower install flvx\n```\n\n# Overview\n\nFlvx is an alternative to traditional MVC architectures that features unidirectional data flow and immutable pieces. A Flvx app is composed of a variety of pieces. Flvx provides the following pre-built pieces out of the box:\n\n- dispatcher - A method that receives events from views/links and propagates them to the store controller\n- aggregator - A method that receives updates from the stores and propagates them to the view controller\n- router - A pair of methods that wires up view controllers, link controllers, and store controllers to the dispatcher and aggregator.\n\nFlvx provides base classes that you extend to provide functionality for your app:\n\n- view controllers - A single controller that oversees all React components.\n- views - A set of React components that that are instantiated by a view controller.\n- store controller - A single controller that oversees the stores.\n- stores - Entities that store state that that are instantiated by a store controller. These can be backed by Backbone Models, custom written code, etc.\n- link controller - A single controller that oversees all connections between a server and the app.\n- links - A set of pieces that communicate with a server that are instantiated by a link controller. These are the only asynchronous pieces in Flvx.\n\nA route is comprised of a view controller, a store controller, and an optional link controller. Switching between routes means switching between sets of these controllers. Here is the relationship and data flow between all the pieces in a single route:\n\n![Flvx Architecture](https://theoreticalideations.com/static/flvx.png)\n\n# Usage\n\n## App structure\n\nA Flvx app is typically organized with the following folder structure:\n\n```\nmyapp\n├── links\n│   ├── MyLinkController.js\n│   └── my_link\n│       ├── MyLink.js\n│       └── ...\n├── stores\n│   ├── GlobalStoreController.js\n│   ├── MyStoreController.js\n│   └── my_store\n│       ├── MyStore.js\n│       └── ...\n├── views\n│   ├── MyViewController.js\n│   └── my_view\n│       ├── MyView.js\n│       └── ...\n└── app.js\n```\n\nFor each category (links, stores, and views), it is typical to put the controllers in the root directory and to put all views, links, and stores in a sub-folder that corresponds to the controller. This structure is simply a suggestion and is not required by Flvx, you can organize your code however you wish.\n\n## app.js\n\nYou should have one file that is the entry point for your app, named ```app.js``` in the example structure above. This file should be responsible for instantiating controllers and wiring them up to the routes, and routing to the first route.\n\nHere is a very simple app.js that instantiates a single route:\n\n```JavaScript\nimport { registerRoute, route } from 'flvx';\nimport { MyLinkController } from 'links/MyLinkController';\nimport { MyStoreController } from 'links/MyStoreController';\nimport { MyViewController } from 'links/MyViewController';\n\nregisterRoute('myRoute', {\n  linkController: new MyLinkController(),\n  storeController: new MyStoreController(),\n  viewController: new MyViewController()\n});\n\nroute('myRoute');\n```\n\nWhen registering a route, the store controller and view controller are required, but the link controller is optional. You can register as many routes as you want to, but note that only a single route can be active at a time.\n\n## View Controllers\n\nA view controller is an ECMAScript 6 class that extends the ```ViewController``` base class in the Flvx library.\n\n```JavaScript\nimport { ViewController } from 'flvx';\nimport { MyView } from 'views/my_view/MyView';\nimport React from 'react';\n\nexport class MyViewController extends ViewController {\n\n  render(data) {\n    React.renderComponent(new MyView(data), document.getElementById('content'));\n  }\n  \n}\n```\n\nThe ```data``` argument comes from a store controller, which will be discussed in more detail further down. Sometimes, it may be necessary to display different views depending on the contents of the data (e.g. list view vs grid view). In cases such as these, you can import multiple views and determine which one to display based on a conditional in the render method here.\n\n### Class Methods\n\n#### [void] render([primitive|object|array] data) _required_\n\nThe render method is passed data from the aggregator and is responsible for calling ```React.renderComponent```, which attaches a view to the DOM.\n\n## Views\n\nA view is simply a standard React view, e.g.:\n\n```JavaScript\nimport { dispatch } from 'flvx';\nimport React from 'react';\n\nexport let MyView = React.createClass({\n\n  render() {\n    return new React.DOM.div({\n      onClick: () =\u003e {\n        dispatch({\n          type: 'REQUEST_NEW_MESSAGE'\n        });\n      },\n      className: 'message'\n    }, this.props.message);\n  }\n  \n});\n```\n\nIn this example, we introduce the concept of dispatching actions. An action can be thought of as an event that is triggered by a view or a link. Actions are dispatched to all links and stores. An action is an object that contains a ```type``` property that indicates the type of action and can optionally contain other properties with data about the action.\n\n### Class Methods\n\nFor more information on views and the methods they support, check out Facebook's documentation on\n[React](http://facebook.github.io/react/).\n\n## Store Controllers\n\nA store controller is an ECMAScript 6 class that extends the ```StoreController``` base class in the Flvx library.\n\n```JavaScript\nimport { StoreController } from 'flvx';\nimport { MyStore } from 'stores/my_store/MyStore';\n\nlet store = Symbol();\n\nexport class MyStoreController extends StoreController {\n\n  onConnected() {\n    this.register(this[store] = new MyStore());\n  }\n\n  render() {\n    return this[store].render();\n  }\n\n}\n```\n\nStore controllers are responsible for instantiating and registering stores, and for managing the render process.\n\nHere, _render_ means to take a snapshot of the state contained in the store. When a store or store controller renders data, it takes all of the state stored inside of it, and returns a simple object (i.e. JSON-serializable) representing that state. This method is analogous to a Backbone model's ```toJSON``` method. The ```render``` method is called as part of aggregating data to views. The aggregator takes the object returned from ```render``` and passes it directly to the active view controller's ```render``` method.\n\nStore controllers are responsible for instantiating all stores for the given route. When a store is instantiated, it needs to be registered using the ```register``` method exposed by the ```StoreController``` base class. When a store is registered by a store controller or another store, it gets wired up to automatically receive dispatched actions. An action is dispatched to the controller first, and then descends down the tree formed by registering stores in a pre-order traversal. Dependencies between stores are implicit in the order they are registered.\n\n### Class Methods\n\n#### [primitive|object|array] render() _required_\n\nRenders the state of the store controller and returns it as a JSON-serializable type.\n\n#### [void] dispatch([object] action) _optional_\n\nReceives actions dispatched by the dispatcher. An action is an object with, at minimum, a ```type``` property that indicates the type of action. Actions can optionally contain more data about the action. Actions can originate from views or links.\n\n#### [void] onConnected() _optional_\n\nCalled when the store controller is connected. A store controller is connected when the route containing the store controller is routed to.\n\n#### [void] onDisconnected() _optional_\n\nCalled when the store controller is disconnected. A store controller is disconnected when a new route is routed to after having previously routed to the route containing the store controller. Note that if a store controller is registered for two or more routes, and you route between them, that the ```onDisconnected``` and ```onConnected``` methods are still called.\n\n## Stores\n\nA store has the same signature as a store controller, except that it cannot be passed to a router, and is not called directly by the dispatcher.\n\n```JavaScript\nimport { Store, aggregate } from 'flvx';\n\nlet MESSAGES = ['Hello (click me)', 'Salut', 'Hola', 'Hallo', 'Привет', '你好', 'こんにちは'];\nlet currentMessage = Symbol();\n\nexport class MyStore extends Store {\n\n  dispatch(action) {\n    switch(action.type) {\n      case 'REQUEST_NEW_MESSAGE':\n        this[currentMessage]++;\n        if (this[currentMessage] == MESSAGES.length) {\n          this[currentMessage] = 0;\n        }\n        aggregate();\n        break;\n    }\n  }\n\n  render() {\n    return {\n      message: MESSAGES[this[currentMessage]]\n    };\n  }\n\n  onConnected() {\n    this[currentMessage] = 0;\n    aggregate();\n  }\n\n}\n```\n\n### Class Methods\n\n#### [primitive|object|array] render() _required_\n\nRenders the state of the store and returns it as a JSON-serializable type.\n\n#### [void] dispatch([object] action) _optional_\n\nReceives actions dispatched by the dispatcher. An action is an object with, at minimum, a ```type``` property that indicates the type of action. Actions can optionally contain more data about the action. Actions can originate from views or links.\n\n#### [void] onConnected() _optional_\n\nCalled when the store is connected. A store is connected when it is registered with a store controller or parent store.\n\n#### [void] onDisconnected() _optional_\n\nCalled when the store is disconnected. A store is disconnected when its parent is disconnected. The parent's ```onDisconnected``` method is called before the child's ```onDisconnected``` method is called.\n\n## Link Controllers\n\nLink controllers are essentially identical to store controllers, except that they are intended to manage connections to a server, not store state. The key difference is that links can dispatch actions, but do not render data.\n\n```JavaScript\nimport { LinkController } from 'flvx';\nimport { MyLink } from 'links/my_link/MyLink';\n\nlet link = Symbol();\n\nexport class MyLinkController extends LinkController {\n\n  onConnected() {\n    this.register(this[link] = new MyLink());\n  }\n\n}\n```\n\n### Class Methods\n\n#### [void] dispatch([object] action) _optional_\n\nReceives actions dispatched by the dispatcher. An action is an object with, at minimum, a ```type``` property that indicates the type of action. Actions can optionally contain more data about the action. Actions can originate from views or links.\n\n#### [void] onConnected() _optional_\n\nCalled when the link controller is connected. A link controller is connected when the route containing the link controller is routed to.\n\n#### [void] onDisconnected() _optional_\n\nCalled when the link controller is disconnected. A link controller is disconnected when a new route is routed to after having previously routed to the route containing the link controller. Note that if a link controller is registered for two or more routes, and you route between them, that the ```onDisconnected``` and ```onConnected``` methods are still called.\n\n## Links\n\nA link has the same signature as a link controller, except that it cannot be passed to a router, and is not called directly by the dispatcher.\n\n```JavaScript\nimport { Link, aggregate } from 'flvx';\n\nexport class MyLink extends Link {\n\n  dispatch(action) {\n    switch(action.type) {\n      case 'REQUEST_NEW_MESSAGE':\n        // Fictional XHR helper\n        xhr('POST', 'stats', {\n          action: 'messageRequested'\n        });\n        break;\n    }\n  }\n\n}\n```\n\n# Example\n\nCheck out the [example](example) directory to see the above examples (minus links) working together. Note that everything is written in ECMAScript 6, and compiled back to ECMAScript 5 using [Traceur](https://github.com/google/traceur-compiler/wiki/GettingStarted) and [Gulp](http://gulpjs.com/). A built version of the example, ready to be loaded in a browser, is available in the [example-dist](example-dist) directory. For a larger example, take a look at the [SChat](https://github.com/bryan-m-hughes/schat) app I wrote.\n\nLicense\n=======\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Bryan Hughes bryan@theoreticalideations.com (https://theoreticalideations.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnebrius%2Fflvx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnebrius%2Fflvx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnebrius%2Fflvx/lists"}