Skip to content

Commit c4499e0

Browse files
committed
Update Flow section and remove Nodemon
1 parent e39f33e commit c4499e0

File tree

17 files changed

+96
-107
lines changed

17 files changed

+96
-107
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ The code of this tutorial works on Linux, macOS, and Windows.
3535

3636
[02 - Babel, ES6, ESLint, Flow](/tutorial/02-babel-es6-eslint-flow)
3737

38-
[03 - Express, Nodemon, PM2](/tutorial/03-express-nodemon-pm2)
38+
[03 - Express, PM2](/tutorial/03-express-pm2)
3939

4040
[04 - Webpack, React](/tutorial/04-webpack-react)
4141

tutorial/02-babel-es6-eslint-flow/README.md

Lines changed: 53 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ If you try to run `yarn start` now, it should print the correct output, but you
4242
},
4343
```
4444

45-
**Note**: A `.babelrc` file at the root of your project could also be used instead of the `babel` field of `package.json`. Your root folder will get more and more bloated over time, so keep the Babel config in `package.json` until it grows too large.
45+
**Note**: A `.babelrc` file at the root of your project could also be used instead of the `babel` field of `package.json`, but since your root folder will get more and more bloated over time, I would recommend to keep the Babel config in `package.json` until it grows too large.
4646

4747
- Try running `yarn start` again. The `lib/index.js` file should now have been correctly transformed into ES5 code (`var` everywhere!).
4848

@@ -55,23 +55,20 @@ We now have the basic compilation working. To make this environment a bit more u
5555
```json
5656
"scripts": {
5757
"start": "yarn run watch",
58-
"clean": "rimraf lib",
59-
"prebuild": "yarn run clean",
60-
"build": "babel src -d lib",
61-
"lint": "eslint src/**/*.js",
6258
"watch": "watch 'yarn run main' src --interval=1",
63-
"main": "yarn run lint && yarn run build && node lib"
59+
"main": "yarn run lint && yarn run build && node lib",
60+
"build": "yarn run clean && babel src -d lib",
61+
"clean": "rimraf lib",
62+
"lint": "eslint src/**/*.js"
6463
},
6564
```
6665

67-
### `clean` with `rimraf`, and `prebuild`
66+
### `clean` with `rimraf`
6867

6968
`clean` is a task that simply deletes our entire auto-generated `lib` folder before every `build`. This is typically useful to get rid of old compiled files after renaming or deleting some in `src`, or to make sure the `lib` folder is in sync with the `src` folder if your build fails and you don't notice. We use `rimraf` instead of a plain `rm -rf` in order to support Windows environments as well.
7069

7170
- Run `yarn add --dev rimraf`.
7271

73-
Tasks that are prefixed by `pre` or `post` will respectively be called after and before said task. `clean` is related to `build` and we want to run it before every build, so it's a good candidate for a `pre` task. `prebuild` simply calls `yarn run clean`.
74-
7572
### `main` and `watch`
7673

7774
`main` is going to be... well the *main* task of our workflow. It performs every operation needed for the build (many more will be added later), and runs the program.
@@ -86,6 +83,8 @@ Alright, we're now good to go.
8683

8784
- Run `yarn start`. It should clean, build, print "Hello ES6" and start watching for changes. Try modifying `src/index.js` to make sure the whole task flow is triggered again.
8885

86+
**Note**: It is possible to prefix task names with `pre` or `post` (like `prebuild`), to trigger tasks before and after others. We could have for instance called `clean` in a `prebuild` task instead of chaining the two in one command separated by `&&`. This approach makes command lines shorter but I find that it actually reduces readability to have to jump up and down to look for any existing `pre` and `post` tasks when reading through our tasks.
87+
8988
## ES6
9089

9190
> 💡 **[ES6](http://es6-features.org/)**: The most significant improvement of the JavaScript language. There are too many ES6 features to list them here but typical ES6 code uses classes with `class`, `const` and `let`, template strings, and arrow functions (`(param) => { console.log('Hi'); }`).
@@ -133,6 +132,7 @@ In `dog.js`, we also replace `module.exports = Dog` by `export default Dog`.
133132
Note that in `dog.js`, the name `Dog` is only used in the `export`. Therefore it could be possible to export directly an anonymous class like this instead:
134133

135134
```javascript
135+
// Dog
136136
export default class {
137137
constructor(name) {
138138
this.name = name;
@@ -144,21 +144,23 @@ export default class {
144144
}
145145
```
146146

147-
You might now guess that the name 'Dog' used in the `import` in `index.js` is actually completely up to you. This would work just fine:
147+
You might now guess that the name `Dog` used in the `import` in `index.js` is actually completely up to you. This would work just fine:
148148

149149
```javascript
150150
import Cat from './dog'; // Don't do this
151151

152152
const toby = new Cat('Toby');
153153
```
154154

155-
Obviously, most of the time you will use the same name as the class / module you're importing.
155+
Obviously, most of the time you will use the same name as the class / module you're importing. Anyway!
156156

157157
- `yarn start` should still print "Wah wah, I am Toby".
158158

159159
## ESLint
160160

161-
We're going to lint our code to catch potential issues. ESLint is the linter of choice for ES6 code. Instead of configuring the rules we want for our code ourselves, we will use the config created by Airbnb. This config uses a few plugins, so we need to install those as well to use their config.
161+
> 💡 **[ESLint](http://eslint.org)** is the linter of choice for ES6 code. A linter gives you recommendations about code formatting, which enforces style consistency in your code, and code you share with your team. It's also a great way to learn about JavaScript by making mistakes that ESLint will catch.
162+
163+
ESLint works with *rules*, and there are [many of them](http://eslint.org/docs/rules/). Instead of configuring the rules we want for our code ourselves, we will use the config created by Airbnb. This config uses a few plugins, so we need to install those as well to use their config.
162164

163165
Check out Airbnb's most recent [instructions](https://www.npmjs.com/package/eslint-config-airbnb) to install the config package and all its dependencies correctly. As of 2016-11-11, they recommend using the following command in your terminal:
164166

@@ -207,11 +209,37 @@ Here we just tell ESLint that the files we want to lint are all the `.js` files
207209

208210
> 💡 **[Flow](https://flowtype.org/)**: A static type checker by Facebook. It detects inconsistent types in your code. For instance, it will give you an error if you try to use a string where should be using a number.
209211
210-
- In order for Babel to understand and remove Flow annotations during the transpilation process, install the Flow preset for Babel by running `yarn add --dev babel-preset-flow`. Then, add `"flow"` under `babel.presets` in your `package.json`.
212+
Right now, our JavaScript code is valid ES6 code. Flow can analyze plain JavaScript to give us some insights, but in order to use its full power, we need to add type annotations in our code, which will make it non-standard. We need to teach Babel and ESLint what those type annotations are in order for these tools to not freak out when parsing our files.
213+
214+
- Run `yarn add --dev flow-bin babel-preset-flow babel-eslint eslint-plugin-flowtype`.
215+
216+
`flow-bin` is the binary to run Flow in our `scripts` tasks, `babel-preset-flow` is the preset for Babel to understand Flow annotations, `babel-eslint` is a package to tell ESLint *to rely on Babel's parser* instead of its own, and `eslint-plugin-flowtype` is an ESLint plugin to lint Flow annotations.
217+
218+
- Update your `package.json` file with the following configuration for `babel` and `eslintConfig`:
219+
220+
```json
221+
"babel": {
222+
"presets": [
223+
"latest",
224+
"flow"
225+
]
226+
},
227+
"eslintConfig": {
228+
"extends": [
229+
"airbnb",
230+
"plugin:flowtype/recommended"
231+
],
232+
"plugins": [
233+
"flowtype"
234+
]
235+
},
236+
```
237+
238+
**Note**: The `plugin:flowtype/recommended` contains the instruction for ESLint to use Babel's parser. If you want to be more explicit, feel free to add `"parser": "babel-eslint"` under `eslintConfig`.
211239

212-
- Create an empty `.flowconfig` file at the root of your project
240+
I know this is a lot to take in, so take a minute to think about it. I'm still amazed that it is even possible for ESLint to use Babel's parser to understand Flow annotations. These 2 tools are really incredible for being so modular.
213241

214-
- Run `yarn add --dev flow-bin` to install Flow, and create a `typecheck` task:
242+
- Create a `typecheck` task:
215243

216244
```json
217245
"typecheck": "flow"
@@ -223,9 +251,11 @@ Here we just tell ESLint that the files we want to lint are all the `.js` files
223251
"main": "yarn run typecheck && yarn run lint && yarn run build && node lib"
224252
```
225253

226-
Alright, we should be able to run Flow now.
254+
- Create an empty `.flowconfig` file at the root of your project.
255+
256+
Alright, we should be all set for the configuration part.
227257

228-
- Add Flow annotations to `src/shared/dog.js` like so:
258+
- Add Flow annotations to `src/dog.js` like so:
229259

230260
```javascript
231261
// @flow
@@ -237,72 +267,27 @@ class Dog {
237267
this.name = name;
238268
}
239269

240-
bark(): string {
270+
bark() {
241271
return `Wah wah, I am ${this.name}`;
242272
}
243-
244-
barkInConsole() {
245-
/* eslint-disable no-console */
246-
console.log(this.bark());
247-
/* eslint-enable no-console */
248-
}
249-
250273
}
251274

252275
export default Dog;
253276
```
254277

255278
The `// @flow` comment tells Flow that we want this file to be typechecked. For the rest, Flow annotations are typically a colon after a function parameter or a function name. Check the documentation for more details.
256279

257-
Now if you run `yarn start`, Flow will work fine, but ESLint is going to complain about that non-standard syntax we're using. Since Babel's parser is all up-and-running with parsing Flow content thanks to the `babel-preset-flow` plugin we installed, it'd be nice if ESLint could rely on Babel's parser instead of trying to understand Flow annotations on its own. That's actually possible using the `babel-eslint` package. Let's do this.
258-
259-
- Run `yarn add --dev babel-eslint`
260-
261-
- In `package.json`, under `eslintConfig`, add the following property: `"parser": "babel-eslint"`
280+
- Add `// @flow` at the top of `index.js` as well.
262281

263282
`yarn start` should now both lint and typecheck your code fine.
264283

265-
Now that ESLint and Babel are able to share a common parser, we can actually get ESLint to lint our Flow annotations via the `eslint-plugin-flowtype` plugin.
266-
267-
- Run `yarn add --dev eslint-plugin-flowtype` and add `"flowtype"` under `eslintConfig.plugins` in `package.json`, and add `"plugin:flowtype/recommended"` under `eslintConfig.extends` in an array next to `"airbnb"`.
268-
269-
Now if you type `name:string` as an annotation, ESLint should complain that you forgot a space after the colon for instance.
270-
271-
**Note**: The `"parser": "babel-eslint"` property that I made you write in `package.json` is actually included in the `"plugin:flowtype/recommended"` config, so you can now remove it for a more minimal `package.json`. Leaving it there is more explicit though, so that's up to your personal preference. Since this tutorial is about the most minimal setup, I removed it.
272-
273-
- You can now add `// @flow` in every `.js` and `.jsx` file under `src`, run `yarn test` or `yarn start`, and add type annotations everywhere Flow asks you to do so.
274-
275-
One counterintuitive case is the following, for `src/client/component/message.jsx`:
276-
277-
```javascript
278-
const Message = ({ message }: { message: string }) => <div>{message}</div>;
279-
```
280-
281-
As you can see, when destructuring function parameters, you must annotate the extracted properties using a sort of object literal notation.
282-
283-
Another case you will encounter is that in `src/client/reducers/dog-reducer.js`, Flow will complain about Immutable not having a default export. This issue is discussed in [#863 on Immutable](https://github.com/facebook/immutable-js/issues/863), which highlights 2 workarounds:
284-
285-
```javascript
286-
import { Map as ImmutableMap } from 'immutable';
287-
// or
288-
import * as Immutable from 'immutable';
289-
```
290-
291-
Until Immutable officially adresses the issue, just pick whichever looks better to you when importing Immutable components. I'm personally going for `import * as Immutable from 'immutable'` since it's shorter and won't require refactoring the code when this issue gets fixed.
292-
293-
**Note**: If Flow detects type errors in your `node_modules` folder, add an `[ignore]` section in your `.flowconfig` to ignore the packages causing issues specifically (do not ignore the entire `node_modules` directory). It could look like this:
294-
295-
```flowconfig
296-
[ignore]
297-
298-
.*/node_modules/gulp-flowtype/.*
299-
```
284+
There are 2 things that I want you to try:
300285

301-
In my case, the `linter-flow` plugin for Atom was detecting type errors in the `node_modules/gulp-flowtype` directory, which contains files annotated with `// @flow`.
286+
- Replace `constructor(name: string)` by `constructor(name: number)`, and run `yarn start`. You should get a **Flow** error telling you that those types are incompatible. That means Flow is set up correctly.
302287

303-
You now have bullet-proof code that is linted, typechecked, and tested, good job!
288+
- Now replace `constructor(name: string)` by `constructor(name:string)`, and run `yarn start`. You should get an **ESLint** error telling you that Flow annotations should have a space after the colon. That means the Flow plugin for ESLint is set up correctly.
304289

305-
Back to the [previous section](/tutorial/11-testing-mocha-chai-sinon) or the [table of contents](https://github.com/verekia/js-stack-from-scratch).
290+
If you got the 2 different errors working, you are all set with Flow and ESLint!
306291

307292
Next section: [4 - Express Server](/tutorial/4-express-server)
308293

tutorial/02-babel-es6-eslint-flow/package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
"description": "JavaScript Stack from Scratch - Step-by-step tutorial to build a modern JavaScript stack",
55
"scripts": {
66
"start": "yarn run watch",
7+
"watch": "watch 'yarn run main' src --interval=1",
8+
"main": "yarn run typecheck && yarn run lint && yarn run build && node lib",
9+
"build": "yarn run clean && babel src -d lib",
710
"clean": "rimraf lib",
8-
"prebuild": "yarn run clean",
9-
"build": "babel src -d lib",
1011
"lint": "eslint src/**/*.js",
11-
"typecheck": "flow",
12-
"watch": "watch 'yarn run main' src --interval=1",
13-
"main": "yarn run typecheck && yarn run lint && yarn run build && node lib"
12+
"typecheck": "flow"
1413
},
1514
"babel": {
1615
"presets": [
@@ -23,7 +22,6 @@
2322
"airbnb",
2423
"plugin:flowtype/recommended"
2524
],
26-
"parser": "babel-eslint",
2725
"plugins": [
2826
"flowtype"
2927
]

tutorial/02-babel-es6-eslint-flow/src/dog.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
class Dog {
44
name: string;
55

6-
constructor(name: string) {
6+
constructor(name:string) {
77
this.name = name;
88
}
99

tutorial/03-express-nodemon-pm2/src/server/dog.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

tutorial/03-express-nodemon-pm2/src/server/templates/master-layout.js

Lines changed: 0 additions & 17 deletions
This file was deleted.
File renamed without changes.
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# 4 - Express Server
22

33
- Run `yarn add express`.
4-
- Run `yarn add --dev gulp-nodemon`.
5-
- Run `yarn add --dev run-sequence`.
64

75
- Create a `public` folder.
86

97
`app.use(staticPath, express.static('public'));` is to add a `static` prefix to your assets' URLs.
8+
9+
## TODO
10+
11+
Check that PM2 works on Windows.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)