DEV Community

Cover image for Power up create-react-app!
James Cote
James Cote

Posted on

Power up create-react-app!

create-react-app (CRA) provides developers with the ability to quickly spin up single-page web applications (SPA) using the React framework without wasting time with configuration or version upgrades. It is a powerful toolkit that has helped make React a dominant player in the web framework space.

There are times however when the out-of-the-box configuration provided by CRA is not enough. Perhaps you want to install a new tool, or you're behind a company firewall and need to use audited dependency versions. In situations like these, CRA provides you with the option to "eject" from the CRA setup. This will allow you to have full control over all dependencies and run scripts. However, this will also prevent you from receiving new upgrades to the React toolchain from CRA. It will also make the React setup much more difficult to manage for newcomers to the framework.

If you want to have more control over your dependencies, but still receive upgrades and support to your React setup from CRA, there are two options available:

  • Forking the react-scripts package from the official CRA repository, which is a core dependency of CRA applications that contains all the other dependencies. By forking this package, you can add your own dependencies in an encapsulated manner, and all projects using the latest version of your fork will get them automatically.
  • Introduced in CRA v3.3.0, a Custom Template can be used to define a set of dependencies and scripts that can be added directly to a React project upon creation. (ie. direct dependency instead of through react-scripts) Templates provide the benefit of adding dependencies to your project transparently and allows you to update them independently of other projects that use the template.

In this post, I will walk through creating both a custom react-scripts fork and a custom CRA template, and I will compare both of the solutions.


Forking react-scripts

To get started with forking react-scripts, perform the following steps:

1. Fork the official create-react-app repository on GitHub.

ℹ️ Note
You can also fork, or simply clone, the packages/react-scripts folder specifically if you like, since that's all we're touching for this tutorial.

2. Clone your newly forked repository to your local machine.

git clone https://github.com/<YOUR GITHUB USERNAME>/create-react-app.git
Enter fullscreen mode Exit fullscreen mode

where <YOUR GITHUB USERNAME> is your GitHub username, assuming you have performed step 1.

3. Checkout the latest release branch of CRA rather than from master branch to ensure stability. At the time of this writing, 3.4.1 is the latest release. [1]

git checkout v3.4.1
Enter fullscreen mode Exit fullscreen mode

4. Now, navigate to the react-scripts package, in packages/react-scripts. Here is where the core CRA dependencies come from. By modifying this package, you will be changing what gets included in your React installation by default.

In my case, I wanted to add jest-junit, which is an extension for Jest that exports test results in JUnit XML format, which can then be accepted by Continuous Integration (CI) tools such as CircleCI to provide readable test results on every build.

I wanted this package to be included with all my current React projects, and every new one I make in the future. Thus, I installed it to the react-scripts package in my fork. This will make it available in all my React apps, so long as it's pointing to my fork of react-scripts instead of the official.

ℹ️ Note
I also recommend making your changes in a new branch within your fork, so that when you pull in changes from upstream (ie. if CRA were to be updated) it's easy to merge in with your custom version.

Once you finish making your changes, you will want to use your fork of react-scripts instead of Facebook's. To do this, you will need to make some changes to its package.json:

{
-  "name": "react-scripts",
+  "name": "<custom>-react-scripts",
  "version": "3.4.1",
-  "description": "Configuration and scripts for Create React App.",
+  "description": "Custom configuration and scripts for Create React App.",
  "repository": {
    "type": "git",
-    "url": "https://github.com/facebook/create-react-app.git",
+    "url": "https://github.com/<YOUR GITHUB USERNAME>/create-react-app.git",
    "directory": "packages/react-scripts"
  },
  "license": "MIT",
Enter fullscreen mode Exit fullscreen mode

Change <custom> to something identifiable to you, and <YOUR GITHUB USERNAME> to your GitHub username.

You can test your custom react-scripts with a new React project by running:

npx create-react-app my-app --scripts-version file:../path/to/your/react-scripts
Enter fullscreen mode Exit fullscreen mode

where ../path/to/your/react-scripts can be either a relative or absolute path to your forked react-scripts.

The --scripts-version argument allows for a custom react-scripts to be installed in place of the official one. A name of an existing custom scripts from npm can be passed in, or a local copy can be passed in using the file: prefix, like we did above.

By making these changes, you will be able to publish it to the npm registry, making it available for your React apps to install as a dependency.

To publish your react-scripts to npm, simply run npm publish and login with your npm credentials when prompted.

ℹ️ Note
Ensure the name of your custom react-scripts package isn't already taken on npm.

Once your fork has been published, you can switch the dependency in your app like this:

 {
   "name": "my-app",
   "version": "0.1.0",
   "private": true,
   "dependencies": {
@@ -8,7 +8,7 @@
     "@testing-library/user-event": "^7.1.2",
     "react": "^16.13.1",
     "react-dom": "^16.13.1",
-    "react-scripts": "3.4.3"
+    "<custom>-react-scripts": "3.4.1"
   },
   "scripts": {
     "start": "react-scripts start",
Enter fullscreen mode Exit fullscreen mode

<custom> is the identifiable name you gave to your forked react-scripts from the previous step.

You can also run yarn remove react-scripts then yarn add <custom>-react-scripts to install your fork.

Since the CRA team is continuously making new updates to react-scripts, you will need to keep your fork up-to-date as time goes on.

First, ensure your local repository is connected to the CRA team's version by adding an upstream remote, like this:

git remote add upstream https://github.com/facebook/create-react-app.git
Enter fullscreen mode Exit fullscreen mode

Next, fetch upstream by running git fetch upstream

After that, apply changes from upstream to your local copy by running git checkout upstream/vX.X.X, where X.X.X is the newest version released, then switching into your custom branch and merging changes into it. git merge vX.X.X

There may be some conflicts, but should mostly just be simple version conflicts within package.json.

Also, to use your fork of react-scripts with new apps you make in the future, simply run:

npx create-react-app --scripts-version <custom>-react-scripts my-app
Enter fullscreen mode Exit fullscreen mode

There is one slight caveat with this setup you will need to address manually if you also use a TypeScript template, see [2].


Custom Template

The CRA team also added a Custom Templates feature starting in v3.3.0, where you can simply have a template file containing your dependencies and scripts, and it'll add them to your project upon creation. This is an alternative to creating a custom fork of react-scripts, and it's useful when you only have a handful of dependencies and prefer to update them on a per-project basis.

There are many custom templates already published on the npm registry that you can plug-and-play, such as this heavily customized Redux template, a Tailwind CSS template, and a template containing Storybook.

If you'd like to create your own template with your own set of dependencies and scripts, perform the following steps:

1. Go to the official create-react-app repository and navigate to packages directory.

2. Copy and paste one of the default templates as a base for your template. As of this writing, there are two official templates, cra-template, which is the default, and cra-template-typescript, which is the default TypeScript template.

3. In package.json, add a new property called main and point it to template.json. At the time of this writing, this property is not present in the official templates and new projects will fail to be built if this property is not present in your template.

From the official webpage for Custom Templates, this is the directory structure for a template: [3]

cra-template-[template-name]/
  README.md (for npm)
  template.json
  package.json
  template/
    README.md (for projects created from this template)
    gitignore
    public/
      index.html
    src/
      index.js (or index.tsx)
Enter fullscreen mode Exit fullscreen mode

The important bits:

  • template.json contains the dependencies, scripts, and other entries that will be copied over into the new React project's package.json file upon creation. They must be populated under a "package" field in this JSON file.
  • template/ directory contains files that will be copied over into the new project upon creation. gitignore will be renamed to .gitignore.

Update template.json with the dependencies you want to add to your project, add any files you will need to template/ directory, and update README.md and package.json with information about your template.

⚠️ Important
All custom templates must start with cra-template- so that CRA knows it's a custom template. Ensure the name of your template within package.json follows this convention.

Once all that's done, you can test your template by running:

npx create-react-app my-app --template file:../path/to/your/template/cra-template-[template-name]
Enter fullscreen mode Exit fullscreen mode

where ../path/to/your/template/cra-template-[template-name] can be either a relative or absolute path to your CRA template project.

Now you can publish the template to the npm registry, making it available for new CRA apps to use as a template.

To publish your template to npm, simply run npm publish and login with your npm credentials when prompted.

ℹ️ Note
Ensure the name of your custom template package isn't already taken on npm.

You can create new React projects using your template by running:

npx create-react-app my-app --template cra-template-[YOUR TEMPLATE]
Enter fullscreen mode Exit fullscreen mode

Comparison

In this section, I will compare each of these two solutions. You may want to use one or the other depending on your situation, and you can also use both of them together!

Forking react-scripts

👍 Benefits

  • Allows you to update dependencies and scripts for your projects in one go
  • Less dependency overhead in your projects' package.json
  • Useful for managing dependencies if behind company firewall and/or using a corporate npm registry

👎 Downsides

  • Not well suited for React projects that would need only a subset of the dependencies updated while keeping old versions of other dependencies (would need to start overriding dependency versions in package.json at this point)

Creating templates

👍 Benefits

  • Much simpler to use - simply specify the dependencies and scripts you need in the template.json file
  • Inserts dependencies directly into your app upon creation, sidestepping the need to fork react-scripts if you want to manage the dependencies on a per-project basis
  • Makes your dependencies visible, unlike the forked react-scripts, which encapsulates them (depending on the situation, this may be a pro or a con)

👎 Downsides

  • Will need to update dependencies and scripts for every new project you make manually

And that's it - You now have the ability to customize your CRA installation however you see fit! Let me know in the comments if there's something I missed, and heart and save it if you found this useful.


[1] The latest version of this writing is actually v3.4.3, but there were no commits between v3.4.1 and this version. The update was simply to bump up dependencies of some internal tools to satisfy audit requirements. You can learn more about this here. Because this minor change does not affect CRA itself, the maintainers felt there was no need to make a release entry for it on GitHub. Thus, v3.4.1 remains as the latest version for the purposes of this article.

[2] When creating a new project using a TypeScript template, there is a special file called react-app-env.d.ts that allows special objects such as images and CSS modules to be detected by TypeScript. It does this by referencing a file in react-scripts that provides these type definitions. This reference to react-scripts does not change even if a custom react-scripts is substituted in place of the official react-scripts. At the moment, a workaround is to change the reference in react-app-env.d.ts to the name of your custom react-scripts. See this issue for more information.

[3] https://create-react-app.dev/docs/custom-templates/#building-a-template

Top comments (0)