├── .eslintrc
├── .gitignore
├── NOTES
├── HowStuffWorks.md
├── importsDiagram.png
└── importsDiagram.txt
├── README.md
├── Vagrantfile
├── app
├── .eslintrc
├── actions.js
├── components
│ ├── ChatLineView.jsx
│ ├── ChatUserView.jsx
│ ├── MainMenu.jsx
│ ├── NewChatEditor.jsx
│ ├── NewTodoItemEditor.jsx
│ ├── README.md
│ ├── TEMPLATE.jsx
│ ├── TodoItem.jsx
│ ├── TodoItemEditor.jsx
│ └── TodoListMenu.jsx
├── containers
│ ├── Application.css
│ ├── Application.jsx
│ ├── ChatList.css
│ ├── ChatList.jsx
│ ├── ChatPage.jsx
│ ├── HomePage.jsx
│ ├── NotFoundPage.jsx
│ ├── README.md
│ ├── ReadmePage.css
│ ├── ReadmePage.jsx
│ ├── SomePage.jsx
│ ├── TEMPLATE.css
│ ├── TEMPLATE.jsx
│ ├── TodoItemPage.jsx
│ ├── TodoListPage.jsx
│ └── TodoPage.jsx
├── elements
│ ├── README.md
│ ├── ReactLogo.jsx
│ ├── ReactLogo
│ │ ├── logo.jpg
│ │ ├── logo.png
│ │ └── logo.svg
│ └── TEMPLATE.jsx
├── fetch-helpers
│ └── rest.js
├── mainPrerender.html
├── mainRoutes.jsx
├── mainStores.js
├── mainStoresDescriptions.js
├── route-handlers
│ ├── Application.jsx
│ ├── ChatPage.jsx
│ ├── HomePage.jsx
│ ├── NotFoundPage.jsx
│ ├── README.md
│ ├── ReadmePage.jsx
│ ├── SomePage.jsx
│ ├── TEMPLATE.jsx
│ ├── TodoItemPage.jsx
│ ├── TodoListPage.jsx
│ ├── TodoPage.jsx
│ └── async.js
├── simple.html
├── store-helpers
│ ├── Chat.js
│ └── Todo.js
└── update-helpers
│ ├── list.js
│ └── react.js
├── build
└── .empty
├── config
├── .eslintrc
├── Prerenderer.jsx
├── SimpleRenderer.js
├── StoresWrapper.jsx
├── createStoresForPrerender.jsx
├── loadersByExtension.js
├── mainApp.jsx
├── mainPrerenderer.jsx
├── renderApplication.jsx
└── withTimeout.jsx
├── lib
├── DB.js
├── api.js
├── dbs.js
├── mainPrerenderApi.js
├── server-development.js
├── server-production.js
└── server.js
├── make-webpack-config.js
├── package.json
├── public
└── .empty
├── webpack-dev-server.config.js
├── webpack-hot-dev-server.config.js
├── webpack-production.config.js
└── webpack.config.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true
4 | },
5 | "rules": {
6 | "strict": 0,
7 | "curly": 0
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /build
3 | .vagrant
4 |
--------------------------------------------------------------------------------
/NOTES/HowStuffWorks.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | *An arrow means: `imports`*
4 |
5 | # How Stuff Works
6 | This documentation is for grasping the overall design. No details by intention. To get up and running quickly see `README.md`.
7 |
8 | At first sight, it may not be immediately clear why/how certain things are called/triggered.
9 | The below explanation points you in the right direction, so you can research further. If you want more details or documentation, see the relevant package.
10 | Some (inconspicuously) used/relevant node modules are explicitly mentioned with package name.
11 |
12 | ## Table of contents
13 |
14 | * [How the app is served.](#how-the-app-is-served)
15 | * [development mode](#development-mode)
16 | * [production mode](#production-mode)
17 | * [How the page updates while you are programming.](#how-the-page-updates-while-you-are-programming)
18 | * [page reloading](#page-reloading)
19 | * [hot reloading](#hot-reloading)
20 | * [How the routes work.](#how-the-routes-work)
21 | * [How the server JSON API works.](#how-the-server-json-api-works)
22 | * [How the stores work.](#how-the-stores-work)
23 | * [Stores setup](#stores-setup)
24 | * [Stores in use](#stores-in-use)
25 | * [How the actions work.](#how-the-actions-work)
26 | * [How the server DB works.](#how-the-server-db-works)
27 | * [How the 'Random fail!' works.](#how-the-random-fail-works)
28 | * [How the build works.](#how-the-build-works)
29 | * [Q&A Why](#qa-why)
30 |
31 | *****
32 |
33 | ## How the app is served.
34 | A JS webserver is included in the form of `lib/server.js`. It can be run in two modes:
35 |
36 | ### development mode
37 | Run the server using `npm run start-dev`.
38 | It will use `lib/server-development.js` which will use `lib/server.js` which will use `config/simple.js` which will use `app/simple.html`. A tiny HTML file is loaded, the JS is downloaded + executed + rendered, and ultimately output is shown.
39 |
40 | ### production mode
41 | In this mode, the React HTML output is (pre)rendered (and populated) on the server (a.k.a. isomorphic).
42 |
43 | Run the server using `npm run start`.
44 | It will use `lib/server-production.js` which will use `lib/server.js` which will use `config/mainPrerenderer.jsx` which will use `app/mainPrerender.html`. A big HTML file is loaded (and output is shown immediately), the JS is downloaded + executed + rendered, and output is updated.
45 |
46 | This server side render (prerender) is possible because the React JS can be executed on the server.
47 | In your browser the main `React.render(, document.getElementById("content"))` call (in `config/mainApp.jsx`) outputs to the browser DOM.
48 | But when pre-rendering, the main `React.renderToString()` call (in `app/prerender.jsx`) outputs to a string, which is inserted into the HTML (including React component states) as content.
49 | The browser now can show the HTML instantly in the DOM, but proceeds to run the React JS that resumes the usual DOM mutations.
50 |
51 | Note: Routes that are asynchronously loaded can not be pre-rendered.
52 |
53 |
54 | ## How the page updates while you are programming.
55 | After running the app webserver in development mode (see above) you'd have to manually reload the page after changing a JSX file.
56 | It is possible to automatically reload _or_ update the page to reflect your changes:
57 |
58 | ### page reloading
59 | Ensure that you are running the app webserver in development mode.
60 |
61 | Then run another server using `npm run dev-server`.
62 | It will rebuild while watching for file changes, and it will trigger your page to reload afterwards.
63 |
64 | ### hot reloading
65 | Ensure that you are running the app webserver in development mode.
66 |
67 | Then run another server using `npm run hot-dev-server`.
68 | It will rebuild while watching for file changes, and it will update the currently shown and affected component(s) while keeping their state.
69 | Note this is experimental, and in some cases you'll need to refresh manually.
70 |
71 |
72 | ## How the routes work.
73 | In React after opening the app and going to some page, there is no actual HTML loaded from the server. React app just replaces a component that acts as a page, including any child components.
74 | But you'd like to have the URL reflect this, and allow user to use browser history (back/forward). A router takes care of these things. (package react-router)
75 |
76 | In this case, the root of your app is not the Application React component.
77 | This starts at `lib/server.js` which will use `config/mainApp.jsx` which instantiates the router and ultimately uses `app/mainRoutes.jsx` to load routes.
78 | You'll find that all pages are subroutes within the `app` route, which instantiates `app/Application/index.jsx`, which contains a `` component that inserts subroute output.
79 |
80 |
81 | ## How the server JSON API works.
82 | The `lib/server.js` serves the application, but it also serves the API URLs (`lib/api.js`) that the stores talk with.
83 | It initializes two databases (todolist and todoitem) once, and then continues to listen for GET/POST requests on specific URLs.
84 |
85 |
86 | ## How the stores work.
87 | As in Flux; the Stores affect the React components. (package `items-store`) And the stores talk to the JSON API (`app/fetch-helpers/rest.js`).
88 | See [Q&A Why](#qa-why)
89 |
90 | ### Stores setup
91 | The stores are constructed as such: startpoint is `config/mainApp.jsx` which will use `app/mainStores.js`. This then:
92 |
93 | - defines routines to handle JSON API read/writes (package `superagent`), and
94 | - sets up a queue that only allows one REST request at a time, and aggregates subsequent changes.
95 | These are then sent as one request..
96 | - and ultimately constructs the two respective `ItemStore` objects (based on `app/mainStoresDescriptions.js`) to which it assigns these routines, queue, and the initial data. This initial data may have been inserted via `app/prerender.html` and `app/`.
97 | - These are then exported back to `config/mainApp.jsx`, along with a store named `Router`.
98 |
99 | The store `Router` just holds a `transition` value which is later read in `app/containers/Application.jsx` to show "loading..." in UI.
100 | The stores `TodoList` and `TodoItem` only have minor differences.
101 |
102 | If you wonder where the default data is inserted, see (#how-the-server-db-works).
103 |
104 | ### Stores in use
105 |
106 | todo :question: this section needs review and should be extended.
107 |
108 | Note: Components should not access the stores except for reading in `getProps()`. Everything else should be done with actions.
109 |
110 |
111 | ## How the actions work.
112 | The Actions affect the stores. (package items-store)
113 |
114 | The actions are setup in `app/mainStores.js` (bottom) from `app/actions.js` which uses the implementation supplied with items-store.
115 | They are triggered/made by the input fields in containers, such as `app/containers/TodoListPage.jsx`.
116 | They end up affecting a store. See [How the stores work.](#how-the-stores-work)
117 |
118 |
119 | ## How the server DB works
120 | When you run `npm run start-dev` (or without `-dev` ofcourse) this will start the server, as you can see defined in `package.json`. This lets node execute `lib/server-development.js` which uses `lib/server.js` where the default data is loaded, and a server (package express) is thrown together that responds to GET POST and DELETE.
121 |
122 | This (REST API with JSON data format) server is accessible via `http://localhost:8080/_/list/mylist` for example, and this is what the application uses to fetch data for the stores.
123 |
124 |
125 | ## How the 'Random fail!' works.
126 | This [Chaos Monkey](https://github.com/Netflix/SimianArmy/wiki) lives in `lib/server.js` and helps you experience realistic server-client retrieval times and errors while developing.
127 | At some time your application is requesting 3 things from the server, and they return in the wrong order and incomplete. Will it break?
128 | Or a form could not be sent to the server. Will it notify the user?
129 |
130 |
131 | ## How the build works.
132 | A build can compile your JS files into one big file, while applying some optimisations (to make it smaller, faster, or obfuscated).
133 | Its also used to add files and features (otherwise not supported by JS in the browser) to your project, such as `JSX`, `markdown`, or `SASS`.
134 |
135 | When you start run a dev-server (like `npm run dev-server` or `npm run hot-dev-server`) it does the builds for you, while it watches for changing files.
136 | Or you can manually do a normal build using the `npm run build`. Note: these `npm run` scripts are defined in `package.json`.
137 |
138 | Depending on what way you used to do this build, a different build configuration is used. For example the normal build script as seen in `package.json` starts webpack with custom config `webpack-production.config.js` which uses shared config `make-webpack-config.js`.
139 | Most webpack configuration is in that shared config file, per entry. Only one main entry is defined. Pre-rendering happens depending on the custom config.
140 | This is where a lot of node modules (packages) come into play: loaders add JSX support, debug options are set, and the output is set to `build/` is set.
141 |
142 | # Q&A Why
143 | **Design choices explained.**
144 | Ok, so now you know the how. But why do it that way? Questions about design choices, answered by the author(s). (Tobias Koppers)
145 |
146 | **(interim, this document should only concern the How question) :exclamation: TODO extract Q&A info and document it.**
147 |
148 | What is the argument for using items-store? (from https://github.com/webpack/react-starter/pull/49 )
149 | > Q: What was the argument for using items-store?
150 | > A:
151 | >
152 | > I didn't want to write a new module. I actually tried using Reflux.js, but couldn't find a good workflow for pre-rendering, optimistic updates and merging of multiple writes. You could do it manually but that is something I would expect from a flux implementation. items-store is a very simple store base class that coordinate this behavior (the repo actually also contains a simple helper for actions and a react mixin, but these are theoretically independent and you don't have to use them with the store).
153 | >
154 | > items-store allows to serialize and deserialize the store data to inject the data after pre-rendering. It manages optimistic updates and merges multiple writes. But items-store only offers a simple key-value store API and forces you to map more complex operations (via store-helpers) to this model. It's just a caching layer with events to the remote API (which need to be provided in the constructor).
155 | >
156 | > items-store basically provides a "raw data" store, while other implementations give you the ability to write higher level stores. In items-store you need to put this higher-level behavior in store-helpers. The advantage is that this way basic functionality is already provided by items-store.
157 | >
158 | > Now there is an alternative to items-store, which could provide "pre-rendering" part too: http://fluxible.io/ they use dehydrate and rehydrate to (de)serialize to data from the stores and provide it to the client stores.
159 |
160 | Regarding the paths that store data travels (from https://github.com/webpack/react-starter/pull/51 )
161 | > Q: How is it triggered to refresh everything from the server,
162 | > A: `config/mainApp.jsx` invalidates store data when you change the page. When the pages read the data again it is invalid and will be refetched.
163 |
164 | > Q: how does it propagate changes when the user edits items, and
165 | > A: The component fires an action (from `app/actions.jsx`) on edit. The action is handled in `app/mainStores.jsx` and writes some items on stores. The stores update their internal cache (which is displayed on the page as optimistic update) and do server requests (through their registered handlers in `app/mainStores.jsx`.
166 |
167 | > Q: how do values travel before ending up in some components render() ?
168 | > A: component requests values from store in getProps() -> `app/mainStores.jsx` read (unavailable or invalidated) data from server -> internal `items-store` cache for the store -> getProps() -> components this.props -> render()
169 |
170 | > Q: how does the queue combine multiple requests? I cant imagine subsequent add/remove/edits would result in just one rest call.. do they?
171 | > A: items-store store a single update per entry. Any subsequent updateItem() call causes both updates to be merged (mergeUpdates from items-store). Requests from stores to the server are queued (queueRequest in app/mainStores.jsx). Here only a single ongoing request is allowed. All writes that happen in the meantime are merged into a single write.
172 |
--------------------------------------------------------------------------------
/NOTES/importsDiagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webpack/react-starter/16c0db3a3bad3cbf611007608339be31fc27bc8b/NOTES/importsDiagram.png
--------------------------------------------------------------------------------
/NOTES/importsDiagram.txt:
--------------------------------------------------------------------------------
1 | @startuml
2 |
3 | package client {
4 | cloud [config/mainApp] as app
5 | }
6 |
7 | package ui {
8 | component elements
9 | component components
10 | component containers
11 | component [route-handlers] as rh
12 | component mainRoutes
13 | }
14 |
15 | component [store-helpers] as sh
16 | component [fetch-helpers] as fh
17 | component [update-helpers] as uh
18 |
19 | component actions
20 |
21 | package stores {
22 | component mainStores
23 | component mainStoresDescriptions
24 | }
25 |
26 | package server {
27 | component [lib/server] as server
28 | component [lib/mainPrerenderApi] as prerenderApi
29 | component [config/mainPrerenderer] as mainPrerenderer
30 | component [lib/api] as api
31 | database "lib/db" as db
32 | }
33 |
34 | component [external styles/components] as ext
35 |
36 |
37 |
38 | server -right-> api
39 | server .down.> mainPrerenderer
40 | server -down-> prerenderApi
41 | api --right-> db
42 | prerenderApi -up-> db
43 |
44 | app ---> mainRoutes
45 | app ---> mainStores
46 | mainPrerenderer -----> mainRoutes
47 | mainPrerenderer -----> mainStoresDescriptions
48 |
49 | mainStores --> actions
50 | mainStores -right-> mainStoresDescriptions
51 | mainStores -down-> fh
52 | mainStoresDescriptions -down-> uh
53 |
54 | mainRoutes -right-> rh
55 | rh -right-> containers
56 | containers -right-> components
57 | containers -down-> containers
58 | components -> components
59 | components -right-> elements
60 | elements -> elements
61 | elements -up-> ext
62 |
63 | containers --> sh
64 | containers --> actions
65 |
66 | @enduml
67 |
68 | // http://www.planttext.com/planttext
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # webpack/react-starter
2 |
3 | Starter template for react and webpack.
4 |
5 | ## Features
6 |
7 | * Compilation with webpack
8 | * React and jsx
9 | * react-router
10 | * Stylesheets can be CSS, LESS, SASS, Stylus or mixed
11 | * Embedded resources like images or fonts use DataUrls if appropriate
12 | * A simple flag loads a react component (and dependencies) on demand.
13 | * Development
14 | * Development server
15 | * Optionally Hot Module Replacement development server (LiveReload for Stylesheets and React components enabled)
16 | * Uses SourceUrl for performance, but you may switch to SourceMaps easily
17 | * Production
18 | * Server example for prerendering for React components
19 | * Initial data inlined in page
20 | * Long Term Caching through file hashes enabled
21 | * Generate separate css file to avoid FOUC
22 | * Minimized CSS and javascript
23 | * Also supports coffee-script files if you are more a coffee-script person.
24 | * You can also require markdown or text files for your content.
25 |
26 | ## Local Installation
27 |
28 | Install [node.js](https://nodejs.org) or [io.js](https://iojs.org)
29 |
30 | Just clone this repo and change the `origin` git remote.
31 |
32 | ``` text
33 | npm install
34 | ```
35 |
36 | ## Installation via Vagrant
37 |
38 | Install [vagrant](https://vagrantup.com)
39 |
40 | ``` text
41 | vagrant up
42 | vagrant ssh
43 | cd /vagrant
44 | ```
45 |
46 | ## Development server
47 |
48 | ``` text
49 | # start the webpack-dev-server
50 | npm run dev-server
51 | # wait for the first compilation is successful
52 |
53 | # in another terminal/console
54 | # start the node.js server in development mode
55 | npm run start-dev
56 |
57 | # open this url in your browser
58 | http://localhost:8080/
59 | ```
60 |
61 | The configuration is `webpack-dev-server.config.js`.
62 |
63 | It automatically recompiles and refreshes the page when files are changed.
64 |
65 | Also check the [webpack-dev-server documentation](http://webpack.github.io/docs/webpack-dev-server.html).
66 |
67 |
68 | ## Hot Module Replacement development server
69 |
70 | ``` text
71 | # start the webpack-dev-server in HMR mode
72 | npm run hot-dev-server
73 | # wait for the first compilation is successful
74 |
75 | # in another terminal/console
76 | # start the node.js server in development mode
77 | npm run start-dev
78 |
79 | # open this url in your browser
80 | http://localhost:8080/
81 | ```
82 |
83 | The configuration is `webpack-hot-dev-server.config.js`.
84 |
85 | It automatically recompiles when files are changed. When a hot-replacement-enabled file is changed (i. e. stylesheets or React components) the module is hot-replaced. If Hot Replacement is not possible the page is refreshed.
86 |
87 | Hot Module Replacement has a performance impact on compilation.
88 |
89 |
90 | ## Production compilation and server
91 |
92 | ``` text
93 | # build the client bundle and the prerendering bundle
94 | npm run build
95 |
96 | # start the node.js server in production mode
97 | npm run start
98 |
99 | # open this url in your browser
100 | http://localhost:8080/
101 | ```
102 |
103 | The configuration is `webpack-production.config.js`.
104 |
105 | The server is at `lib/server.js`
106 |
107 | The production setting builds two configurations: one for the client (`build/public`) and one for the serverside prerendering (`build/prerender`).
108 |
109 |
110 | ## Legacy static assets
111 |
112 | Assets in `public` are also served.
113 |
114 |
115 | ## Build visualization
116 |
117 | After a production build you may want to visualize your modules and chunks tree.
118 |
119 | Use the [analyse tool](http://webpack.github.io/analyse/) with the file at `build/stats.json`.
120 |
121 |
122 | ## Loaders and file types
123 |
124 | Many file types are preconfigured, but not every loader is installed. If you get an error like `Cannot find module "xxx-loader"`, you'll need to install the loader with `npm install xxx-loader --save` and restart the compilation.
125 |
126 |
127 | ## Common changes to the configuration
128 |
129 | ### Add more entry points
130 |
131 | (for a multi page app)
132 |
133 | 1. Add an entry point to `make-webpack-config.js` (`var entry`).
134 | 2. Add a new top-level react component in `app` (`xxxRoutes.js`, `xxxStoreDescriptions.js`, `xxxStores.js`).
135 | 3. (Optional) Enable `commonsChunk` in `webpack-production.config.js` and add `` to `app/prerender.html`.
136 | 4. Modify the server code to require, serve and prerender the other entry point.
137 | 5. Restart compilation.
138 |
139 | ### Switch devtool to SourceMaps
140 |
141 | Change `devtool` property in `webpack-dev-server.config.js` and `webpack-hot-dev-server.config.js` to `"source-map"` (better module names) or `"eval-source-map"` (faster compilation).
142 |
143 | SourceMaps have a performance impact on compilation.
144 |
145 | ### Enable SourceMaps in production
146 |
147 | 1. Uncomment the `devtool` line in `webpack-production.config.js`.
148 | 2. Make sure that the folder `build\public\debugging` is access controlled, i. e. by password.
149 |
150 | SourceMaps have a performance impact on compilation.
151 |
152 | SourceMaps contains your unminimized source code, so you need to restrict access to `build\public\debugging`.
153 |
154 | ### Coffeescript
155 |
156 | Coffeescript is not installed/enabled by default to not disturb non-coffee developer, but you can install it easily:
157 |
158 | 1. `npm install coffee-redux-loader --save`
159 | 2. In `make-webpack-config.js` add `".coffee"` to the `var extensions = ...` line.
160 |
161 |
162 | ## License
163 |
164 | Copyright (c) 2012-2015 Tobias Koppers [](https://www.gittip.com/sokra/)
165 |
166 | MIT (http://www.opensource.org/licenses/mit-license.php)
167 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | _script = <CONTENT