diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index d15b16a0544..18307aee7f1 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -10,14 +10,8 @@ // @remove-on-eject-end var path = require('path'); -var fs = require('fs'); -// Make sure any symlinks in the project folder are resolved: -// https://github.com/facebookincubator/create-react-app/issues/637 -var appDirectory = fs.realpathSync(process.cwd()); -function resolveApp(relativePath) { - return path.resolve(appDirectory, relativePath); -} +var resolveApp = require('../utils/resolveApp'); // We support resolving modules according to `NODE_PATH`. // This lets you use absolute paths in imports inside large monorepos: diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index d0f22bdd934..45a73473a6a 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -52,6 +52,7 @@ "http-proxy-middleware": "0.17.2", "jest": "17.0.2", "json-loader": "0.5.4", + "lodash": "^4.17.2", "object-assign": "4.1.0", "path-exists": "2.1.0", "postcss-loader": "1.0.0", diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js index 8e4141be8bc..f4d87890c9f 100644 --- a/packages/react-scripts/scripts/build.js +++ b/packages/react-scripts/scripts/build.js @@ -25,12 +25,21 @@ var pathExists = require('path-exists'); var filesize = require('filesize'); var gzipSize = require('gzip-size').sync; var webpack = require('webpack'); -var config = require('../config/webpack.config.prod'); var paths = require('../config/paths'); var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); var recursive = require('recursive-readdir'); var stripAnsi = require('strip-ansi'); +var getWebpackConfig = require('../utils/getWebpackConfig'); + +var config; + +config = require('../config/webpack.config.prod'); + +// @remove-on-eject-begin +config = getWebpackConfig('../config/webpack.config.prod'); +// @remove-on-eject-end + var useYarn = pathExists.sync(paths.yarnLockFile); // Warn and crash if required files are missing diff --git a/packages/react-scripts/scripts/eject.js b/packages/react-scripts/scripts/eject.js index a2bd4961026..411c1ce2b5e 100644 --- a/packages/react-scripts/scripts/eject.js +++ b/packages/react-scripts/scripts/eject.js @@ -58,6 +58,7 @@ prompt( path.join('config', 'webpack.config.prod.js'), path.join('config', 'jest', 'CSSStub.js'), path.join('config', 'jest', 'FileStub.js'), + path.join('utils', 'resolveApp.js'), path.join('scripts', 'build.js'), path.join('scripts', 'start.js'), path.join('scripts', 'test.js') diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 752bd8a08a8..21457c44a6f 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -30,9 +30,18 @@ var getProcessForPort = require('react-dev-utils/getProcessForPort'); var openBrowser = require('react-dev-utils/openBrowser'); var prompt = require('react-dev-utils/prompt'); var pathExists = require('path-exists'); -var config = require('../config/webpack.config.dev'); var paths = require('../config/paths'); +var getWebpackConfig = require('../utils/getWebpackConfig'); + +var config; + +config = require('../config/webpack.config.dev'); + +// @remove-on-eject-begin +config = getWebpackConfig('../config/webpack.config.dev'); +// @remove-on-eject-end + var useYarn = pathExists.sync(paths.yarnLockFile); var cli = useYarn ? 'yarn' : 'npm'; var isInteractive = process.stdout.isTTY; diff --git a/packages/react-scripts/utils/getWebpackConfig.js b/packages/react-scripts/utils/getWebpackConfig.js new file mode 100644 index 00000000000..81cfef0ca22 --- /dev/null +++ b/packages/react-scripts/utils/getWebpackConfig.js @@ -0,0 +1,60 @@ +var mergeWith = require('lodash/mergeWith'); +var resolveApp = require('./resolveApp'); +var paths = require('../config/paths'); + +function customizer(objValue, srcValue) { + if (Array.isArray(objValue)) { + return objValue.concat(srcValue); + } +} + +function firstLevelCustomizer(objValue, srcValue, paramName) { + var array = customizer(objValue, srcValue, paramName); + + if (array) return array; + + if (paramName === 'eslint' && srcValue.configFile) { + srcValue.configFile = resolveApp(srcValue.configFile); + } + + if (typeof srcValue === 'object') { + return mergeWith(objValue, srcValue, customizer); + } +} + +function getWebpackConfig(defaultPath) { + var configPath = resolveApp(process.env.WEBPACK_REPLACE, defaultPath); + + var initialConfig = require(configPath); + var extendConfig = resolveApp(process.env.WEBPACK_MERGE); + + var resultConfig = extendConfig ? mergeWith( + initialConfig, + require(extendConfig), + firstLevelCustomizer + ) : initialConfig; + + var babelConfigPath = resolveApp(process.env.BABEL_REPLACE); + + if (babelConfigPath) { + var loaderBabel = resultConfig.module.loaders.filter(function (loader) { + return loader.loader === 'babel'; + })[0]; + + if (!loaderBabel) { + loaderBabel = { + test: /\.(js|jsx)$/, + include: paths.appSrc, + loader: 'babel' + }; + + resultConfig.module.loaders.push(loaderBabel); + } + + loaderBabel.query = require(babelConfigPath); + } + + return resultConfig; +} + +module.exports = getWebpackConfig; diff --git a/packages/react-scripts/utils/resolveApp.js b/packages/react-scripts/utils/resolveApp.js new file mode 100644 index 00000000000..1690347d602 --- /dev/null +++ b/packages/react-scripts/utils/resolveApp.js @@ -0,0 +1,13 @@ +var fs = require('fs'); +var path = require('path'); + +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebookincubator/create-react-app/issues/637 +var appDirectory = fs.realpathSync(process.cwd()); +function resolveApp(relativePath, defaultPath) { + return relativePath ? + path.resolve(appDirectory, relativePath) : + defaultPath; +} + +module.exports = resolveApp;