Maintaining a fork of create-react-app as an alternative to ejecting
Step-by-step example and a working repo
Sometimes you really need an X feature which is not supported. Sometimes it could be turned on with a ridiculously small modification, like setting just one configuration flag from false to true. People open an issue or create a pull request, but get officially rejected:
“I don’t think we want to support this. I would actually like to turn this feature off. … I would accept a PR that forbids extra features if possible.”. © Dan Abramov
No doubt, such a unified tool must conform with very strict standards. You either accept and steer your workflow, or search for other options.
Solution #1: eject
One possible solution is the official and documented one: to eject. It means you get current configs and may tweak them as you like, but you can never return to the regular work flow to have any updates.
Note: this is a one-way operation. Once you eject, you can’t go back! … At this point you’re on your own. © Docs.
Example medium article trying to address the issue:
How to Use CSS Modules with Create React App
Short answer: you can’t. You gotta ⏏ © Ned Schwartz
Solution #2: fork
There’s one still not documented option: creating a custom fork of
create-react-app. You can basically fork it, alter any configuration and merge any upcoming changes from the upstream, even automatically! But it took me some time to wrap my head around, and I’m going to share that knowledge with you, providing a step-by-step example.
How everything works
create-react-app is a multi-package repository, powered by Lerna.
Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm. © Docs.
create-react-app is just a shell storing all its packages in a
/packages folder. After you install it, it runs a
postinstall command from the main
package.json, which in turn runs Lerna’s bootstrap script, which does some magic: basically moves or symlinks nested packages into your main
node_modules folder allowing to
import them as usual.
The only package you need to bother about is located in
/packages/react-scripts. It exposes all the configuration and scripts your own project (if it was generated by
create-react-app), uses to start, build, etc. Have a look at
scripts section of your project’s
react-scripts is the only dependency left in your
create-react-app have initialised. So, you’ve understood it right: we need to create our own,
No time to read, just give me any solution!
Features: decorators, babel-preset-stage-0, LESS, SASS, CSS modules. The features are optional and can be turned on/off individually. © Docs.
Even more flexibility, example repo
Unfortunately, I wasn’t satisfied enough with the latter module. I needed a feature which was implemented in newer version of original
create-react-app, than the one was merged in
custom-react-scripts. And at the same time I needed to use custom PostCSS configuration instead of LESS/SASS, so a pull request wouldn’t help me either. So I decided to create my own fork (a scoped package to not pollute NPM’s global namespace).
Just replace the original package with the tweaked one:
yarn remove react-scripts
yarn add --dev @uqee/react-scripts
and you’re good to go, no more changes! It enables: CSS modules,
/src folder as an import source, decorators, class properties and some PostCSS plugins.
Your own configs, step-by-step
Finally, time to create your own build! You need a github account (
ghname) and an NPM account (
- [optionally] Create an account on backstroke and link the above pair of repos to auto sync master branches.
- Clone your new repository and fork a new
- Go to the
./packages/react-scripts. From now on consider
react-scriptsas a separated package.
- In its
package.json: change the package name to
@npmname/react-scripts, and also replace all occurrences of
- Make and commit all the changes to configuration files you want, e.g.
- Staying in the
npm publish --access public, this will create a scoped package named
- When updates from the upstream are pulled (either automatically or manually), you should rebase your
custom-react-scriptsbranch onto the
masterbranch and publish your custom
@npmname/react-scriptsagain, if its version was also updated.
Congratulations! You have created your own build config, which will receive updates from the official
create-react-app repo! You can now attach it to any project by simply doing
yarn add --dev @npmname/react-scripts.
P. S. For security reasons NPM forbids publishing the same name and version pair even if you have previously done a forced unpublish, so for testing purposes I recommend using Yarn’s ability to install packages from a local folder (until you’re satisfied with the new config and ready to publish). I mean, instead of
yarn add --dev @npmname/react-scripts you can do
yarn add --dev file:path/to/your/custom/react-scripts.