Create React App comes with a great config out of the box, and it has the "eject" feature for when you want to take the config into your own hands.
But what if you just want to add a couple little tweaks to the Webpack config without having to keep the entire config up to date by yourself?
We'll go over how to do that here.
Warning!
First, a word of warning: if you are unfamiliar with how Webpack works, or are not comfortable maintaining the (small amount of) hacky code that we'll produce here, I recommend skipping this one. This is rather advanced magic.
As Create React App (specifically its react-scripts
package) changes, it is HIGHLY LIKELY that the code below will eventually need some repairs. If their Webpack config changes structure, or it's exported differently, or any number of other things happens, this code will break, and it will be up to you to figure out how it works and fix it. So, again: if you're not comfortable with that idea, don't do this.
Hacking Create React App
Ok, with that scary disclaimer out of the way, let's figure out how to hack Create React App. If you want to skip straight to the Example Project, that's fine too.
The underpinnings of Create React App are housed in the "react-scripts
" package, which you'll see listed under "devDependencies
" in package.json.
We're going to use rewire to monkey-patch react-scripts and allow us to customize the Webpack config before it executes.
This file here is the biggest piece of that puzzle. I suggest making a directory called "scripts" inside your CRA project and putting this code in scripts/customized-config.js. You can name it whatever you like, though (we'll need the name again later).
scripts/customized-config.js
var rewire = require('rewire');
var proxyquire = require('proxyquire');
switch(process.argv[2]) {
case 'start':
rewireModule('react-scripts/scripts/start.js', loadCustomizer('../config-overrides.dev'));
break;
case 'build':
rewireModule('react-scripts/scripts/build.js', loadCustomizer('../config-overrides.prod'));
break;
case 'test':
let customizer = loadCustomizer('../config-overrides.testing');
proxyquire('react-scripts/scripts/test.js', {
'../utils/createJestConfig': (...args) => {
var createJestConfig = require('react-scripts/utils/createJestConfig');
return customizer(createJestConfig(...args));
}
});
break;
default:
console.log('customized-config only supports "start", "build", and "test" options.');
process.exit(-1);
}
function loadCustomizer(module) {
try {
return require(module);
} catch(e) {
if(e.code !== "MODULE_NOT_FOUND") {
throw e;
}
}
return config => config;
}
function rewireModule(modulePath, customizer) {
let defaults = rewire(modulePath);
let config = defaults.__get__('config');
config = customizer(Object.assign({}, config));
defaults.__set__('config', config);
}
To make this work, you'll need to install a few extra packages:
npm install --save-dev rewire proxyquire
You can pretty much read the comments to figure out how it works. The interesting part is the rewireModule
function at the bottom, which uses the rewire
library to modify variables in another file.
Once you've got that in place, you can write the config-overrides files for dev, prod, and test. This part is really up to you - whatever changes you need to make to CRA's Webpack config, go right ahead.
These files should go directly in the root of your CRA folder, and all 3 are optional. If you want to relocate them, just change the path in the "loadCustomizer
" calls above. Just don't put them in "src
".
Here's an example of some dev overrides:
config-overrides.dev.js
<code class="language-js">const path = require('path');
module.exports = function(config) {
config.eslint.useEslintrc = true;
config.module.loaders[0].exclude.push(/\.scss$/);
config.module.loaders.push({
test: /\.scss$/,
loaders: ["style", "css", "sass"]
});
return config;
}
To make this work, you'll need to install the SASS loader:
npm install --save sass-loader node-sass
Finally, to trigger all this new code, you'll need to change package.json
to call this new customized-config
script instead of the default react-scripts
. To do that, replace the "start", "build", and "test" lines with these:
package.json
"scripts": {
"start": "node scripts/customized-config start",
"build": "node scripts/customized-config build",
"test": "node scripts/customized-config test --env=jsdom",
}
Example Project
A CRA-generated project with these mods applied is up on Github here.
Create React App: Customize Webpack Config Without Ejecting was originally published by Dave Ceddia at Dave Ceddia on April 23, 2017.
CodeProject