|
| 1 | +<div align="center"> |
| 2 | + <!-- Build Status TODO: update to real jenkins URL --> |
| 3 | + <a href="https://travis-ci.org/mxstbr/react-boilerplate"> |
| 4 | + <img src="https://travis-ci.org/mxstbr/react-boilerplate.svg" alt="Build Status" /> |
| 5 | + </a> |
| 6 | + <!-- Test Coverage TODO: update to real coveralls URL --> |
| 7 | + <a href="https://coveralls.io/r/mxstbr/react-boilerplate"> |
| 8 | + <img src="https://coveralls.io/repos/github/mxstbr/react-boilerplate/badge.svg" alt="Test Coverage" /> |
| 9 | + </a> |
| 10 | +</div> |
| 11 | + |
| 12 | +# Frontend Technology Stack |
| 13 | + |
| 14 | +### Navigation <small style="color: grey; font-weight: normal">(↓ marks in-document links)</small> |
| 15 | +| **General** | **JavaScript** | **CSS** | **Testing** | |
| 16 | +|----------|----------|----------|----------| |
| 17 | +| ↓ [Tooling](#tooling) | ↓ [Javascript Overview](#javascript-overview) | ↓ [CSS & Styling Overview](#css-overview) | ↓ [Testing Overview](#testing-overview) | [Reselect](./docs/js/reselect.md) | |
| 18 | +| ↓ [Deployment](#deployment) | [ImmutableJS](./docs/js/immutablejs.md) | ↓ [Fonts](#fonts) | [Unit Testing](./docs/testing/unit-testing.md) | | |
| 19 | +| ↓ [File Glossary](#file-glossary) |[Redux Saga](./docs/js/redux-saga.md) | [CSS Modules](./docs/css/css-modules.md) | [Component Testing](./docs/testing/component-testing.md) | |
| 20 | +|| [Routing](./docs/js/routing.md) | [PostCSS](./docs/css/postcss.md) | [Redux Testing](./docs/testing/redux-testing.md) | |
| 21 | +|| [i18n](./docs/js/i18n.md) |
| 22 | + |
| 23 | +## JavaScript Overview |
| 24 | + |
| 25 | +### View |
| 26 | +Powered by [React ➝](https://facebook.github.io/react/). <small style="color: grey; font-weight: normal">(➝ marks external links)</small> |
| 27 | + |
| 28 | +### Code Organization |
| 29 | +We differentiate between **dumb**, reusable and ideally functional **stateless** `components` and **smart** **stateful** `containers`. |
| 30 | +Read Dan Abramov's [explanation to this approach ➝](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0). |
| 31 | + |
| 32 | +We organize code primarily **by feature**, not by functionality. That means we co-locate all component-specific code in the same folder. An example for a container component: |
| 33 | + |
| 34 | +``` |
| 35 | +├ CoolContainer |
| 36 | +├── index.js // the actual react component |
| 37 | +├── actions.js // container-specific actions |
| 38 | +├── constants.js // container-specific constants |
| 39 | +├── reducer.js // container-specific reducer |
| 40 | +├── sagas.js // container-specific sagas |
| 41 | +├── selectors.js // container-specific selectors |
| 42 | +├── styles.css // container-specific styles |
| 43 | +└── tests/ // container-specific tests |
| 44 | + ├—— index.test.js |
| 45 | + ├—— actions.test.js |
| 46 | + ├—— reducer.test.js |
| 47 | + ├—— sagas.test.js |
| 48 | + └── selectors.test.js |
| 49 | +``` |
| 50 | + |
| 51 | +We do keep tests in a subfolder to make it easier to differentiate between `actions.js` and `actions.test.js` etc. |
| 52 | + |
| 53 | +### State management / Reudx |
| 54 | +We *manage* application state with [Redux ➝](http://redux.js.org), make it |
| 55 | +*immutable* with [ImmutableJS ➝](https://facebook.github.io/immutable-js/), improve *performance* |
| 56 | +with [reselect ➝](https://github.com/reactjs/reselect) and handle *side effects* like data fetching or login with [redux-saga ➝](http://yelouafi.github.io/redux-saga/). |
| 57 | + |
| 58 | +If you haven't worked with Redux, it's highly recommended to read through the excellent [official documentation ➝](http://redux.js.org) |
| 59 | +and/or watch these free [beginner ➝](https://egghead.io/series/getting-started-with-redux) and [advanced ➝](https://egghead.io/courses/building-react-applications-with-idiomatic-redux) video series by creator [Dan Abramov ➝](https://twitter.com/dan_abramov). |
| 60 | + |
| 61 | +We have more detailed docs on [ImmutableJS](docs/js/immutablejs.md), [reselect](docs/js/reselect.md) and [redux-saga](docs/js/redux-saga.md). |
| 62 | + |
| 63 | + |
| 64 | +### Routing |
| 65 | +We use [react-router ➝](https://github.com/ReactTraining/react-router) for routing and keep the URL state synced to redux with [react-router-redux ➝](https://github.com/reactjs/react-router-redux). |
| 66 | +See a short explanation and some code examples in the [routing doc](docs/js/routing.md). |
| 67 | + |
| 68 | +### i18n / Internationalization |
| 69 | +We use [react-intl ➝](https://github.com/yahoo/react-intl) for internationalization and pluralization. Read the [i18n doc](docs/js/i18n.md) for implementation details. |
| 70 | + |
| 71 | +## CSS Overview |
| 72 | + |
| 73 | +### Toolchain |
| 74 | +| **Tool** | **Description** | |
| 75 | +|----------|-----------------| |
| 76 | +| [PostCSS ➝](http://postcss.org) | We use PostCSS for all our CSS transformation needs | |
| 77 | +| [cssnext ➝](http://cssnext.io) | The latest CSS features without cross-browser pain | |
| 78 | +| [CSSModules ➝](https://github.com/css-modules/css-modules) | Avoid global scope littering and keep styles local | |
| 79 | +| [Autoprefixer ➝](https://github.com/postcss/autoprefixer) | Automagically™️ adds vendor prefixes | |
| 80 | +| [sanitize.css ➝](https://jonathantneal.github.io/sanitize.css/) | A modern take on `normalize.css` | |
| 81 | +| [cssnano ➝](http://cssnano.co) | CSS compressor/minifier/optimizer | |
| 82 | +| [stylelint ➝](http://stylelint.io) | Catches bugs and keeps our styles consistent | |
| 83 | + |
| 84 | + |
| 85 | +### Code Organization |
| 86 | +* We write our styles as modular and composable as possible. |
| 87 | +* No special `/css` directory. |
| 88 | +* We co-locate component-specific styles with the actual component code. |
| 89 | + |
| 90 | +Read further docs on [CSS Modules](./docs/css/css-modules.md) and [PostCSS](./docs/css/postcss.md). |
| 91 | + |
| 92 | + |
| 93 | +## Fonts Overview |
| 94 | +### Performant Web Font Loading |
| 95 | + |
| 96 | +If you import web fonts naively, you'll either have blank page until |
| 97 | +the fonts are downloaded or face an ugly FOUC (Flash of unstyled content). Both scenarios aren't ideal. |
| 98 | + |
| 99 | +[FontFaceObserver ➝](https://github.com/bramstein/fontfaceobserver) adds a class |
| 100 | +to the `body` when the fonts have loaded. (see [`app.js`](../../app/app.js#L26-L36) |
| 101 | +and [`App/styles.css`](../../app/containers/App/styles.css)) |
| 102 | + |
| 103 | +### Adding a new font |
| 104 | + |
| 105 | +1. Either add the `@font-face` declaration to `App/styles.css` or add a `<link>` |
| 106 | +tag to the [`index.html`](../../app/index.html). |
| 107 | + |
| 108 | +2. In `App/styles.css`, specify your initial `font-family` in the `body` tag |
| 109 | +with only web-save fonts. In the `body.jsFontLoaded` tag, specify your |
| 110 | +`font-family` stack with your web font. |
| 111 | + |
| 112 | +3. In `app.js` add a `<fontName>Observer` for your font. |
| 113 | + |
| 114 | + |
| 115 | +## Testing Overview |
| 116 | + |
| 117 | +### Toolchain |
| 118 | +| **Tool** | **Description** | |
| 119 | +|----------|-----------------| |
| 120 | +| [Karma ➝](https://karma-runner.github.io) | Test Runner | |
| 121 | +| [Mocha ➝](https://mochajs.org) | Test Framework | |
| 122 | +| [Expect ➝](https://github.com/mjackson/expect) | Assertion Library | |
| 123 | +| [Enzyme ➝](http://airbnb.io/projects/enzyme/) | Shallow Component Rendering | |
| 124 | +| [Sinon.JS ➝](http://sinonjs.org) | Spies / Stubs / Mocks | |
| 125 | +| [Cheerio ➝](https://www.npmjs.com/package/cheerio) | Browserless DOM testing using Node | |
| 126 | +| [Coveralls ➝](https://coveralls.io) | Test Coverage | |
| 127 | +| [Snyk ➝](https://snyk.io) | Dependency Vulnerability Checker | |
| 128 | + |
| 129 | +### Test Types |
| 130 | +| **Type** | **Description** | |
| 131 | +|----------|-----------------| |
| 132 | +| [Unit Testing](docs/testing/unit-testing.md) | We use standard unit tests for all non-component code like actions, reducers, sagas, helpers, business logic etc. | |
| 133 | +| [Component Testing](docs/testing/component-testing.md) | We use enzyme to test the correct rendering and behavior of our React components | |
| 134 | +| Integration/E2E Testing | We consciously decide to start without e2e tests to keep overhead low. It will make sense to add later on when functionality is more well-defined and less likely to change often. | |
| 135 | +| Remote Testing | We use [ngrok ➝](https://ngrok.com) to enable remote testers to access our local machine on demand. | |
| 136 | + |
| 137 | +## Deployment |
| 138 | +TODO: Add details on deployment once we have a deployment target… |
| 139 | + |
| 140 | + |
| 141 | +## Tooling |
| 142 | + |
| 143 | +### npm commands |
| 144 | +We have a [detailed doc](./docs/general/npm-commands.md) of available npm scripts with explanations. |
| 145 | + |
| 146 | +### Babel |
| 147 | +* ES6/7 support thanks to `babel-react`, `babel-preset-latest` and `babel-preset-stage-0` |
| 148 | + |
| 149 | +### Webpack 2 |
| 150 | +* Bundling |
| 151 | +* Native ES6 Modules |
| 152 | +* Hot Module Reloading incl. state preservation |
| 153 | +* Treeshaking |
| 154 | +* [Webpack's image-loader ➝](https://github.com/tcoopman/image-webpack-loader) optimizes every PNG, JPEG, GIF and SVG image. |
| 155 | +* Special images in HTML files |
| 156 | + |
| 157 | + If you specify your images in the `.html` files using the `<img>` tag, everything |
| 158 | + will work fine. The problem comes up if you try to include images using anything |
| 159 | + except that tag, like meta tags: |
| 160 | + |
| 161 | + ```HTML |
| 162 | + <meta property="og:image" content="img/yourimg.png" /> |
| 163 | + ``` |
| 164 | + |
| 165 | + The webpack `html-loader` does not recognise this as an image file and will not |
| 166 | + transfer the image to the build folder. To get webpack to transfer them, you |
| 167 | + have to import them with the file loader in your JavaScript somewhere, e.g.: |
| 168 | + |
| 169 | + ```JavaScript |
| 170 | + import 'file?name=[name].[ext]!../img/yourimg.png'; |
| 171 | + ``` |
| 172 | + |
| 173 | + Then webpack will correctly transfer the image to the build folder. |
| 174 | + |
| 175 | +### Component Generators |
| 176 | +We include a generator for components, containers, sagas, routes and selectors. |
| 177 | +Run `npm run generate` to choose from the available generators, and automatically |
| 178 | +add new parts of your application! |
| 179 | + |
| 180 | +> Note: If you want to skip the generator selection process, |
| 181 | + `npm run generate <generator>` also works. (e.g. `npm run generate route`) |
| 182 | + |
| 183 | +We use [Plop ➝](https://github.com/amwmedia/plop) to generate new components from predefined templates. You can find all the logic and templates for the generation in [internals/generators]() |
| 184 | + |
| 185 | +### Devtools |
| 186 | +[Redux devtools ➝](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) should work out of the box. |
| 187 | + |
| 188 | +### Server Configurations |
| 189 | +For routing to work correctly, we'll need to set up some server configs. |
| 190 | + |
| 191 | +##### Apache |
| 192 | +This app includes a `.htaccess` file that does two things: |
| 193 | +1. Redirect all traffic to HTTPS because ServiceWorker only works for encrypted |
| 194 | + traffic. |
| 195 | +1. Rewrite all pages (e.g. `yourdomain.com/subpage`) to `yourdomain.com/index.html` |
| 196 | + to let `react-router` take care of presenting the correct page. |
| 197 | + |
| 198 | +> Note: For performance reasons you should probably adapt it to run as a static |
| 199 | + `.conf` file (typically under `/etc/apache2/sites-enabled` or similar) so that |
| 200 | + your server doesn't have to apply its rules dynamically per request) |
| 201 | + |
| 202 | +##### Nginx |
| 203 | + |
| 204 | +Also it includes a `.nginx.conf` file that does the same on Nginx server. |
| 205 | + |
| 206 | +### Offline-first |
| 207 | +Availability without network connection is powered by a ServiceWorker with a fallback to AppCache for older browsers. All files are included automatically. No manual intervention needed thanks to [Webpack's Offline Plugin ➝](https://github.com/NekR/offline-plugin) |
| 208 | + |
| 209 | +### Add To Homescreen |
| 210 | +After repeat visits to the website, users will get a prompt to add the application to their homescreen. Combined with offline caching, this means our web app can be used exactly like a native application (without the limitations of an app store). |
| 211 | + |
| 212 | +The name and icon to be displayed are set in the `app/manifest.json`. |
| 213 | + |
| 214 | + |
| 215 | +## File Glossary |
| 216 | +``` |
| 217 | +. |
| 218 | +├── app # The application source code |
| 219 | +│ ├── assets # Fonts & images |
| 220 | +│ ├── components # „Dumb“ Components |
| 221 | +│ ├── containers # „Smart“ Containers |
| 222 | +│ ├── tests # Global tests e.g. for store, rootReducer etc. |
| 223 | +│ ├── translations # [Generated] i18n locale files (`npm run extract-intl`) |
| 224 | +│ └── utils # Global helpers and utility-functions like API-helpers etc. |
| 225 | +├── dist # [Generated] Build output |
| 226 | +├── docs # Documentation on specific technologies/frameworks etc. |
| 227 | +├── internals # Tooling & Configuration |
| 228 | +│ ├── generators # Generator templates for new components, containers, routes etc. |
| 229 | +│ ├── scripts # Utility and tooling scripts like extract-i18n, pagespeed analysis etc. |
| 230 | +│ ├── testing # Test config for Karma etc. |
| 231 | +│ └── webpack # Webpack config |
| 232 | +├── node_modules # [Generated] NPM packages |
| 233 | +├── .editorconfig # Editor styleguide for all team members |
| 234 | +├── .gitattributes # Normalizes how git handles certain files |
| 235 | +├── .gitignore # Tells git which files to ignore |
| 236 | +├── .snyk # snyk.io policy file |
| 237 | +├── CHANGELOG # [Generated] Auto-generated CHANGELOG on version bump summarizing changes since the last version |
| 238 | +├── package.json # Lists project's dependencies. Configures babel/eslint/stylelint. Specifies npm tasks |
| 239 | +└── README.md # This file |
| 240 | +``` |
0 commit comments