Custom templates with Create React App
Tags: react, javascript, webdev, tutorial
Published: 2020-07-24 08:01:32

_<span>Cover photo by <a href="https://unsplash.com/@grohsfabian?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Fabian Grohs</a> on <a href="https://unsplash.com/s/photos/developer?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>_



Templates are great. They provide a useful starting point for projects and can cut out common setup and configuration work. We can also enhance them with tools that promote good habits and processes by default, making it easier to make the "right" decisions. This saves time and mental bandwidth - with these tasks out of the way there's more time to concentrate on actually writing code.

Templates can be extended and refined over time. By building on what we already have we can start further and further from "zero". This, to me, sums up the process of technical progress - by packaging up something useful and making it easy to replicate we can direct our efforts to the "next" problem.

So yeah, if you haven't guessed already I'm a big fan of templates. This post will walk through the process of creating a custom template for [Create React App (CRA)](https://github.com/facebook/create-react-app), using the official default template as a base.

## Planning out the template

Templates of any kind should have a clear purpose. This helps to avoid a situation where we end up catering for too many possibilities and face difficult decisions on what should and shouldn't be included. We're trying to make things easier for ourselves after all!

We're going to look at a more general baseline use case, so it will be lightweight with some utilities that would be useful for any project. If you had a more specific use case it would make sense to create a more specialised template with features and utilities relevant to the problem area.

What we'll do:

- use the official CRA default template as a starting point
- remove some files
- update some files
- add some common utilities (Prettier, Source Map Explorer, testing coverage reporting with Jest)
- test it out by generating a new project

## Anatomy of a CRA template

A CRA template has two key elements:

`/template`

- can contain anything you want and will form the basis of your newly created project
- must contain some common files and folders as a bare minimum for `react-scripts` to work as expected

`template.json`

- the config file for your template
- currently supports a single key, `"package"`, under which you can nest info that will be merged into the newly created project's `package.json` file
- any dependencies and scripts that you specify will be merged in with the default values in `react-scripts` (i.e. dependencies like React itself, and scripts that set your app up for development/build)
- other values will just be directly copied over, replacing any defaults if they already exist

The template needs to have the following structure and files as a bare minimum, as laid out in the [CRA docs](https://create-react-app.dev/docs/custom-templates/):

```
README.md
template.json
package.json
template/
  README.md
  gitignore (this will be renamed to .gitignore during the init process)
  public/
    index.html
  src/
    index.js
```

## Using the default template as a starting point

To ensure we're meeting the minimum criteria above, we can use the [official default template](https://github.com/facebook/create-react-app/tree/master/packages/cra-template) of CRA as a foundation for our own template.

In your terminal, navigate to the directory where this template should live and run the following commands:

```bash
# Clone the repo
git clone https://github.com/facebook/create-react-app.git

# Copy the template into the current directory
cp -r create-react-app/packages/cra-template .

# Clean up after ourselves
rm -rf create-react-app
```

## Cleaning up

Let's get rid of some unnecessary files and edit a few of the existing ones so that we're left with only what we need.

1. Delete `App.css` and `logo.svg` from the `/template` directory

2. Update `App.js`:

```jsx
import React from 'react';

const App = () => <h1>Hello, world</h1>;

export default App;
```

3\. Update `App.test.js` to reflect the change to `<App />`:

```jsx
test('renders test heading', () => {
  render(<App />);
  const headingElement = screen.getByText(/hello, world/i);
  expect(headingElement).toBeInTheDocument();
});
```

4\. The last step here is to add the following to your `package.json`:

```json
{
  ...
  "main": "template.json"
}
```

N.B. this is a necessary step until CRA v4 is released. [A fix has already been made](https://github.com/facebook/create-react-app/pull/8734).

You may also want to update the name and info in `README.md` and `package.json`, and the name of the directory we're working in, but I'll leave that up to you.

## Adding some common utilities

There are a couple of things that I always set up on new projects - this template is the perfect place to put these things.

We're going to add:

- [Prettier](https://prettier.io/) to ensure our code stays nicely formatted
- [Source Map Explorer](https://github.com/danvk/source-map-explorer) so we can keep an eye on the state of the app's bundle
- an npm script for code coverage reporting using [Jest](https://jestjs.io/)

### A note on specifying dependencies

We'll have to add a few dependencies in order to complete the next steps. We're not actually going to install them, we just need to list what we need in `template.json` so that CRA knows what to install when we use this template to create a new project. The process we'll use to do this is as follows:

- go to the [npm site](https://www.npmjs.com/)
- search for the package to add
- copy the version number, and then add the package and version number to `template.json` with `^` as a prefix, for example:

```json
{
  "package": {
    "dependencies": {
      "prettier": "^2.0.5"
    }
  }
}
```

The `^` symbol is a "caret", and allows us to give npm permission to install newer minor or patch versions of the package - it's like saying "feel free to install a newer version if there is one, but no breaking changes please". It does rely on the package authors following [semantic versioning](https://semver.org/) but most major open source projects do so we should be fine, just be aware of this. This will mean that we can go for a longer period of time without needing to update the template's dependencies (although this is something to revisit periodically so that we're benefitting from the latest releases). If you want a specific version of a package then you can leave this off.

N.B. while you'd normally add these as `devDependencies` the current system for templates in CRA only supports listing them as regular `dependencies`. While this [wasn't considered a problem in the past](https://github.com/facebook/create-react-app/issues/6180), it now looks like this will be [supported in a future release](https://github.com/facebook/create-react-app/pull/8838).

### Adding Prettier

We're going to add Prettier and run it with a pre-commit hook using [Husky](https://github.com/typicode/husky).

1. Add `prettier`, `pretty-quick`, and `husky` to `dependencies` in `template.json`

2. Create a file called `prettier.config.js` in `/template` and add config options:

```js
// Some of these are defaults, but let's be explicit for other humans
module.exports = {
  tabWidth: 2,
  semi: true,
  singleQuote: true,
  bracketSpacing: true,
  printWidth: 80,
};
```

3\. Create a file called `.prettierignore` in `/template` (this can stay blank for now)

4\. Create a file called `husky.config.js` in `/template` and add the following:

```js
module.exports = {
  hooks: {
    'pre-commit': 'npm run pre-commit',
  },
};
```

5\. In `template.json` add a `"scripts"` object to `"package"` with the following script:

```json
{
  "package": {
    ...
    "scripts": {
      "pre-commit": "pretty-quick --staged"
    }
  }
}
```

N.B. you might also want to add Prettier to the actual CRA template we're creating to ensure your template code is formatted as well.

### Adding Source Map Explorer

Being able to see what actually goes into your bundles is useful when trying to reduce bundle size and save your user from downloading unnecessary bytes. To get some visibility on this we're going to use Source Map Explorer.

1. Add `source-map-explorer` to `dependencies` in `template.json`

2. In `template.json` add the following to the `"scripts"` object:

```json
{
  "package": {
    ...
    "scripts": {
      ...
      "analyze": "source-map-explorer 'build/static/js/*.js'"
    }
  }
}
```

That's it! This command will only look at built files. If you want, you can prefix the command above `npm run build &&` so that you don't have to build as a separate step before running this.

### Adding code coverage reporting with Jest

This is also quite straightforward. Jest has its own built-in coverage reporting functionality, and the package itself already comes with any app created using CRA so we don't even need to add any dependencies.

In `template.json` add the following to the `"scripts"` object:

```json
{
  "package": {
    ...
    "scripts": {
      ...
      "coverage": "npm test -- --coverage --watchAll=false"
    }
  }
}
```

## Putting it all together

Now that we've added a bunch of useful stuff we need to make sure it works as expected. CRA allows to you specify the path to a custom template when creating a new app. For convenience you might want to add something like this to your `.bash_profile`:

```bash
# Maybe with a catchier name...
alias create-react-app-custom="npx create-react-app --template=file:/path/to/template"
```

Hint: a quick way to make sure you get the correct path is to type use `pwd` in your terminal and just copy/paste the result into the alias above.

Now you can just run the following every time you want to use this template:

```bash
create-react-app-custom <name> [options]
```

N.B. you'll need to open up a new terminal window for this change to your `.bash_profile` to take effect.

In a new terminal window, try running the following command and looking at the output:

```bash
create-react-app-custom custom-app
```

The contents of the generated project should look familiar. This is the contents of `/template`, and if you look at the `package.json` for this project you will see that the dependencies and scripts we specified in `template.json` have been included.

To test that our additions have been included correctly you can do the following:

- **Prettier**: mess up some formatting and commit the change to see the pre-commit handler tidy up for you (e.g. remove the semi-colons in `App.js`)
- **Source Map Explorer**: run `npm run build && npm run analyze` to see a report in your browser
- **Test coverage**: run `npm run coverage` to see a very basic coverage report based on the default `<App>` test we left in
  - when this command runs it also generates a new folder, `/coverage`
  - you can open `./coverage/lcov-report/index.html` in your browser for a more interactive experience
  - N.B. you may receive some errors in your terminal related to [this issue](https://github.com/facebook/create-react-app/issues/8689) but the `/coverage` folder should still be created

And that's it for the basic template! When using this template to create new projects we no longer have to delete stock files that we don't need, and a few useful utilities are set up out of the box.

## Next steps

If you weren't already sold, I hope that over the course of reading this you've realised that templates can be incredibly useful. We've added some basic quality-of-life tools for new projects that use this template but there are a tonne of other things you could add depending on your use case - to name a few:

- set up your preferred styling solution with a basic theme, default global styles ([box-sizing anyone?](https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/))
- `react-axe` and a11y plugins
- change default icons and HTML in `/public`
- i18n config
- preferred folder structure
- add more npm scripts that match your common workflows
- common packages you always use, including your own utils

## Wrapping up

We've looked at making our own custom template for Create React App by using the official starter as a base. This was as simple as removing some unwanted code and files, specifying some packages and scripts to include in new projects, and testing it out.

Finally, you should remember that while templates can help us to save time and cut out repetitive tasks it's important to think about your use case and what to include. If you regularly end up in a situation where you're editing or deleting the files and utilities generated by your template, you've probably gone a bit overboard.

---

**This post was originally published on [tomvalorsa.com](https://tomvalorsa.com/blog/custom-templates-with-create-react-app/)**