Or how to heavily modify Create React App settings without having to eject.

I love using Create React App as a starting point for my React front-end as I get to concentrate on code and delivering value. Plus, by updating it I get new features without having to spend hours to configure them myself.
That is, until you want do something custom with your app that authors did not intend to. In that case you have two choices, neither of them being great:

  • eject and expose all logic/dependencies behind react-scripts. This transforms projects into monstrosity of build settings and dependencies. Then you have to live with it, update CRA yourself etc because once ejected - there is no going back
  • fork create-react-app and use that as a dependency instead in your project. You are still left with syncing all the later changes and improvements done on the CRA end. But at least your project is not polutted with everything that happens behind the scene

I wanted to include Stylelint into a project to lint CSS. Basic functionality can be achieved quite easily - yarn add stylelint --dev and add npm script to your package.json. Something like this:

  "scripts": {
    "lint:client:css": "stylelint 'src/scss/**/*.scss'",

This is all sweet and dandy, but it has certain limitations:

  • it does not watch for file changes
  • it is not integrated in Webpack so it will not flash a message in your browser and terminal like ESLint does in case there is a linting error

In order to do have that last piece of the integration puzzle, you need stylelint-webpack-plugin. But that requires either of the two options from above, right? Well, there is another option I came across recently!

Meet react-app-rewired

This package sits between your local app configuration and CRA's config and overwrites CRA on the fly with any loader, plugin or setting that can be overwritten. So you get all the benefits of CRA without the limitations of "no config". Pretty cool!

Anyway, back to Stylelint.

Let's install what we need first. Optionally you'd want stylelint-config-standard, depending on what kind of stylelint config you want.

yarn add react-app-rewired stylelint stylelint-webpack-plugin --dev

Then create config-overrides.js in your project root.

// config-overrides.js

const StylelintPlugin = require('stylelint-webpack-plugin')

module.exports = {
  webpack: function (config, env) {
    if (env === 'development') {
        new StylelintPlugin({
            // options here

    return config
  // jest: function(config) {
  //   // customize jest here
  //   return config;
  // },
  // devServer: function(configFunction) {
  //   return function(proxy, host) {
  //     // customize devServer config here
  //     return config;
  //   }
  // }

Now in your package.json, "start": "react-scripts start" becomes "start": "react-app-rewired start".

That's it. react-app-rewired will merge this setting with the settings on the CRA end. Your project remains clean and maintainable.

There are also default rewires that you could use, such as relay, eslint (in case you want a different config), etc.

In and out. Ciao!