{"id":13438075,"url":"https://github.com/reactuate/reactuate","last_synced_at":"2025-03-19T18:31:47.435Z","repository":{"id":57348464,"uuid":"49798542","full_name":"reactuate/reactuate","owner":"reactuate","description":"React/Redux stack (not a boilerplate kit)","archived":false,"fork":false,"pushed_at":"2016-07-22T09:25:14.000Z","size":196,"stargazers_count":486,"open_issues_count":13,"forks_count":15,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-09-21T17:58:23.674Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reactuate.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-17T01:38:06.000Z","updated_at":"2024-05-25T13:33:16.000Z","dependencies_parsed_at":"2022-08-24T18:00:21.661Z","dependency_job_id":null,"html_url":"https://github.com/reactuate/reactuate","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactuate%2Freactuate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactuate%2Freactuate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactuate%2Freactuate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactuate%2Freactuate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reactuate","download_url":"https://codeload.github.com/reactuate/reactuate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221729798,"owners_count":16871106,"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-07-31T03:01:02.710Z","updated_at":"2025-03-19T18:31:47.427Z","avatar_url":"https://github.com/reactuate.png","language":"JavaScript","readme":"[![npm package][npm-badge]][npm]\n[![dependencies][david-dm]][david]\n\n# Reactuate\n\n[![Join the chat at https://gitter.im/reactuate/reactuate](https://badges.gitter.im/reactuate/reactuate.svg)](https://gitter.im/reactuate/reactuate?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nReactuate is an opinionated stack for building React/Redux-based frontend applications with a focus on DDD (Domain-Driven Design). The rationale behind\nthis project is to ensure there's a \"standard stack\" with compatible\nversions of various libraries stitched together in a cohesive way. This comes\nat a cost of reduced ability to swap out certain components but ultimately\nhelps shipping software fast.\n\nThis is an early version, and some things are in a flux, and some underlying\nlibraries and APIs will change before 1.0.\n\n[Next version roadmap](https://github.com/reactuate/reactuate/milestones/0.2)\n\n## Version\n\nCurrent published version:\n\n    0.1.21\n\n## License\n\nReactuate is licensed under the terms of [Apache 2.0 license](LICENSE.md).\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [Core Objectives](#core-objectives)\n- [Features](#features)\n- [Overview](#overview)\n- [Requirements](#requirements)\n- [Getting started](#getting-started)\n- [Webpack Layer](#webpack-layer)\n  - [Webpack Configuration](#webpack-configuration)\n- [Reactuate Application](#reactuate-application)\n  - [Running a development Webpack server](#running-a-development-webpack-server)\n    - [Development server](#development-server)\n- [Language Layer](#language-layer)\n  - [Babel Layer](#babel-layer)\n- [React Layer](#react-layer)\n  - [Redux Layer](#redux-layer)\n  - [React Routing](#react-routing)\n  - [Layout](#layout)\n  - [Domain](#domain)\n  - [Managing effects](#managing-effects)\n  - [Putting it all together](#putting-it-all-together)\n- [Example Application](#example-application)\n- [Appendix 1. Post-Installation Instructions](#appendix-1-post-installation-instructions)\n- [Appendix A. Package file](#appendix-a-package-file)\n- [Appendix B. .gitignore](#appendix-b-gitignore)\n- [Appendix B1. .npmignore](#appendix-b1-npmignore)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# Core Objectives\n\n1. Fork-and-forget (or fork-and-follow) is not a great way to keep up with what's happening in the original boilerplate (and in the space in general). Therefore, starting off a cloned boilerplate \"kit\" is not an acceptable solution. Reactuate is distributed as a __dependency__.\n1. Reactuate is strictly a frontend-oriented stack and is not meant to provide a foundation for so called \"universal\" (server and client side) JavaScript applications.\n1. Reducing the amount of noise. Many kits suffer from the need to create too many files for each \"functional vertical\" (such as action creators, constants, reducer), which in turn leads to increased maintenance complexity (try renaming one of the verticals!), _import nightmare_ and inability to have a compact overview of the functionality.\n1. Discovering and learning the capabilities of a comprehensive stack could be complicated. What's worse, maintaining such stacks can be equally painful. Therefore, unconventionally, Reactuate is written as a *literate program* and is meant to be read as an article and be a concise reference manual — while being a functional library. The effects of this literate program are also included in Reactuate's repository to improve its accessibility. *Certain parts of code that do not contribute to the reader's clarity are commented out and therefore omitted from the rendered documentation. They are, however, used for source code production.*\n\n# Features\n\n* [Redux](https://github.com/rackt/redux) implementation of the \"Flux\"-like\narchitecture (unidirectional data flow)\n* Domain-Driven Design with [tcomb](https://github.com/gcanti/tcomb)\n* [Babel](https://babeljs.io) future generation JavaScript transpiler.\n* Hot code reloading for React with [react-transform-hmr](https://github.com/gaearon/react-transform-hmr)\n* [react-router](https://github.com/rackt/react-router) and [redux-router](https://github.com/acdlite/redux-router) are used for routing.\n* [redux-saga](https://github.com/yelouafi/redux-saga) for complex asynchronous\nworkflows orchestration\n\n# Overview\n\nBelow is a quick reference diagram of the Reactuate stack.\n\n![Diagram](https://raw.githubusercontent.com/reactuate/reactuate/master/diagram.png)\n\n# Requirements\n\nReactuate requires the following version of Node.js:\n\n\u003c!--+ [Node.js version]() --\u003e\n\n    v5.4.1\n\nMore recent versions are allowed, within the upper boundary of the next major version.\n\nIn order to produce the extracted source code of Reactuate (should you need it), you will need `litpro` npm package to be installed. Currently required version:\n\n\u003c!--+ [litpro version]() --\u003e\n\n    0.12.0\n\nBuilding Reactuate is quite simple:\n\n```shell\n$ make\n```\n\n# Getting started\n\nAs it has been mentioned before, Reactuate is distributed as a dependency, and can be installed with npm. Assuming you already initialized your project with `npm init`:\n\n```shell\n$ npm install --save-dev reactuate\n# if you answered 'yes' to the postinstall script:\n$ npm start\n# otherwise:\n$ node node_modules/reactuate/webpack-dev-server.js\n```\n\nNow you can open [http://localhost:3000](http://localhost:3000) to run the first application!\n\n_Note: The development server port defaults to 3000, but can be configured using `PORT` environment variable._\n\nThe rest of this manual will introduce you to the concepts and software used in the stack. Please note that this stack is developed as a literate program. This\nmeans that you'll see excerpts from the stack's code and examples of how you\ncan use these parts. All excerpts are marked with this image: [![excerpt]](#)\n\n\n# Webpack Layer\n\nWe serve the application in development mode and package the production version using [webpack](http://webpack.github.io) package [npm|webpack@1.12.14](# \"push:\"):\n\n## Webpack Configuration\n\nThere's normally little to no Webpack configuration tweaking you need to do.\n\nBy default, it will assume your index.html to be this:\n\n\u003c!--+ [index.html]() --\u003e\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n\t\u003chead\u003e\n    \u003cmeta charset=\"utf-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\"\u003e\n\t\t\u003ctitle\u003eReactuate Application\u003c/title\u003e\n\t\u003c/head\u003e\n\t\u003cbody\u003e\n\t\t\u003cdiv id=\"app\"\u003e\u003c/div\u003e\n\t\u003c/body\u003e\n\u003c/html\u003e\n```\n\n\u003c!--+ [sample/index.html](#:index.html \"save:\") --\u003e\n\nWhen you are ready to override it, simply copy the above file to the root of your project.\n\n\u003c!--+ [index file]() --\u003e\n\u003c!--+\n```js\nrequire('fs').existsSync(path.join(process.cwd(), 'index.html')) ?\n  path.join(process.cwd(), 'index.html') : path.join(__dirname, 'sample', 'index.html')\n``` --\u003e\n\nThis file will be processed with [npm|html-webpack-plugin@2.15.0](# \"push:\").\n\nReactuate will search for source code files in this directory in your project:\n\n\u003c!--+ [source directory]() --\u003e\n\n    src\n\nIt will assume your main file in that directory to be `index.js`, and if there is no such file in your project yet, Reactuate will use its own sample file.\n\n\u003c!--+ [main file]() --\u003e\n\n\u003c!--+\n```js\nrequire('fs').existsSync(path.join(options.sourceDirectory || '_\":source directory\"', 'index.js')) ? path.join(options.sourceDirectory || '_\":source directory\"', 'index.js') : path.join(__dirname, 'sample','index.js')\n``` --\u003e\n\n\nAll the JavaScript files are going to be process by Babel through the use of\n[npm|babel-loader@6.2.4](# \"push:\") plugin.\n\nTo enable ES2015 syntax and experimental features, the following plugins are required:\n\n* [npm|babel-preset-es2015@6.6.0](# \"push:\")\n* [npm|babel-preset-stage-0@6.5.0-1](# \"push:\")\n* [npm|babel-plugin-transform-export-extensions@6.5.0-1](# \"push:\")\n\nTo enable React-specific features, a number of Babel plugins is required:\n\n* [npm|babel-plugin-react-transform@2.0.2](# \"push:\")\n* [npm|babel-preset-react@6.5.0-1](# \"push:\")\n* [npm|babel-preset-react-hmre@1.1.1](# \"push:\")\n\nIn production builds, following optimizations are used:\n\n* [npm|babel-plugin-transform-react-constant-elements@6.5.0-1](# \"push:\")\n* [npm|babel-plugin-transform-react-inline-elements@6.6.5](# \"push:\")\n* [npm|babel-plugin-transform-react-remove-prop-types@0.2.4](# \"push:\")\n\nSource code builds will be produced into this directory in your project:\n\n\u003c!--+ [build directory]() --\u003e\n\n    build\n\n\u003c!--+ []() --\u003e\n\n\u003c!--+ [webpack-config.js](# \"save:\") --\u003e\n\u003c!--+\n```js\nvar path = require('path')\n\nvar webpack = require('webpack')\nvar HtmlWebpackPlugin = require('html-webpack-plugin')\n\nmodule.exports = function(options) {\n  var plugins = []\n  var loaders = []\n\n  var production = process.env['NODE_ENV'] === 'production'\n  var src = options.sourceDirectory || '_\":source directory\"'\n  var main = options.mainFile || _\":main file\"\n  console.log('Using ' + main + ' as an entry script')\n  var index = options.indexFile || _\":index file\"\n  console.log('Using ' + index + ' as an index file')\n\n  var port = (process.env.PORT ? parseInt(process.env.PORT, 10) : 3000)\n  var entry = path.resolve(process.cwd(), main)\n``` --\u003e\n\nWhen used in development mode, Webpack should use Webpack development server as\nan entry point and enable hot module replacement,\n\n\u003c!--+\n```js\n  if (!production) {\n    entry = [\n        \"webpack-dev-server/client?http://localhost:\" + port, // Needed for hot reloading\n        \"webpack/hot/only-dev-server\", // See above\n        entry\n      ]\n  }\n``` --\u003e\n\n\u003c!--+\n```js\n  if (!production) {\n    plugins.push(new webpack.HotModuleReplacementPlugin())\n    plugins.push(new HtmlWebpackPlugin({template: index, inject: true}))\n  }\n```\n--\u003e\n\nIn production, following HTML processing will be performed:\n\n[![excerpt]](#)\n```js\nif (production) {\n  plugins.push(new HtmlWebpackPlugin({\n    template: index,\n    minify: {\n      removeComments: true,\n      collapseWhitespace: true,\n      removeRedundantAttributes: true,\n      useShortDoctype: true,\n      removeEmptyAttributes: true,\n      removeStyleLinkTypeAttributes: true,\n      keepClosingSlash: true,\n      minifyJS: true,\n      minifyCSS: true,\n      minifyURLs: true\n    },\n    inject: true\n  }))\n}\n```\n\nReactuate's Webpack configuration will define the location of the reactuate module as `REACTUATE_DIRNAME` variable in the target runtime.\n\n\u003c!--+\n```js\nplugins.push(new webpack.DefinePlugin({\"REACTUATE_DIRNAME\": production ? \"undefined\" : JSON.stringify(__dirname)}))\n``` --\u003e\n\nIn production, it will produce compacted and somewhat obscured JavaScript (no source map to avoid divulging original source code's information).\n\n\u003c!--+\n```js\nif (production) {\n  plugins.push(new webpack.optimize.UglifyJsPlugin({sourceMap: false, compress: {warnings: false}}))\n}\n``` --\u003e\n\nIt will also set `process.env` to your host's `process.env.NODE_ENV` (if none specified, then it will be assumed to be `development`).\n\n\u003c!--+\n```js\nplugins.push(new webpack.DefinePlugin({\n  \"process.env\": {\n    NODE_ENV: JSON.stringify(process.env.NODE_ENV || \"development\")\n  }\n}))\n``` --\u003e\n\n\u003c!--+\n```js\nvar jsLoaders = []\n``` --\u003e\n\nReactuate enables ES2015, react/react hot module replacement, and stage-0 presets.\n\nWhat's important, since babel-loader will **not** use local .babelrc to merge options, Reactuate will read .babelrc (but not babel configuration from package.json yet) and merge it with its own defaults (it will use [npm|deepest-merge@0.1.1](# \"push:\") for that).\n\nBy default, .babelrc takes precedence (this also means that arrays specified in .babelrc are appended to those in defaults). If the precedence needs to be flipped (for example, certain presets need to be invoked before the default ones), .babelrc.default file can be used instead of (or in addition to) .babelrc\n\n\u003c!--+\n```js\n  var fs = require('fs')\n  var deepestMerge = require('deepest-merge')\n  var babelConfig = {presets:[\"react\",\"es2015\",\"stage-0\"],\n                     plugins:[\"transform-export-extensions\"],\n                     env:{development:{presets:[\"react-hmre\"]},\n                     production: {\n                       plugins:\n                         [\"transform-react-remove-prop-types\",\n                          \"transform-react-constant-elements\",\n                          \"transform-react-inline-elements\"]}}}\n  var babelrcFile = path.join(process.cwd(), '.babelrc')\n  var defaultBabelrcFile = path.join(process.cwd(), '.babelrc.default')\n  if (fs.existsSync(defaultBabelrcFile)) {\n    console.log('Using ' + defaultBabelrcFile)\n    var defaultBabelrc = JSON.parse(fs.readFileSync(defaultBabelrcFile))\n    babelConfig = deepestMerge(defaultBabelrc, babelConfig)\n  }\n  if (fs.existsSync(babelrcFile)) {\n    console.log('Using ' + babelrcFile)\n    var babelrc = JSON.parse(fs.readFileSync(babelrcFile))\n    babelConfig = deepestMerge(babelConfig, babelrc)\n  }\n  console.log('Babel config: \\n' + JSON.stringify(babelConfig, null, ' '))\n  jsLoaders.push('babel-loader?' + JSON.stringify(babelConfig))\n``` --\u003e\n\n\u003c!--+\n```js\n  loaders.push({test: /\\.(js|jsx)$/,\n    loaders: jsLoaders,\n    exclude: /node_modules\\/(?!reactuate)/\n  })\n``` --\u003e\n\nIt will also enable *source maps* in development.\n\n\u003c!--+\n```js\n  var devtool = process.env.NODE_ENV === 'production' ? undefined : 'cheap-module-inline-source-map'\n``` --\u003e\n\nReactuate also allows importing JSON files with [json-loader](https://github.com/webpack/json-loader) [npm|json-loader@0.5.4](# \"push:\").\n\n\u003c!--+\n```js\n  loaders.push({ test: /\\.json$/, loader: 'json'})\n``` --\u003e\n\nReactuate allows importing CSS files with [npm|style-loader@0.13.1](# \"push:\") [npm|css-loader@0.23.1](# \"push:\"), [npm|less@2.6.1](# \"push:\") with [npm|less-loader@2.2.3](# \"push:\"). It also includes [npm|postcss-loader@0.8.2](# \"push:\"), [npm|postcss-import@8.0.2](# \"push:\"). In\norder to enable globbing in CSS processing in postcss-import, [npm|globby@4.0.0](# \"push:\") is required.\n\n\u003c!--+\n```js\n  loaders.push({ test: /\\.css$/, loader: 'style!css!postcss'})\n  loaders.push({ test: /\\.less$/, loader: 'style!css!less'})\n``` --\u003e\n\nReactuate allows importing fonts and images with [npm|file-loader@0.8.5](# \"push:\") and [npm|url-loader@0.5.7](# \"push:\").\n\n\u003c!--+\n```js\n  loaders.push({ test: /\\.woff(2)?(\\?.+)?$/, loader: \"url?limit=10000\u0026mimetype=application/font-woff\" })\n  loaders.push({ test: /\\.ttf(\\?.+)?$/, loader: \"url?limit=10000\u0026mimetype=application/octet-stream\" })\n  loaders.push({ test: /\\.eot(\\?.+)?$/, loader: \"file\" },\n   { test: /\\.svg(\\?.+)?$/, loader: \"url?limit=10000\u0026mimetype=image/svg+xml\" })\n  loaders.push({ test: /\\.png$/, loader: \"url-loader?limit=100000\" })\n  loaders.push({ test: /\\.jpg$/, loader: \"file-loader\" })\n\n``` --\u003e\n\nReactuate also requires [npm|raw-loader@0.5.1](# \"push:\") to allow loading raw\nfiles as a string, if necessary, using the `\"raw!/path/to/file\"` syntax.\n\n\u003c!--+\n```js\n  return {\n    entry: entry,\n    devtool: devtool,\n    plugins: plugins,\n    postcss: function() {\n      return [\n      require('postcss-import')({\n        resolve: function(id, base) {\n            return require('globby').sync(path.join(base, id))\n        },\n        onImport: function (files) {\n             files.forEach(this.addDependency)\n         }.bind(this)\n      }) ]\n    },\n    output: {\n      path: path.resolve(process.cwd(), '_\":build directory\"'),\n      publicPath: '/',\n      filename: 'js/bundle.js'\n    },\n    module: {loaders: loaders},\n    target: \"web\", // Make web variables accessible to webpack, e.g. window\n    stats: false, // Don't show stats in the console\n    progress: true\n  }\n}\n```\n\nIn order to automate your production builds, add this to your package.json:\n\n\u003c!--+ [npm run build]() --\u003e\n```json\n\"scripts\": {\n  \"build\": \"NODE_ENV=production webpack --config node_modules/reactuate/default-webpack-config.js --progress --colors\"\n}\n```\n\nYou will be able to run it with\n\n\u003c!--+ [npm run build command]() --\u003e\n```shell\n$ npm run build\n```\n\n\u003c!--+ [default webpack config]() --\u003e\n\u003c!--+\n```js\nvar path = require('path')\nvar fs = require('fs')\nvar configFile = path.join(process.cwd(), \"webpack.config.js\")\nif (fs.existsSync(configFile)) {\n  console.log('Using webpack config ' + configFile)\n}\nvar config = fs.existsSync(configFile) ? require(configFile) : {}\nmodule.exports = require(path.join(__dirname, 'webpack-config'))(config)\nmodule.exports._config = config\n``` --\u003e\n\n\u003c!--+ [default-webpack-config.js](#:default-webpack-config \"save:\") --\u003e\n\n## Running a development Webpack server\n\nIt is imperative to be able to run an easy to update, hot-reloadable development version of the application before shipping a build. This is what [npm|webpack-dev-server@1.14.1](# \"push:\") does.\n\nIn order to start a development Webpack server, you can run:\n\n\u003c!--+ []() --\u003e\n```shell\n$ node node_modules/reactuate/webpack-dev-server.js\n```\n\nAlternatively, you can add a convenience helper to your `package.json`:\n\n\u003c!--+ [webpack-dev-server-script]() --\u003e\n```json\n\"scripts\": {\n  \"start\": \"node node_modules/reactuate/webpack-dev-server.js\"\n}\n```\n\nWith this you can simply run the following to start your development server:\n\n\u003c!--+ [webpack-dev-server-start]() --\u003e\n```shell\n$ npm start\n```\n\n### Development server\n\n[![excerpt]](#)\n\u003c!--+ [webpack-dev-server.js](# \"save:\") --\u003e\n```js\nvar path = require('path'),\n    webpack = require('webpack'),\n    WebpackDevServer = require('webpack-dev-server'),\n    config = require(path.join(__dirname, 'default-webpack-config')),\n    port = (process.env.PORT ? parseInt(process.env.PORT, 10) : 3000)\n\nconsole.log('Starting server...\\n')\n\nnew WebpackDevServer(webpack(config), { // Start a server\n  publicPath: config.output.publicPath,\n  hot: true, // With hot reloading\n  inline: false,\n  historyApiFallback: true,\n  quiet: false,\n  proxy: config._config.devProxy\n}).listen(port, 'localhost', function (err, result) {\n  if (err) {\n    console.log(err)\n  } else {\n    console.log('Server started')\n    console.log('Listening at localhost:' + port)\n  }\n})\n```\n\n# Language Layer\n\n## Babel Layer\n\nReactuate encourages the use of most recent versions of Babel. [Babel](http://babeljs.io) is a transpiler from future versions of ECMAScript to JavaScript you can run in the browser today [npm|babel-core@6.7.4](# \"push:\") (also required as a peer dependency [npm-peer|babel-core@6.7.4](# \"push:\")).\n\nBabel 6 is still fairly new and unfortunately, not all tools support it well, but this should be less of a problem going forward.\n\nIn order to avoid generating plain JavaScript files for this package, we also include [babel-register](https://babeljs.io/docs/usage/require/) [npm|babel-register@6.7.2](# \"push:\")\n\nES6 also has new APIs that are provided by [npm|babel-polyfill@6.7.4](# \"push:\").\n\nReactuate itself requires the following Babel configuration:\n\n[![excerpt]](#)\n\u003c!--+ [.babelrc]() --\u003e\n```json\n{\"presets\":[\"react\",\"es2015\",\"stage-0\"], \"plugins\":[\"transform-export-extensions\"]}\n```\n\n\u003c!--+ [.babelrc](#:.babelrc \"save:\") --\u003e\n\n# React Layer\n\nReactuate is a React-based stack, so it naturally depends on [npm|react@15.0.1](# \"push:\") and[npm|react-dom@15.0.1](# \"push:\").\n\n## Redux Layer\n\nPart of React's power lies in the associated \"Flux\" architecture. There are many\ndifferent implementations of it, and Reactuate is using [Redux](http://rackt.org/redux/) [npm|redux@3.3.1](# \"push:\") and its React binding [npm|react-redux@4.4.1](# \"push:\"). To enable asynchronous action creators, we have included [npm|redux-thunk@2.0.1](# \"push:\") (however, we promote another way to handle asynchronous operations, more on that later). It also uses [npm|redux-logger@2.6.1](# \"push:\") for logging.\n\nOur own version of `createStore` takes care of a few things automatically.\n\n[![excerpt]](#)\n\u003c!--+ [createStore.js]() --\u003e\n```js\nimport { createHistory }                         from 'history'\nimport { createStore, applyMiddleware, compose } from 'redux'\nimport { Provider }                              from 'react-redux'\nimport thunk                                     from 'redux-thunk'\nimport { reduxReactRouter, routerStateReducer }  from 'redux-router'\nimport createLogger                              from 'redux-logger'\nimport sagaMiddleware                            from 'redux-saga'\n\nimport domainMiddleware                          from './domainMiddleware'\n\nexport default function(routes, domains) {\n  let sagas = []\n  for (var domainName in domains) {\n    let sagasDict = domains[domainName].get('sagas')\n    for (var sagaName in sagasDict) {\n      sagas.push(sagasDict[sagaName])\n    }\n  }\n  let store = compose(\n    applyMiddleware(\n```\n\nIt enables Saga middleware for complex asynchronous operations orchestration:\n\n```js\n      sagaMiddleware(...sagas),\n```\n\nIt enables serializability of domain actions:\n\n```js\n      domainMiddleware,\n```\n\nIt also enables asynchronous action creators:\n\n```js\n      thunk,\n```\n\nAnd adds logging in the development mode:\n\n```js\n      createLogger({\n        predicate: (getState, action) =\u003e\n        (process.env.NODE_ENV === 'development' \u0026\u0026\n        action['type'] !== 'EFFECT_TRIGGERED' \u0026\u0026\n        action['type'] !== 'EFFECT_RESOLVED' \u0026\u0026\n        !action['type'].startsWith(\"@@redux\")),\n        actionTransformer: (action) =\u003e {\n          if (action['type'] === '@@reactuate/action') {\n            return action.payload\n          } else {\n            return action\n          }\n        }\n        })),\n```\n\nIt is important to note that it automatically injects a store enhancer for react-router:\n\n```js\n    reduxReactRouter({routes, createHistory})\n  )(createStore)\n  return store\n}\n```\n\n\u003c!--+ [src/createStore.js](#:createStore.js \"save:\") --\u003e\n\n## React Routing\n\nAs a foundation for routing React applications, we use [react-router](https://github.com/rackt/react-router)\n[npm|react-router@1.0.3](# \"push:\") (which requires a peer dependency of [npm|history@1.17.0](# \"push:\")).\n\nWe also supplement it with a [npm|Redux extension](https://github.com/acdlite/redux-router) [npm|redux-router@1.0.0-beta8](# \"push:\"). Although this\none is less stable, we believe it has more comprehensive functionality comparing to [redux-simple-router](redux-simple-router).\n\nFirst of all, we want to define a way to create a router-enabled composite reducer:\n\n* Inject `routerStateReducer` at `router`\n\n\u003c!--+ [combineReducers.js]() --\u003e\n\n[![excerpt]](#)\n\n**combineReducers**\n\n```js\nimport { combineReducers }    from 'redux'\nimport { routerStateReducer } from 'redux-router'\n\nexport default function(reducers) {\n   if (typeof reducers !== 'object') {\n     throw \"Reactuate reducers should be an object (and not a function)\"\n   }\n   return combineReducers({router: routerStateReducer, ...reducers})\n}\n```\n\n\u003c!--+ [src/combineReducers.js](#:combineReducers.js \"save:\") --\u003e\n\nWe also standardize route initialization. This step is hidden from the end user.\n\n[![excerpt]](#)\n\n**createRouter**\n\n\u003c!--+ [createRouter.js]() --\u003e\n\n```js\nimport React           from 'react'\nimport { ReduxRouter } from 'redux-router'\nimport { Provider }    from 'react-redux'\n\nexport default function(store, routes, createElement) {\n  return \u003cProvider store={store}\u003e\u003cReduxRouter createElement={createElement}\u003e{routes}\u003c/ReduxRouter\u003e\u003c/Provider\u003e\n}\n```\n\n\u003c!--+ [src/createRouter.js](#:createRouter.js \"save:\") --\u003e\n\n## Layout\n\nMany React/Redux applications adopt the following directory layout (or a variation of it):\n\n```\nsrc/\n   actions/\n     UserActions.js\n     FooActions.js\n   constants/\n     UserConstants.js\n     FooConstants.js\n   reducers/\n     UserReducers.js\n     FooReducers.js\n   components/\n     Login.js\n     Dashboard.js\n```\n\nWe find this layout to be very counter-productive comparing to organizing code by domains. It is only marginally better than organizing directories or packages by entity types. Consider doing this in Java:\n\n```\ncom.foo.bar.\n           classes\n           interfaces\n           singletons\n           factories\n```\n\nDoes this make a lot of sense to you? Hope not!\n\nTherefore, we propose organizing Reactuate-based applications by domain:\n\n```\nsrc/\n   user/\n      actions.js\n      reducers.js\n   small/\n      index.js\n```\n\nThis way you don't need to jump across the\nhierarchy of the project while working on one domain, and you can easily\nrename the whole domain without having to rename 4-5 files across the project!\n\n## Domain\n\nNow we have approached one of the most important aspects of Reactuate. We structure our applications around domains, not types of artifacts.\n\nWhile JavaScript as a language is quite flexible and doesn't possess a strong type system, there are some great libraries available that solve this problem to an extent. Reactuate applications make a heavy use of [npm|tcomb@3.0.0](# \"push:\") and its helper module [npm|tcomb-form-types@1.1.0](# \"push:\").\n\nFirst of all, we need to define a class representing a domain. It is a named container for all things associated with one domain (including, but not limited to, types, action creators, sagas and a reducer).\n\n[![excerpt]](#)\n\n**Domain**\n\n\u003c!--+ [Domain.js]() --\u003e\n```js\nexport default class Domain {\n\n  constructor(prefix) {\n    this.prefix = prefix || \"\"\n  }\n\n  withPrefix(name) {\n    return (this.prefix == \"\" ? \"\" : this.prefix + \"/\") + name\n  }\n\n  withoutPrefix(name) {\n    return name.replace(new RegExp(`^${this.prefix}\\/`),'')\n  }\n\n  register(type, name, value) {\n    this[type] = this[type] || {}\n    this[type][name] = value\n  }\n\n  get(type) {\n    return this[type] || {}\n  }\n}\n```\n\u003c!--+ [src/Domain.js](# \"save:\") --\u003e\n\nMost of the time, you don't need to do anything with the Domain object yourself,\nexcept for passing it as a parameter to other Reactuate functions that you'll see below. One significant exception to that is our current convention of \"attaching\" your types to the domain. Consider this example:\n\n\u003c!--++ []() --\u003e\n```js\nconst domain = new Domain(\"user\")\n\nconst User = t.struct({\n  email: t.String\n}, 'User')\n\ndomain.User = User\n```\n\nThis way you can easily access types from other domains when importing those domains:\n\n```js\nimport user from '../user'\n\nconst Message = t.struct({\n  user: user.User,\n  message: t.String\n}, 'Message')\n```\n\nEvery domain begins with a state. We define state with tcomb's help:\n\n\u003c!--+ [Domain state example]() --\u003e\n```js\nimport ft from 'tcomb-form-types'\n\nimport { t, Domain } from 'reactuate'\n\nconst domain = new Domain(\"counter\")\nexport default domain\n\nconst State = t.struct({\n  counter: ft.Number.Integer\n}, 'State')\n```\n\nIn the above example, we are defining a state that has a counter. Now, we should define an increment action. Reactuate offers helper functionality to do so, in adherence with [FSA](https://github.com/acdlite/flux-standard-action) [npm|flux-standard-action@0.6.1](# \"push:\") guidelines:\n\n[![excerpt]](#)\n\n**createAction**\n\n\u003c!--+ [createAction.js]() --\u003e\n```js\nimport t from 'tcomb'\n\nexport default function(domain, action, payload = t.Any, defaultValue = undefined, meta = t.Any) {\n  let actionString = domain.withPrefix(action)\n  function ActionCreator(value = defaultValue, error = false,\n                         metaValue = undefined, path = [payload.displayName]) {\n\n    if (ActionCreator.is(value)) {\n      return value\n    }\n\n    value = payload(value)\n\n    if (typeof metaValue !== 'undefined') {\n      metaValue = meta(metaValue)\n    }\n\n    if (!(this instanceof ActionCreator)) {\n      return new ActionCreator(value, error, metaValue, path)\n    }\n\n    this.type = actionString\n    this.payload = value\n\n    if (!!error) {\n      this.error = true\n    }\n\n    if (typeof metaValue !== 'undefined') {\n      this.meta = metaValue\n    }\n\n    if (process.env.NODE_ENV !== 'production') {\n      Object.freeze(this)\n    }\n  }\n\n  ActionCreator.meta = {\n    kind: 'actionCreator',\n    payload: payload,\n    name: actionString,\n    identity: false\n  }\n\n  ActionCreator.displayName = `Action ${actionString}(${payload.displayName})`\n  ActionCreator.actionCreator = true\n  ActionCreator.action = action\n\n  ActionCreator.is = x =\u003e x instanceof ActionCreator\n\n  domain.register('actions', action, ActionCreator)\n  return ActionCreator\n}\n```\n\n\u003c!--+ [src/createAction.js](#:createAction.js \"save:\") --\u003e\n\nUnfortunately, tcomb structures do not fit the definition of a plain object\nrequired by redux, so we have to implement a custom middleware that strips the extra metadata.\n\n[![excerpt]](#)\n\n**domainMiddleware**\n\n\u003c!--+ [domainMiddleware.js]() --\u003e\n```js\nexport default function ({ getState }) {\n  return (next) =\u003e (action) =\u003e {\n    if (!!action.constructor.actionCreator) {\n      let newAction = {type: \"@@reactuate/action\", payload: {...action}, meta: {name: action.constructor.action}}\n      return next(newAction)\n    } else {\n      return next(action)\n    }\n  }\n}\n```\n\n\u003c!--+ [src/domainMiddleware.js](#:domainMiddleware.js \"save:\") --\u003e\n\n`IncrementCounter` in the example below is an action creator:\n\n\u003c!--+ [Domain action example]() --\u003e\n```js\n\nimport { createAction } from 'reactuate'\n\nconst incrementParameter = t.struct({increment: ft.Number.Integer}, 'incrementParameter')\nconst IncrementCounter = createAction(domain, 'IncrementCounter',\n                                      t.maybe(incrementParameter))\n```\n\nReactuate has a helper that allows creating a reducer that (again) makes a good use of tcomb. The syntax that it defines is based on the one from `tcomb.match()`. After specifying the domain and the initial state, it takes a variadic list of matchers:\n\n\n\u003c!--+ []() --\u003e\n```js\ncreateReducer(domain, initialState, ...matchers: Array\u003cMatcher\u003e)\n```\n\nWhere each `Matcher` has the following structure: `type, [guard], handler`:\n\n* `type` is a tcomb type\n* `guard` is an **optional** predicate `(state, action) =\u003e boolean`\n* `handler` is a function that handles the action `(state, action) =\u003e State`\n\nIt also takes care of disabling state mutation (however, normally this shouldn't be necessary, if tcomb is used for action creators).\n\n[![excerpt]](#)\n\n**createReducer**\n\n\u003c!--+ [createReducer.js]() --\u003e\n```js\nimport t from 'tcomb'\n\nexport default function(domain, initialState, ...cases) {\n  let reducer = (state = initialState, action) =\u003e {\n    let typedAction = action\n    if (action['type'] === '@@reactuate/action') {\n      let actionCreator = domain.get('actions')[domain.withoutPrefix(action.payload.type)]\n      if (!t.Nil.is(actionCreator)) {\n        typedAction = actionCreator(action.payload.payload, action.payload.error, action.payload.meta)\n      }\n    }\n    Object.freeze(state)\n    let stateCases = cases.map(f =\u003e {\n      if (typeof f === 'function' \u0026\u0026 typeof f.meta === 'undefined') {\n        return (handler) =\u003e f(state, handler)\n      } else {\n        return f\n      }\n    })\n    return t.match(typedAction, ...stateCases, t.Any, () =\u003e state)\n  }\n  domain.reducer = reducer\n  return reducer\n}\n```\n\u003c!--+ [src/createReducer.js](#:createReducer.js \"save:\") --\u003e\n\nNow, we can define a reducer this way:\n\n\u003c!--+ [Domain reducer example]() --\u003e\n```js\nimport { createReducer } from 'reactuate'\n\nconst initialState = State({counter: 0}, 'CounterState')\n\nconst reducer = createReducer(domain, initialState,\n    IncrementCounter, (state, action) =\u003e {\n      let increment = 1;\n      if (incrementParameter.is(action.payload)) {\n        increment = action.payload.increment\n      }\n      return State.update(state, {counter: { $set: state.counter + increment }})\n    })\n```\n\nDid you notice we avoided creating the whole layer of 'constants'?\n\n\u003c!--+ [Domain example]() --\u003e\n\u003c!--+\n```js\n_\":Domain state example\"\n_\":Domain action example\"\n_\":Domain reducer example\"\n```\n--\u003e\n\u003c!--+ [sample/counter/index.js](#:Domain-example \"save:\") --\u003e\n\n## Managing effects\n\nWhen asynchronous (thunk middleware) action creates are getting too complex, it's a sign that it's time to manage effects in an orchestrated way. We are using [redux-saga](https://github.com/yelouafi/redux-saga), [npm|redux-saga@0.9.5](# \"push:\") for that.\n\n\n[![excerpt]](#)\n\n**createSaga**\n\n\u003c!--+ [createSaga.js]() --\u003e\n```js\nexport default function(domain, name, saga) {\n  domain.register('sagas', name, saga)\n}\n```\n\n\u003c!--+ [src/createSaga.js](#:createSaga.js \"save:\") --\u003e\n\nThe below example shows handling the counter example in an async way (we're introducing a delay as well):\n\n\u003c!--+ [Saga example]() --\u003e\n```js\nimport ft               from 'tcomb-form-types'\nimport { t,\n         Domain,\n         createSaga,\n         createAction,\n         fork,\n         take, put }    from 'reactuate'\n\nimport domain           from './index'\n\nconst asyncDomain = new Domain(\"counterAsync\")\n\nconst incrementParameter = t.struct({increment: ft.Number.Integer}, 'incrementParameter')\nconst IncrementCounterDelayed = createAction(asyncDomain,\n                                'IncrementCounterDelayed', t.maybe(incrementParameter))\n\nfunction delay(millis) {\n    return new Promise(resolve =\u003e\n      setTimeout( () =\u003e resolve(true), millis)\n    )\n}\n\ncreateSaga(asyncDomain, 'IncrementCounterDelayed', function* () {\n  while(true) {\n     const nextAction = yield take(IncrementCounterDelayed.is)\n     yield fork(function* () {\n       yield delay(1000)\n       yield put(domain.actions.IncrementCounter(nextAction.payload))\n     })\n   }\n})\n\nexport default asyncDomain\n```\n\n\u003c!--+ [sample/counter/async.js](#:Saga-example \"save:\") --\u003e\n\n\n## Putting it all together\n\n[![excerpt]](#)\n\n\u003c!--+ [Application.js]() --\u003e\n```js\nimport t               from 'tcomb'\nimport ReactDOM        from 'react-dom'\n\nimport createStore     from './createStore'\nimport combineReducers from './combineReducers'\nimport createRouter    from './createRouter'\n\nexport default class Application {\n\n  constructor(properties) {\n    this.routes = properties.routes\n    this.element = properties.element || document.getElementById('app')\n    this.domains = properties.domains || {}\n    this.reducers = {}\n    for (var key in this.domains) {\n      if (!t.Nil.is(this.domains[key].reducer)) {\n        this.reducers[key] = this.domains[key].reducer\n      }\n    }\n    if (!!this.routes) {\n      this.createElement = properties.createElement\n      this.store = createStore(this.routes, this.domains)(combineReducers(this.reducers))\n      this.router = createRouter(this.store, this.routes, this.createElement)\n    }\n  }\n\n  render() {\n    ReactDOM.render(this.router, this.element)\n  }\n\n}\n```\n\n\u003c!--+ [src/Application.js](#:Application.js \"save:\") --\u003e\n\u003c!--+ []() --\u003e\n\n\u003c!--+ [index.js]() --\u003e\n\u003c!--+\n```js\nrequire('babel-register')\nrequire('babel-polyfill')\nmodule.exports = require('./src')\n```\n--\u003e\n\n\u003c!--+ [index.js](#:index.js \"save:\") --\u003e\n\n\n\u003c!--+ [index.es6.js]() --\u003e\n```js\nexport Application            from './Application'\nexport Domain                 from './Domain'\nexport createReducer          from './createReducer'\nexport createAction           from './createAction'\nexport createSaga             from './createSaga'\nexport React                  from 'react'\nexport { Route }              from 'react-router'\nexport { connect }            from 'react-redux'\nexport { bindActionCreators } from 'redux'\nexport t                      from 'tcomb'\n\nexport { takeEvery, takeLatest } from 'redux-saga'\nimport { effects, utils }        from 'redux-saga'\nmodule.exports = {...module.exports, ...effects, ...utils}\n```\n\u003c!--+ [src/index.js](#:index.es6.js \"save:\") --\u003e\n\n# Example Application\n\nYou can use it this way (this is the sample file you get by default, by the way!):\n\n\u003c!--+ [Example]() --\u003e\n\n```js\nimport { React, Route, Application,\n         connect, bindActionCreators } from 'reactuate'\n\nimport counter from './counter'\nimport counterAsync from './counter/async'\n\nclass App extends React.Component {\n  render() {\n    return \u003cdiv\u003e{this.props.children}\u003c/div\u003e\n  }\n}\n\nclass HomePage extends React.Component {\n  handleIncrement() {\n    this.props.actions.IncrementCounter()\n  }\n  handleIncrementDelayed() {\n    this.props.actions.IncrementCounterDelayed()\n  }\n  render() {\n    return (\u003cdiv\u003e\n     \u003ch1\u003eReactuate Application\u003c/h1\u003e\n     \u003cp\u003e\n     Congratulations! You are running a Reactuate application now. Here is what you need to do to start developing your own application:\n     \u003c/p\u003e\n     \u003col\u003e\n       \u003cli\u003eUnless you have done so already, add a start script to your package.json:\n        \u003cpre\u003e\u003ccode\u003e\n{`_\"Running a development Webpack server:webpack-dev-server-script|trim\"`}\n        \u003c/code\u003e\u003c/pre\u003e\n        This way you can easily run your application:\n        \u003cpre\u003e\u003ccode\u003e\n{`_\"Running a development Webpack server:webpack-dev-server-start\"`}\n        \u003c/code\u003e\u003c/pre\u003e\n       \u003c/li\u003e\n       \u003cli\u003eAlso, add this to your package.json\n       \u003cpre\u003e\u003ccode\u003e\n{`_\"Webpack Configuration:npm run build\"`}\n       \u003c/code\u003e\u003c/pre\u003e\n       This way you can easily make a production build of your application:\n       \u003cpre\u003e\u003ccode\u003e\n{`_\"Webpack Configuration:npm run build command\"`}\n       \u003c/code\u003e\u003c/pre\u003e\n       \u003c/li\u003e\n       \u003cli\u003eCopy the starter file from {`${typeof REACTUATE_DIRNAME === 'undefined' ? \"\u003creactuate package dir\u003e\" : REACTUATE_DIRNAME}/sample/index.js`} to src/index.js\u003c/li\u003e\n     \u003c/ol\u003e\n     \u003cdiv\u003e\n       \u003ch5\u003eCounter example\u003c/h5\u003e\n       {this.props.counter}\n       \u003cbutton onClick={() =\u003e this.handleIncrement()}\u003eIncrement\u003c/button\u003e\n       \u003cbutton onClick={() =\u003e this.handleIncrementDelayed()}\u003eIncrement with delay\u003c/button\u003e\n     \u003c/div\u003e\n    \u003c/div\u003e)\n  }\n}\n\nHomePage = connect(state =\u003e ({counter: state.counter.counter}),\n                   dispatch =\u003e ({actions:\n                     bindActionCreators({...counter.actions, ...counterAsync.actions}, dispatch)}))(HomePage)\n\nconst routes = (\n  \u003cRoute component={App}\u003e\n    \u003cRoute path=\"/\" component={HomePage} /\u003e\n  \u003c/Route\u003e\n)\n\nnew Application({routes, domains: {counter, counterAsync}}).render()\n```\n\n\u003c!--+ [sample/index.js](#:Example \"save:\") --\u003e\n\n\n# Appendix 1. Post-Installation Instructions\n\nReactuate is nice enough to help you finalizing your setup once it is installed. This requires [npm|yesno@0.0.1](# \"push:\").\n\n\u003c!--+ [postinstall]() --\u003e\n\u003c!--+\n```js\n'use strict';\n\nvar _path = require('path');\n\nvar _path2 = _interopRequireDefault(_path);\n\nvar _yesno = require('yesno');\n\nvar _yesno2 = _interopRequireDefault(_yesno);\n\nvar _fs = require('fs');\n\nfunction _interopRequireDefault(obj) { return obj \u0026\u0026 obj.__esModule ? obj : { default: obj }; }\n\nfunction printInstructions() {\n  console.log('Add this to your package.json:\\n\\n\"scripts\": {\\n  \"start\": \"node node_modules/reactuate/webpack-dev-server.js\"\\n}\\n\\n  This way you can easily run your application:\\n\\n$ npm start\\n\\n  Also, you can add this to your package.json\\n\\n\"scripts\": {\\n  \"build\": \"NODE_ENV=production webpack --config node_modules/reactuate/default-webpack-config.js --progress --colors\"\\n}\\n\\n  This way you can easily make a production build of your application:\\n\\n$ npm run build\\n');\n}\n\nvar cwd = process.cwd();\nvar packageJson = _path2.default.join(cwd, '..', '..', 'package.json');\n\nvar startScript = \"node node_modules/reactuate/webpack-dev-server.js\";\nvar buildScript = \"NODE_ENV=production webpack --config node_modules/reactuate/default-webpack-config.js --progress --colors\";\n\nif ((0, _fs.existsSync)(packageJson)) {\n  (function () {\n    var pkg = JSON.parse((0, _fs.readFileSync)(packageJson));\n    var scripts = pkg.scripts || {};\n    if (scripts.start !== startScript || scripts.build !== buildScript) {\n      printInstructions();\n      _yesno2.default.ask('Reactuate can add these convenience helpers to your package.json automatically. Proceed? ([yes]/no)', true, function (ok) {\n        if (ok) {\n          console.log(\"Updating your package.json\");\n          var _pkg = JSON.parse((0, _fs.readFileSync)(packageJson));\n          scripts.start = startScript;\n          scripts.build = buildScript;\n          _pkg.scripts = scripts;\n          (0, _fs.writeFileSync)(packageJson, JSON.stringify(_pkg, null, 4));\n        }\n        process.exit(0);\n      });\n    } else {\n      console.log(\"Congratulations! Your package scripts are already configured for Reactuate\");\n    }\n  })();\n} else {\n  console.log(\"WARNING: Looks like you haven't initialized your package with `npm init`\");\n  printInstructions();\n}\n```\n--\u003e\n\u003c!--+ [postinstall.js](#:postinstall \"save:\") --\u003e\n\n# Appendix A. Package file\n\nWe process all dependencies declared in this file to produce a list of dependencies for package.json.\n\n\u003c!--+ [dependency]() --\u003e\n\u003c!--+\n```js\nfunction(input, args, name) {\n    var arr = input.split(\"@\"),\n        package = arr[0],\n        version = arr[1]\n    return '\"' + package + '\": \"' + version + '\"'\n}\n```\n--\u003e\n\u003c!--+ [dependency](#:dependency \"define:\")\n\n\n\u003c!--+ [package.json]() --\u003e\n\u003c!--+\n```json\n{\n  \"name\": \"reactuate\",\n  \"version\": \"_\"Version\"\",\n  \"description\": \"Reactuate is an opinionated React-based stack\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026   exit 1\",\n    \"postinstall\": \"node ./postinstall.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/reactuate/reactuate.git\"\n  },\n  \"keywords\": [\n    \"react\",\n    \"redux\",\n    \"frontend\"\n  ],\n  \"author\": \"Yurii Rashkovskii \u003cyrashk@gmail.com\u003e\",\n  \"license\": \"Apache-2.0\",\n  \"engines\": {\"node\": \"\u003e=_\"Requirements:Node.js version\" \u003c6.0\"},\n  \"dependencies\": {\n      _\"npm| .mapc dependency | .join \\,\\n\"\n  },\n  \"peerDependencies\": {\n      _\"npm-peer| .mapc dependency | .join \\,\\n\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/reactuate/reactuate/issues\"\n  },\n  \"homepage\": \"https://github.com/reactuate/reactuate#readme\",\n  \"babel\": _\"Babel Layer:.babelrc\"\n}\n```\n--\u003e\n\n\u003c!--+ [package.json](# \"save:\") --\u003e\n\n# Appendix B. .gitignore\n\n\u003c!--+ [.gitignore](# \"save:\") --\u003e\n\n```\n.checksum\nnode_modules\n```\n\n# Appendix B1. .npmignore\n\nAs npm documentation says:\n\n\"Use a .npmignore file to keep stuff out of your package. If there's no .npmignore file, but there is a .gitignore file, then npm will ignore the stuff matched by the .gitignore file. If you want to include something that is excluded by your .gitignore file, you can create an empty .npmignore file to override it\"\n\n\u003c!--+ [.npmignore](# \"save:\") --\u003e\n ```\n Makefile\n .checksum\n ```\n\n[npm]: https://www.npmjs.org/package/reactuate\n[npm-badge]: https://badge.fury.io/js/reactuate.svg\n[david-dm]: https://david-dm.org/reactuate/reactuate.svg\n[david]: https://david-dm.org/reactuate/reactuate\n[excerpt]: https://img.shields.io/badge/excerpt-from%20the%20stack-green.svg\n","funding_links":[],"categories":["Uncategorized","Code Design","Boilerplate","JavaScript","Marks"],"sub_categories":["Uncategorized","Boilerplate","Other","[React - A JavaScript library for building user interfaces](http://facebook.github.io/react)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactuate%2Freactuate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freactuate%2Freactuate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactuate%2Freactuate/lists"}