So I Chose React E3 – Setting up our dev env – Enhanced
**Nov 2021 update – dependency updates, minor updates required due to dependency updates, split prettier out from eslint, hot reloading is no built in and defaulted on with web-dev-server***
Last time we got all setup with React, Babel and Webpack. Our environment was all set to start coding react components with JSX and ES2015+. However, we can automate a few things to help enhance our development experience.
- Hot Reloading with webpack-dev-server
- Scripts in our package.json file
- Static analysis with ESLint
- Auto formatting with Prettier
- Automated testing with Jest
Hot Reloading with webpack-dev-server
We now get hot reloading for free with webpack-deev-server, no configuration required other than installing it. So, like the others type this in the terminal:
$ yarn add --dev webpack-dev-server
$ npm install --dev-save webpack-dev-server
And there you have it. That’s it to getting hot loading setup with webpack-dev-server. Your webpack.config.js should look like the following:
const webpack = require('webpack');
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const config = {
mode: 'development',
entry: `${path.resolve(__dirname, 'src')}/index.jsx`,
resolve: {
extensions: ['.js', '.jsx', '.json', '.css', '.scss'],
},
output: {
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new CopyWebpackPlugin({ patterns: [{ from: './src/index.html' }] }),
],
module: {
rules: [
{
test: /\.jsx?/,
include: `${path.resolve(__dirname, 'src')}`,
use: {
loader: 'babel-loader',
},
},
],
},
};
module.exports = config;
Test that hot-reloading works by starting your dev-server like so:
$ webpack-dev-server
Then open your browser and navigate to http://localhost:8081 then modify your App.jsx, save it and you will see the update without refreshing the browser.
Adding ESLint
ESLint is used to analyze our code to check for anything from code style consistency to finding common coding bugs.
ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs.
ESLint can also be configured with custom rules. There are a couple eslint extensions that others have built that I also highly recommend:
$ yarn add --dev eslint
$ npm install --dev-save eslint
After adding to your project you should setup a config file
$ ./node_modules/.bin/eslint --init
You will be prompted with a few questions that will create your config file and install other extensions, here are my preferences:
? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Airbnb
? Do you use React? Yes
? What format do you want your config file to be in? JavaScript
I like the JavaScript version of the config file so I can add comments,
*Note* If you are using yarn you will need to run yarn install to fix the fact that npm messed of eslint and delete the package.json.lock file. If you are using npm you can ignore this.
Then you can run against your code like this:
$ ./node_modules/.bin/eslint yourfile.js
Or against an entire directory
$ ./node_modules/.bin/eslint ./src --ext jsx
–ext jsx tells eslint to also check files with the extension of jsx, the default is js
After running eslint it will display a list of errors and warnings similar to this (assuming you have errors/warnings):
/projects/react-starter/src/index.jsx
3:17 error Unexpected use of file extension "jsx" for "./App.jsx" import/extensions
6:1 error Expected indentation of 2 spaces but found 1 tab indent
6:2 error Unexpected tab character no-tabs
6:2 error Expected indentation of 2 space characters but found 0 react/jsx-indent
7:1 error Expected indentation of 2 spaces but found 1 tab indent
7:2 error Unexpected tab character no-tabs
7:2 error 'document' is not defined no-undef
7:32 error Missing trailing comma comma-dangle
✖ 15 problems (15 errors, 0 warnings)
7 errors, 0 warnings potentially fixable with the `--fix` option.
You’ll see the file where errors are in and the line:column the error is on along with the reason and description of error. You can easily fix some by running again with the –fix option. If you want more detail on the error you can look the error up on the eslint website. They usually have good documentation on the error. If you chose to use Airbnb extension then you can also look up their style guide and they have good documentation on their site too. Since we will be adding jest we need to add one more item to the .eslintrc.js file so linting doesn’t flag errors in our test files. Add the following to the top of the .eslintrc.js file:
env: {
browser: true,
commonjs: true,
node: true,
jest: true,
},
These are for allowing these environment global variables. Otherwise ESLint will through errors when it parses the global variables . For example, without browser the “document” variable will through a no-undef error. Without the jest env the “it” and “expect” variables will through no-undef errors. And the node globals will also have the same issue without it. Commonjs adds some webpack globals.
I also recommend setting up a .eslintignore file:
$ touch .eslintignore
Open that file and here is what i generally start with:
.idea
dist
If you use VSCode you should add .vscode as well.
Prettier
Prettier is used to automatically format code. This helps to reduce cognitive load and removes the need to bother with verifying proper formatting during code reviews. This saves time for both the coder and the code reviewer.
An opinionated code formatter, Supports many languages, Integrates with most editors, Has few options, You press save and code is formatted, No need to discuss style in code review, Saves you time and energy
https://prettier.io/
To get started with prettier you will need to download these:
$ yarn add --dev prettier eslint-config-prettier
$ npm install --dev-save prettier eslint-config-prettier
Once these finish downloading you will need to update your .eslintrc.js config file first in the extends array add prettier and prettier/react just below the airbnb entry:
extends: ['airbnb', 'prettier'],
When all is said and done here is what my .eslintrc.js config file looks like:
module.exports = {
env: {
browser: true,
commonjs: true,
node: true,
jest: true,
},
extends: ['airbnb', 'prettier'],
};
Now that Prettier is install and setup to play nice with eslint we need to create a couple prettier files:
$ touch prettier.config.js
$ touch .prettierignore
Once those are created open the prettier.config.js file and add any overrides you prefer, you can see options on the prettier website, these are the couple I prefer:
module.exports = {
trailingComma: 'all',
singleQuote: true,
};
Now open the .prettierignore file and add any files you wish to ignore, there are usually project files to ignore, here are the defaults I start with:
.idea
__snapshots__
.gitignore
yarn.lock
.prettierignore
.eslintignore
dist
If you are using VSCode you should add .vscode in there as well, also if you are using npm as instead of yarn you should add your package-lock.json file too.
I also add settings to my ide so eslint and prettier run on format and save. I highly recommend doing this.
Jest
Jest is used to test our React components.
Complete and easy to set-up JavaScript testing solution. Works out of the box for any React project.
Fast interactive watch mode runs only test files related to changed files and is optimized to give signal quickly.
Capture snapshots of React trees or other serializable values to simplify testing and to analyze how state changes over time”
Setting up jest and creating a unit test for React components is quite simple. First like always we need to add jest and react-test-renderer to our project:
$ yarn add --dev jest react-test-renderer
$ npm install --dev-save jest react-test-renderer
Next we need to create either a test folder and you can either name you tests folder “__tests__” and jest will assume all files in these folders are test files to run or you can name the test files with .spec.js or .test.js extension. I prefer the .test.js extension. This always you the luxury and having a test file right with you react component file. Makes it simple to see if you component has a test already or needs one. So with that let’s create our first test.
$ touch ./src/App.test.jsx
Then in this file add this code:
import React from 'react';
import renderer from 'react-test-renderer';
import App from './App';
it('renders correctly', () => {
const tree = renderer.create(
<App />
).toJSON();
expect(tree).toMatchSnapshot();
});
Then you can run the test:
$ ./node_modules/.bin/jest
You should receive the following output:
$ jest
PASS src/App.test.js
✓ renders correctly (11ms)
› 1 snapshot written.
Snapshot Summary
› 1 snapshot written in 1 test suite.
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 added, 1 total
Time: 1.491s
Ran all test suites.
Done in 2.38s.
A __snapshots__ folder was created and the snapshot file was placed in there. These should be committed into source so the next time someone makes a change they can run jest against this snapshot and be able to compare the difference via jest. There is so much more you can do with jest and then even more you can do with jest and enzyme. Enzyme is a testing suite create by Airbnb that gives you the ability to interact and test these interactions with your components as if you are a user all without running your code in a browser. Very powerful way to automate tests.
That’s a basic intro to Jest!
Scripts in our package.json file
Next let’s setup some scripts to make starting our dev-server quicker and easier. Also we will add a couple scripts to build a test version and a production version. In the package.json file we need to add a script section:
"scripts": {
"start": "webpack-dev-server",
"build": "webpack --mode production",
"build-develop": "webpack --mode development",
"clean": "npx rimraf dist",
"format": "prettier --check \"**/*.*\"",
"lint": "eslint . --ext .jsx --ext .js src webpack.config.*",
"test": "jest",
"pre-push": "yarn lint && yarn format && yarn test && yarn clean && yarn build"
},
What are these for:
- “start” – starting your dev server for testing locally
- “build” – output the artifacts required for a production release – minified code
- “build-develop” – development version of the build is to test the build and even test your artifacts before generating the production artifacts.
- “clean” – deletes the dist directory, used prior to building so nothing gets left from previous build
- “format” – runs prettier to check the formatting of your code
- “lint” – runs eslint to look for issues
- “test” – using jest it will run any tests you have
- “pre-push” – my favorite! I always run this prior to committing and or pushing code to verify all scripts pass without errors. I highly recommend you use this often.
When building the different versions you should notice the output size of the main.js: here is the production build:
$ webpack --mode production
asset main.js 127 KiB [emitted] [minimized] (name: main) 1 related asset
asset index.html 328 bytes [compared for emit] [from: src/index.html] [copied]
And here is the output from the test build:
$ webpack --mode development
asset main.js 1010 KiB [emitted] (name: main)
asset index.html 328 bytes [compared for emit] [from: src/index.html] [copied]
You can also chose to have a separate webpack.config.js file for a production build to customize even more.
Add that’s it! You made it – you can see the final source I have at https://github.com/nkas17/react-starter