How To Make A Template For CRA ⚛️
Tags: react
Published: 2020-04-14 06:33:02

Recently, I've had much more free time than I used to. The spread of the COVID epidemic in the world (in my case, in France) has put forward the remote work (more than usual) ; and who says "_working remotely_" says more time for oneself. Indeed, by removing the daily journey constraint to go to your workplace, you can save a significant time to enjoy your family, play videogames (and/or read books), do sports (just enough) and of course... coding!

I've been evolving in the _frontend_ development world since several years now, with the help of the essential React ~~framework~~ library. As often, to instantiate a viable project quickly (without worrying about the Webpack configuration), I use the `create-react-app` command-line tool. Unfortunately, every time, I need something extra, that may be: a dependency, an unsupported file format (by default), or a project architecture for scalable applications. So I decided to create my own scaffold project for my future developments. In this post, I suggest you follow, step by step, the development of what is commonly called a "_boilerplate_" for the React ~~framework~~ library.

_**NB**: Before talking about the main topic, you should know that I spent a lot of time on Figma in order to design some SVGs essential to my development base (in particular, I chose the **[Monument Valley](https://www.monumentvalleygame.com/)** game as a visuel theme). I might talk about it more in a spin-off post..._

## 1st Step: Project Initialization

The easiest way to create a new React project is to use the command-line tool:

```
npx create-react-app my-awesome-project
```

One more time, `create-react-app` makes things much easier. It generates a React project tree including the main dependencies (`react` and `react-dom`), while mystifying some technical dependencies (Webpack, Jest, ESLint, etc...) as well as their configuration file. When we choose this way to generate code, the entire configuration of our application is based on the `react-scripts` dependency. However, its operation allows the developer to easily overload some libraries, this is the case for ESLint.

Latest versions of `react-scripts` go even further, since this library is now pre-configured to accept additional dependencies without more configuration. This is the case for the Sass language support, or even for the implementation of the typed JavaScript superset: TypeScript. For my part, I chose to use the `.scss` format in my scaffold project, simply by adding the appropriate package:

```
npm install node-sass
```

_**NB**: If you want to see what is hidden behind the `react-scripts` dependency, I invite you to eject the project via the command below. Please note, this action is irrevocable..._

```
npm run eject
```

## 2nd Step: Adding Dependencies

I've already started adding dependencies with `node-sass`. Great! With that, I'll already be able to edit `.scss` and import it directly into my `.js` and `.jsx` files.

Then, I wanted to set up "_linting_" rules, to make my code more cleaner (even if it's a subjective concept) but above all for it to be properly formatted. So I added everything about the Prettier dependency:

```
npm install prettier eslint-config-prettier eslint-plugin-prettier
```

Knowing that `react-scripts` already includes ESLint, I didn't need to add this dependency. However, I had to edit the `package.json` of my project:
- To add the `lint` script
- To complete the ESLint configuration

```json
"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "lint": "eslint --ext .js,.jsx src"
},
"eslintConfig": {
  "extends": ["react-app", "prettier", "prettier/react"],
  "plugins": ["prettier"]
}
```

For the formatter, I didn't stop there. Since I decided to have a precise configuration for formatting my code, I had to create a Prettier configuration file (`prettier.config.js`) with all of these options:


```js
module.exports = {
  printWidth: 120,
  singleQuote: true,
  trailingComma: "none",
  jsxBracketSameLine: true,
  arrowParens: "avoid"
};
```

Finally, I added this same configuration at the ESLint level:

```json
"eslintConfig": {
  "extends": ["react-app", "prettier", "prettier/react"],
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": [
      "warn",
      {
        "printWidth": 120,
        "singleQuote": true,
        "trailingComma": "none",
        "jsxBracketSameLine": true,
        "arrowParens": "avoid"
      }
    ]
  }
}
```

So, with the right plugin in VSCode (**[Prettier - Code Formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode/)**), Prettier formats the code when saving files, and ESLint controls the formatting. Q.E.D!

_**NB**: You can also externalize ESLint parameters, but I didn't find a way to delete them (or prevent their writing) in the `package.json` when using the template, to keep the `.eslintrc.js` file only... Therefore, I advise you to keep them in the `package.json` at the risk of having two separate ESLint configurations._

To finish with dependencies required for my scaffold project; latest addition: `prop-types`! You might already know it, but it's essential to control the typing of component properties during your developments (especially for large collaborative projects). React has chosen to extract this package from its core, but I continue to use it as being a good practice!

```
npm install prop-types
```

_**NB**: About unit tests, I chose to keep dependencies related to `@testing-library` in my `package.json`. You should know that when using the template, these packages disappear, only `react`, `react-dom` and `react-scripts` persist. So, you might keep these test libraries for the future._

### Bonus

Once the _linting_ process implemented, I said to myself that it would be interesting to automate it, to not have to execute the `npm run lint` command, only when really needed. This is how I came across two new finds:

```
npm install husky lint-staged
```

The combination of these two dependencies allows me to play the task of formatting and checking the syntax of my code at each commit. To do this, a small configuration is required into the `package.json` file:

```json
"husky": {
  "hooks": {
    "pre-commit": "lint-staged"
  }
},
"lint-staged": {
  "*.{js,jsx}": [
    "prettier --write",
    "eslint --fix"
  ]
}
```

## 3rd Step: Code Organization

I took advantage of my scaffold project implementation to review the code organization. Here is the structure generated by `create-react-app`:

```
+-- public/                    # 'index.html' Is Here
+-- src/
  +-- App.css
  +-- App.js
  +-- App.test.js
  +-- index.css
  +-- index.js
  +-- logo.svg
  +-- serviceWorker.js
  +-- setupTests.js
+-- .gitignore
+-- package.json
```

I really appreciate my project when it's organized by component folders. As the same, I consider a component file to be suffixed by the `.jsx` extension and not `.js` (even if this assertion is also valid), visually I find my components more quickly. Here is the structure that I propose to you:

```
+-- public/                    # 'index.html' Is Here
+-- src/
  +-- components/
  +-- __tests__
    +-- App.test.js
    +-- Content.test.js
  +-- vectors/                 # SVGs Are Here
  +-- App.jsx
  +-- Content.jsx
  +-- index.js
  +-- index.scss
  +-- setupTests.js
+-- .gitignore
+-- package.json
+-- prettier.config.js
```

Note the deletion of the `serviceWorker.js` file. Indeed, in my case, I didn't need to implement PWA, so I preferred to remove this part to lighten the code. In addition, we quickly notice the appearance of the `__tests__` folder which allow me to group my unit tests (from the same directory), in a single place.

I'm aware that my organization may seem a little bit too directive, and thus allow less freedom when developing applications, but it's just a proposal. After all, the base provided by `create-react-app` is quite "_flat_" to make it what we want!

## 4th Step: Template Assembly

Once your React project is functional and it satisfies you (personally, I changed the whole graphic part), you can start building the template. For that, some rules are essential:
- The template must be named according to a **[convention](https://create-react-app.dev/docs/custom-templates/)** (for example, `cra-template-my-awesome-project`)
- The template must respect a specific architecture

```
+-- cra-template-my-awesome-project/
  +-- template/                # Previous Project Goes Here
    +-- public/
    +-- src/
    +-- gitignore
    +-- README.md
  +-- package.json
  +-- README.md
  +-- template.json
```

The structure above describes the template organization. Just tell yourself that your previous project is nothing more than the `template` directory (it must keep this label, this is essential).

_**NB**: As the same, the `.gitignore` file must be renamed to `gitignore`, otherwise the template will not be able to work._

According to the code organization that I presented to you previously, the final structure should look something like this:

```
+-- cra-template-my-awesome-project/
  +-- template/
    +-- public/                # 'index.html' Is Here
    +-- src/
      +-- components/
        +-- __tests__
          +-- App.test.js
          +-- Content.test.js
        +-- vectors/           # SVGs Are Here
        +-- App.jsx
        +-- Content.jsx
      +-- gitignore
      +-- index.js
      +-- index.scss
      +-- prettier.config.js
      +-- setupTests.js
  +-- package.json
  +-- README.md
  +-- template.json
```

Once these changes have been made, you'll have to move the dependencies, configurations and scripts (except those related to `react-scripts`) present in your `package.json` to the `template.json` file as follows:

```json
{
  "package": {
    "dependencies": {
      "@testing-library/jest-dom": "~4.2.0",
      "@testing-library/react": "~9.3.0",
      "eslint-config-prettier": "~6.10.0",
      "eslint-plugin-prettier": "~3.1.0",
      "husky": "~4.2.0",
      "lint-staged": "~10.1.0",
      "node-sass": "~4.13.0",
      "prettier": "~2.0.0",
      "prop-types": "~15.7.0"
    },
    "scripts": {
      "lint": "eslint --ext .js,.jsx src"
    },
    "eslintConfig": {
      "extends": ["react-app", "prettier", "prettier/react"],
      "plugins": ["prettier"],
      "rules": {
        "prettier/prettier": [
          "warn",
          {
            "printWidth": 120,
            "singleQuote": true,
            "trailingComma": "none",
            "jsxBracketSameLine": true,
            "arrowParens": "avoid"
          }
        ]
      }
    },
    "husky": {
      "hooks": {
        "pre-commit": "lint-staged"
      }
    },
    "lint-staged": {
      "*.{js,jsx}": [
        "prettier --write",
        "eslint --fix"
      ]
    }
  }
}
```

Don't forget to complete the `package.json` for your future template / library for `create-react-app`, as well as the two `README.md` files (one for your NPM dependency, the other for the project generated by this template). It now remains to test your template locally. To do this, simply pointing the command-line tool usage to your `cra-template-my-awesome-project` directory, and see the result:

```
npx create-react-app my-awesome-project --template file:./path/to/cra-template-my-awesome-project
cd my-awesome-project
npm run start
```

Here we are! If you're fully satisfied with the final result, all you have to do is publish your template on NPM. For my part, you will find my template embedding all the libraries presented above, and responding to the visual below, directly on **[NPM](https://www.npmjs.com/package/cra-template-monument-valley/)** (the source code is available on **[GitLab](https://gitlab.com/DmnChzl/CRA-Template-Monument-Valley/)**).

![Before / After](https://dev-to-uploads.s3.amazonaws.com/i/dzfv70lq2aqva15tic9q.png)

I had a lot of fun doing this project (besides more on the _design_ part than on the code itself). Possibilities offered by the command-line tool are more and more extensive (note that custom templates are only available since version 3.3.0 of the `react-scripts` dependency). I plan to (re)do other _boilerplates_ for professional use cases this time. For example, a scaffold project with some of pre-instantiated custom hooks, or another one _boilerplate_ which implements a Redux base for scalable applications.

Given the orientation that React has taken in last years (especially with the hooks birth, or even with the `create-react-app` flexibility), the JavaScript library for building interfaces turns out to be my first choice when I have to create a new web application; it may also be my love for functional programming that makes me think that... Anyway, I hope one day to see some of these concepts embedded in other component-oriented frameworks (maybe Vue, maybe Svelte). Wait and see...