Skip to content

Commit f1b59cb

Browse files
committed
Make config customizable
1 parent cd5c6d5 commit f1b59cb

File tree

7 files changed

+174
-13
lines changed

7 files changed

+174
-13
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ npm-debug.log*
1111
yarn-debug.log*
1212
yarn-error.log*
1313
/.changelog
14+
yarn.lock
15+
*.orig

packages/react-scripts/README.md

Lines changed: 144 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,148 @@
11
# react-scripts
22

33
This package includes scripts and configuration used by [Create React App](https://github.com/facebookincubator/create-react-app).<br>
4-
Please refer to its documentation:
54

6-
* [Getting Started](https://github.com/facebookincubator/create-react-app/blob/master/README.md#getting-started) – How to create a new app.
7-
* [User Guide](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md) – How to develop apps bootstrapped with Create React App.
5+
To customize, create `config/webpack.custom.{dev|prod}.js` and export a function. The function will be given the react-scripts webpack configuration as the only parameters and
6+
should return a webpack configuration object (modified as you want).
7+
8+
An example custom dev config file:
9+
```
10+
const log = require('tmpljs/log')
11+
const autoprefixer = require('autoprefixer')
12+
const {addFileLoaderExclude, addBabelPreset, addBabelPlugins, addRule} = require('./config-helpers')
13+
14+
module.exports = (c) => {
15+
try {
16+
addFileLoaderExclude(c, /\.(scss|sass)/)
17+
addBabelPreset(c, 'babel-preset-stage-0')
18+
addBabelPlugins(c, 'transform-decorators-legacy')
19+
addRule(c, {
20+
test: /(\.scss|\.sass)$/,
21+
use: [
22+
{
23+
loader: "style-loader"
24+
},
25+
{
26+
loader: "css-loader",
27+
options: {
28+
modules: true,
29+
localIdentName: '[name]__[local]___[hash:base64:5]'
30+
}
31+
},
32+
{
33+
loader: "sass-loader"
34+
},
35+
{
36+
loader: require.resolve('postcss-loader'),
37+
options: {
38+
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
39+
syntax: 'postcss-scss',
40+
plugins: () => [
41+
require('postcss-flexbugs-fixes'),
42+
autoprefixer({
43+
browsers: [
44+
'>1%',
45+
'last 4 versions',
46+
'Firefox ESR',
47+
'not ie < 9', // React doesn't support IE8 anyway
48+
],
49+
flexbox: 'no-2009',
50+
}),
51+
]
52+
},
53+
},
54+
]
55+
}
56+
)
57+
} catch (e) {
58+
console.error(e)
59+
process.exit(1)
60+
}
61+
return c
62+
63+
}
64+
```
65+
./config-helpers
66+
```
67+
const merge = require('lodash/merge')
68+
69+
const getRule = (c, predicate) => {
70+
const {rules} = c.module
71+
const rule = rules.filter(r => predicate(r))
72+
if (rule.length != 1) {
73+
return
74+
} else {
75+
return rule[0]
76+
}
77+
}
78+
79+
const loaderMatch = (loader) => {
80+
return r => r.loader === require.resolve(loader)
81+
}
82+
83+
const getLoaderRule = (c, loader) => {
84+
return getRule(c, loaderMatch(loader))
85+
}
86+
87+
const getFileLoaderRule = (c) => {
88+
return getLoaderRule(c, 'file-loader')
89+
}
90+
91+
const addFileLoaderExclude = (c, ...exclude) => {
92+
const rule = getFileLoaderRule(c)
93+
if (rule) {
94+
if (rule.exclude) {
95+
rule.exclude = [...rule.exclude, ...exclude]
96+
} else {
97+
rule.exclude = exclude
98+
}
99+
} else {
100+
throw new Error('Unable to add excludes, file loader rule not found')
101+
}
102+
}
103+
104+
105+
const getBabelLoaderRule = (c) => {
106+
return getLoaderRule(c, 'babel-loader')
107+
}
108+
109+
const addBabelPreset = (c, ...preset) => {
110+
const rule = getBabelLoaderRule(c)
111+
if (rule) {
112+
const newRule = merge({options: {presets: []}}, rule)
113+
newRule.options.presets = [...newRule.options.presets, ...preset]
114+
Object.assign(rule, newRule)
115+
} else {
116+
throw new Error('Unable to add Babel Loader presets, rule not found')
117+
}
118+
}
119+
120+
const addBabelPlugins = (c, ...plugins) => {
121+
const rule = getBabelLoaderRule(c)
122+
if (rule) {
123+
const newRule = merge({options: {plugins: []}}, rule)
124+
newRule.options.plugins = [...newRule.options.plugins, ...plugins]
125+
Object.assign(rule, newRule)
126+
} else {
127+
throw new Error('Unable to add Babel Loader plugins, rule not found')
128+
}
129+
}
130+
131+
const addRule = (c, rule) => {
132+
const {rules} = c.module
133+
rules.push(rule)
134+
}
135+
136+
module.exports = {
137+
getRule,
138+
loaderMatch,
139+
getLoaderRule,
140+
getFileLoaderRule,
141+
addFileLoaderExclude,
142+
getBabelLoaderRule,
143+
addBabelPreset,
144+
addBabelPlugins,
145+
addRule,
146+
}
147+
```
148+
This adds `stage-0`, `@decorators` and `sass` with `css-modules`

packages/react-scripts/config/paths.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ module.exports = {
7777
appIndexJs: resolveApp('src/index.js'),
7878
appPackageJson: resolveApp('package.json'),
7979
appSrc: resolveApp('src'),
80+
appConfig: resolveApp('config'),
8081
yarnLockFile: resolveApp('yarn.lock'),
8182
testsSetup: resolveApp('src/setupTests.js'),
8283
appNodeModules: resolveApp('node_modules'),

packages/react-scripts/config/webpack.config.dev.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
2222
const getClientEnvironment = require('./env');
2323
const paths = require('./paths');
2424

25+
const customConfig = (c) => {
26+
try {
27+
return require(`${paths.appConfig}/webpack.custom.dev.js`)(c);
28+
} catch(e) {
29+
return c
30+
}
31+
}
32+
2533
// Webpack uses `publicPath` to determine where the app is being served from.
2634
// In development, we always serve from the root. This makes config easier.
2735
const publicPath = '/';
@@ -35,7 +43,7 @@ const env = getClientEnvironment(publicUrl);
3543
// This is the development configuration.
3644
// It is focused on developer experience and fast rebuilds.
3745
// The production configuration is different and lives in a separate file.
38-
module.exports = {
46+
module.exports = customConfig({
3947
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
4048
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.
4149
devtool: 'cheap-module-source-map',
@@ -283,4 +291,4 @@ module.exports = {
283291
performance: {
284292
hints: false,
285293
},
286-
};
294+
});

packages/react-scripts/config/webpack.config.prod.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
2323
const paths = require('./paths');
2424
const getClientEnvironment = require('./env');
2525

26+
const customConfig = (c) => {
27+
try {
28+
return require(`${paths.appConfig}/webpack.custom.prod.js`)(c);
29+
} catch(e) {
30+
return c
31+
}
32+
}
33+
2634
// Webpack uses `publicPath` to determine where the app is being served from.
2735
// It requires a trailing slash, or the file assets will get an incorrect path.
2836
const publicPath = paths.servedPath;
@@ -57,7 +65,7 @@ const extractTextPluginOptions = shouldUseRelativeAssetPaths
5765
// This is the production configuration.
5866
// It compiles slowly and is focused on producing a fast and minimal bundle.
5967
// The development configuration is different and lives in a separate file.
60-
module.exports = {
68+
module.exports = customConfig({
6169
// Don't attempt to continue if there are any errors.
6270
bail: true,
6371
// We generate sourcemaps in production. This is slow but gives good results.
@@ -339,4 +347,4 @@ module.exports = {
339347
net: 'empty',
340348
tls: 'empty',
341349
},
342-
};
350+
});

packages/react-scripts/config/webpackDevServer.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
'use strict';
1212

1313
const errorOverlayMiddleware = require('react-error-overlay/middleware');
14-
const config = require('./webpack.config.dev');
14+
const _config = require('./webpack.config.dev');
15+
const config = Array.isArray(_config)?_config[0]:_config
1516
const paths = require('./paths');
1617

1718
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';

packages/react-scripts/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
2-
"name": "react-scripts",
3-
"version": "1.0.1",
4-
"description": "Configuration and scripts for Create React App.",
5-
"repository": "facebookincubator/create-react-app",
2+
"name": "customizable-react-scripts",
3+
"version": "1.0.1-alpha.5",
4+
"description": "customizable CRA's react-scripts",
5+
"repository": "lewisdiamond/create-react-app",
66
"license": "BSD-3-Clause",
77
"engines": {
88
"node": ">=6"
99
},
1010
"bugs": {
11-
"url": "https://github.com/facebookincubator/create-react-app/issues"
11+
"url": "https://github.com/lewisdiamond/create-react-app/issues"
1212
},
1313
"files": [
1414
"bin",

0 commit comments

Comments
 (0)