|
| 1 | +# Translate.Next — a better Translate app for Pontoon |
| 2 | + |
| 3 | + |
| 4 | +## Tools |
| 5 | + |
| 6 | +<table> |
| 7 | + <tr> |
| 8 | + <td>Bootstrapper</td> |
| 9 | + <td>create-react-app — https://github.com/facebook/create-react-app</td> |
| 10 | + </tr> |
| 11 | + <tr> |
| 12 | + <td>Package manager</td> |
| 13 | + <td>Yarn — https://yarnpkg.com/</td> |
| 14 | + </tr> |
| 15 | + <tr> |
| 16 | + <td>Views</td> |
| 17 | + <td>React — https://reactjs.org/</td> |
| 18 | + </tr> |
| 19 | + <tr> |
| 20 | + <td>Data</td> |
| 21 | + <td>Redux — https://redux.js.org/</td> |
| 22 | + </tr> |
| 23 | + <tr> |
| 24 | + <td>Tests</td> |
| 25 | + <td>Jest — http://jestjs.io/</td> |
| 26 | + </tr> |
| 27 | + <tr> |
| 28 | + <td>Type checking</td> |
| 29 | + <td>Flow — https://flow.org/</td> |
| 30 | + </tr> |
| 31 | + <tr> |
| 32 | + <td>Localization</td> |
| 33 | + <td>Fluent — https://projectfluent.org/</td> |
| 34 | + </tr> |
| 35 | + <tr> |
| 36 | + <td>Style</td> |
| 37 | + <td>CSS</td> |
| 38 | + </tr> |
| 39 | +</table> |
| 40 | + |
| 41 | + |
| 42 | +## Code architecture |
| 43 | + |
| 44 | +### Where code goes |
| 45 | + |
| 46 | +`src/core/` contains features that are shared in the application, in the form of modules. There should be as little code as possible in this folder. |
| 47 | + |
| 48 | +`src/modules/` contains the self-contained features of the application, separated in modules. |
| 49 | + |
| 50 | +`src/rootReducer.js` creates the main reducer to be used with Redux. When adding a new module with a reducer, make sure to include that reducer to `rootReducer`. |
| 51 | + |
| 52 | +### Modules |
| 53 | + |
| 54 | +Each module should be in a folder and have an `index.js` file that serves as the module's public interface. Outside of the module, always import from the module's index, and never from specific files. This allows us to easily evolve modules and keep things decoupled, which reduces code complexity. |
| 55 | + |
| 56 | +Here are the files commonly found in a module: |
| 57 | + |
| 58 | +- `index.js` — public interface of the module |
| 59 | +- `actions.js` — actions that can be used to fetch data from an API, trigger changes, etc. |
| 60 | +- `reducer.js` — a single Redux reducer (if you need to have more than one reducer, you probably actually need to make several modules) |
| 61 | +- `constants.js` — a list of constants required by the module or other modules. It is recommended to define a NAME constant here which should be a unique identifier of the module. This name will be used in `combineReducers` and in all `mapStateToProps` to identify the subtree of the global state relevant to this module. |
| 62 | +- `components/` — a folder containing components, with file names in CamelCase |
| 63 | + |
| 64 | +Of course, more can be added if needed. For example, modules with a high number of action types might want to have an `actionTypes.js` file to separate them from actions. |
| 65 | + |
| 66 | + |
| 67 | +## Running and deploying |
| 68 | + |
| 69 | +### This feature is behind a Switch |
| 70 | + |
| 71 | +While this is under development, the feature is hidden behing a feature switch, and thus is not accessible by default. In order to turn it on, you have to run `./manage.py waffle_switch translate_next on --create`, then restart your web server. To turn it off, run `./manage.py waffle_switch translate_next off`. |
| 72 | + |
| 73 | +### Production |
| 74 | + |
| 75 | +The only required step for the front-end is to build static files with `yarn build`. Django is configured to collect the `index.html` and static files from the `build` folder and put them with other static files. All of that is automated for deployement to Heroku. |
| 76 | + |
| 77 | +### Development |
| 78 | + |
| 79 | +If you're using docker, `make run` automatically starts both a webpack server (on port 3000) and a Django server (on port 8000). Django is the server you want to hit, and it will then proxy appropriate requests to the webpack server. |
| 80 | + |
| 81 | +A common case during development is to have 3 terminals open: one for the dev servers, one for the tests and one for Flow: |
| 82 | + |
| 83 | + # terminal 1 |
| 84 | + $ make run |
| 85 | + |
| 86 | + # terminal 2 |
| 87 | + $ make test-frontend |
| 88 | + |
| 89 | + # terminal 3 |
| 90 | + $ make flow |
| 91 | + |
| 92 | +#### Enabling websocket and warm-reloading for dev |
| 93 | + |
| 94 | +Currently websocket requests are redirected by Django to the webpack server. Sadly, by default major browsers do not support websocket redirection. To enable it in Firefox, go to `about:config` and turn `network.websocket.auto-follow-http-redirect` to `true`. Note that there is a bug filed to get rid of that option entirely: https://bugzilla.mozilla.org/show_bug.cgi?id=1052909 |
| 95 | + |
| 96 | +As far as we know, it is not possible to make that work in Chrome or Edge. This only impacts development, as there's no hot reloading in production. |
| 97 | + |
| 98 | +If you can't turn on websockets, you will see errors in the console (that's not very impacting) and you'll have to reload your Django server regularly, because polling requests don't close, and after so many web page reloads, the Django process won't be able to accept new requests. |
| 99 | + |
| 100 | + |
| 101 | +## Type checking |
| 102 | + |
| 103 | +Our code uses Flow to enforce type checking. This is a good way to significantly improve resilience to bugs, and it removes some burden from unit tests (because Flow ensures that we use functions and components correctly). |
| 104 | + |
| 105 | +To check for Flow issues during development while you edit files, run: |
| 106 | + |
| 107 | + yarn flow:dev |
| 108 | + |
| 109 | +To learn more, you can read [Why use static types in JavaScript?](https://medium.freecodecamp.org/why-use-static-types-in-javascript-part-1-8382da1e0adb) or the official [Flow documentation](https://flow.org/en/docs/). Additionally, you can read through the [web-ext guide](https://github.com/mozilla/web-ext/blob/master/CONTRIBUTING.md#check-for-flow-errors) for hints on how to solve common Flow errors. |
| 110 | + |
| 111 | +Until we define our set of rules, please refer to the [addons team's Flow manifesto](https://github.com/mozilla/addons-frontend/#flow) regarding specific usage and edge cases. |
| 112 | + |
| 113 | + |
| 114 | +## Testing |
| 115 | + |
| 116 | +Tests are run using [`jest`](https://facebook.github.io/jest/). We use [`enzyme`](http://airbnb.io/enzyme/docs/api/) for mounting React components and [`sinon`](http://sinonjs.org/) for mocking. |
| 117 | + |
| 118 | +To run the test suite, use: |
| 119 | + |
| 120 | + $ yarn test |
| 121 | + |
| 122 | +It will start an auto-reloading test runner, that will refresh every time you make a change to the code or tests. |
| 123 | + |
| 124 | +Tests are put in files called `fileToTest.test.js` in the same directory as the file to test. Inside test files, test suites are created. There should be one test suite per component, using this notation: |
| 125 | + |
| 126 | +```javascript |
| 127 | +describe('<Component>', () => { |
| 128 | + // test suite here |
| 129 | +}); |
| 130 | +``` |
| 131 | + |
| 132 | +Individual tests follow `mocha`'s syntax: |
| 133 | + |
| 134 | +```javascript |
| 135 | +it('does something', () => { |
| 136 | + // unit test here |
| 137 | +}); |
| 138 | +``` |
| 139 | + |
| 140 | +We use `jest`'s [`expect`](https://facebook.github.io/jest/docs/en/expect.html) assertion tool. |
| 141 | + |
| 142 | + |
| 143 | +## Development resources |
| 144 | + |
| 145 | +### Integration between Django and React |
| 146 | + |
| 147 | +- [Making React and Django play well together — Fractal Ideas](https://fractalideas.com/blog/making-react-and-django-play-well-together/) |
| 148 | +- [Making React and Django play well together - the “hybrid app” model — Fractal Ideas](https://fractalideas.com/blog/making-react-and-django-play-well-together-hybrid-app-model/) |
| 149 | + |
| 150 | +### Code architecture |
| 151 | + |
| 152 | +- [Three Rules For Structuring (Redux) Applications — Jack Hsu](https://jaysoo.ca/2016/02/28/organizing-redux-application/) |
| 153 | +- [The Anatomy Of A React & Redux Module (Applying The Three Rules) — Jack Hsu](https://jaysoo.ca/2016/02/28/applying-code-organization-rules-to-concrete-redux-code/) |
| 154 | +- [Additional Guidelines For (Redux) Project Structure — Jack Hsu](https://jaysoo.ca/2016/12/12/additional-guidelines-for-project-structure/) |
| 155 | + |
| 156 | +### Tools documentation |
| 157 | + |
| 158 | +- [React](https://reactjs.org/docs/getting-started.html) |
| 159 | +- [Redux](https://redux.js.org/) |
| 160 | +- [create-react-app](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md) |
| 161 | +- [Flow](https://flow.org/en/docs/) |
| 162 | +- [Jest](http://jestjs.io/docs/en/getting-started) |
0 commit comments