diff --git a/config/babel.dev.js b/config/babel.dev.js index ee7d4fdf6db..59b12fa490e 100644 --- a/config/babel.dev.js +++ b/config/babel.dev.js @@ -8,41 +8,51 @@ * of patent rights can be found in the PATENTS file in the same directory. */ // @remove-on-eject-end - var path = require('path'); -var findCacheDir = require('find-cache-dir'); -module.exports = { - // Don't try to find .babelrc because we want to force this configuration. - babelrc: false, - // This is a feature of `babel-loader` for webpack (not Babel itself). - // It enables caching results in ./node_modules/.cache/react-scripts/ - // directory for faster rebuilds. - cacheDirectory: findCacheDir({ name: 'react-scripts' }), - presets: [ - // Latest stable ECMAScript features - require.resolve('babel-preset-latest'), - // JSX, Flow - require.resolve('babel-preset-react') - ], - plugins: [ - // class { handleClick = () => { } } - require.resolve('babel-plugin-transform-class-properties'), - // { ...todo, completed: true } - require.resolve('babel-plugin-transform-object-rest-spread'), - // function* () { yield 42; yield 43; } - [require.resolve('babel-plugin-transform-regenerator'), { - // Async functions are converted to generators by babel-preset-latest - async: false - }], - // Polyfills the runtime needed for async/await and generators - [require.resolve('babel-plugin-transform-runtime'), { - helpers: false, - polyfill: false, - regenerator: true, - // Resolve the Babel runtime relative to the config. - // You can safely remove this after ejecting: - moduleName: path.dirname(require.resolve('babel-runtime/package')) - }] - ] +module.exports = function (resolvePaths) { + return { + // Don't try to find .babelrc because we want to force this configuration. + babelrc: false, + presets: [ + // Latest stable ECMAScript features + 'babel-preset-latest', + // JSX, Flow + 'babel-preset-react' + ].map(function (preset) { + if (resolvePaths) { + return require.resolve(preset); + } + + return preset; + }), + plugins: [ + // class { handleClick = () => { } } + 'babel-plugin-transform-class-properties', + // { ...todo, completed: true } + 'babel-plugin-transform-object-rest-spread', + // function* () { yield 42; yield 43; } + ['babel-plugin-transform-regenerator', { + // Async functions are converted to generators by babel-preset-latest + async: false + }], + // Polyfills the runtime needed for async/await and generators + ['babel-plugin-transform-runtime', { + helpers: false, + polyfill: false, + regenerator: true, + // Resolve the Babel runtime relative to the config. + // You can safely remove this after ejecting: + moduleName: path.dirname(require.resolve('babel-runtime/package')) + }] + ].map(function (plugin) { + if (resolvePaths) { + return Array.isArray(plugin) ? + [require.resolve(plugin[0]), plugin[1]] : + require.resolve(plugin); + } + + return plugin; + }) + } }; diff --git a/config/babel.prod.js b/config/babel.prod.js index f53094ababd..1bdfdad8f05 100644 --- a/config/babel.prod.js +++ b/config/babel.prod.js @@ -8,42 +8,57 @@ * of patent rights can be found in the PATENTS file in the same directory. */ // @remove-on-eject-end - var path = require('path'); -module.exports = { - // Don't try to find .babelrc because we want to force this configuration. - babelrc: false, - presets: [ - // Latest stable ECMAScript features - require.resolve('babel-preset-latest'), - // JSX, Flow - require.resolve('babel-preset-react') - ], - plugins: [ - // class { handleClick = () => { } } - require.resolve('babel-plugin-transform-class-properties'), - // { ...todo, completed: true } - require.resolve('babel-plugin-transform-object-rest-spread'), - // function* () { yield 42; yield 43; } - [require.resolve('babel-plugin-transform-regenerator'), { - // Async functions are converted to generators by babel-preset-latest - async: false - }], - // Polyfills the runtime needed for async/await and generators - [require.resolve('babel-plugin-transform-runtime'), { - helpers: false, - polyfill: false, - regenerator: true, - // Resolve the Babel runtime relative to the config. - // You can safely remove this after ejecting: - moduleName: path.dirname(require.resolve('babel-runtime/package')) - }], - // Optimization: hoist JSX that never changes out of render() - // Disabled because of issues: - // * https://github.com/facebookincubator/create-react-app/issues/525 - // * https://phabricator.babeljs.io/search/query/pCNlnC2xzwzx/ - // TODO: Enable again when these issues are resolved. - // require.resolve('babel-plugin-transform-react-constant-elements') - ] +module.exports = function (resolvePaths) { + return { + // Don't try to find .babelrc because we want to force this configuration. + babelrc: false, + presets: [ + // Latest stable ECMAScript features + 'babel-preset-latest', + // JSX, Flow + 'babel-preset-react' + ].map(function (preset) { + if (resolvePaths) { + return require.resolve(preset); + } + + return preset; + }), + plugins: [ + // class { handleClick = () => { } } + 'babel-plugin-transform-class-properties', + // { ...todo, completed: true } + 'babel-plugin-transform-object-rest-spread', + // function* () { yield 42; yield 43; } + ['babel-plugin-transform-regenerator', { + // Async functions are converted to generators by babel-preset-latest + async: false + }], + // Polyfills the runtime needed for async/await and generators + ['babel-plugin-transform-runtime', { + helpers: false, + polyfill: false, + regenerator: true, + // Resolve the Babel runtime relative to the config. + // You can safely remove this after ejecting: + moduleName: path.dirname(require.resolve('babel-runtime/package')) + }], + // Optimization: hoist JSX that never changes out of render() + // Disabled because of issues: + // * https://github.com/facebookincubator/create-react-app/issues/525 + // * https://phabricator.babeljs.io/search/query/pCNlnC2xzwzx/ + // TODO: Enable again when these issues are resolved. + // require.resolve('babel-plugin-transform-react-constant-elements') + ].map(function (plugin) { + if (resolvePaths) { + return Array.isArray(plugin) ? + [require.resolve(plugin[0]), plugin[1]] : + require.resolve(plugin); + } + + return plugin; + }) + }; }; diff --git a/config/jest/transform.js b/config/jest/transform.js index 3a085e93e65..9380abb4344 100644 --- a/config/jest/transform.js +++ b/config/jest/transform.js @@ -8,7 +8,13 @@ */ // @remove-on-eject-end -const babelDev = require('../babel.dev'); const babelJest = require('babel-jest'); +// After Eject +module.exports = babelJest.createTransformer(); + +// @remove-on-eject-begin +// Before Eject +const babelDev = require('../babel.dev')(true); module.exports = babelJest.createTransformer(babelDev); +// @remove-on-eject-end diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index 34bda5590a3..942d44099d9 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -17,6 +17,7 @@ var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); var WatchMissingNodeModulesPlugin = require('../scripts/utils/WatchMissingNodeModulesPlugin'); var paths = require('./paths'); var env = require('./env'); +var findCacheDir = require('find-cache-dir'); // This is the development configuration. // It is focused on developer experience and fast rebuilds. @@ -107,7 +108,17 @@ module.exports = { test: /\.(js|jsx)$/, include: paths.appSrc, loader: 'babel', - query: require('./babel.dev') + query: Object.assign({}, + // @remove-on-eject-begin + require('./babel.dev')(true), + // @remove-on-eject-end + { + // This is a feature of `babel-loader` for webpack (not Babel itself). + // It enables caching results in ./node_modules/.cache/react-scripts/ + // directory for faster rebuilds. + cacheDirectory: findCacheDir({ name: 'react-scripts' }) + } + ) }, // "postcss" loader applies autoprefixer to our CSS. // "css" loader resolves paths in CSS and adds assets as dependencies. diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index c03b6ef272f..f9f71843714 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -102,7 +102,9 @@ module.exports = { test: /\.(js|jsx)$/, include: paths.appSrc, loader: 'babel', - query: require('./babel.prod') + // @remove-on-eject-begin + query: require('./babel.prod')(true) + // @remove-on-eject-end }, // The notation here is somewhat confusing. // "postcss" loader applies autoprefixer to our CSS. diff --git a/scripts/eject.js b/scripts/eject.js index 3e5e18af387..9d21be36771 100644 --- a/scripts/eject.js +++ b/scripts/eject.js @@ -13,6 +13,8 @@ var path = require('path'); var prompt = require('./utils/prompt'); var rimrafSync = require('rimraf').sync; var spawnSync = require('cross-spawn').sync; +var babelDevConfig = require('../config/babel.dev.js')(false); +var babelProdConfig = require('../config/babel.prod.js')(false); prompt( 'Are you sure you want to eject? This action is permanent.', @@ -29,8 +31,6 @@ prompt( var ownPath = path.join(__dirname, '..'); var appPath = path.join(ownPath, '..', '..'); var files = [ - path.join('config', 'babel.dev.js'), - path.join('config', 'babel.prod.js'), path.join('config', 'flow', 'css.js.flow'), path.join('config', 'flow', 'file.js.flow'), path.join('config', 'eslint.js'), @@ -62,6 +62,17 @@ prompt( } }); + // Ensure a .babelrc file doesn't exist in the app config folder + if (fs.existsSync(path.join(appPath, 'config', '.babelrc'))) { + console.error( + 'config/.babelrc already exists in your app folder. We cannot ' + + 'continue as you would lose all the changes in that file ' + + 'Please delete it (maybe make a copy for backup) and run this ' + + 'command again. You might have to manually merge your configs.' + ); + process.exit(1); + } + // Copy the files over fs.mkdirSync(path.join(appPath, 'config')); fs.mkdirSync(path.join(appPath, 'config', 'flow')); @@ -69,6 +80,7 @@ prompt( fs.mkdirSync(path.join(appPath, 'scripts')); fs.mkdirSync(path.join(appPath, 'scripts', 'utils')); + files.forEach(function(file) { console.log('Copying ' + file + ' to ' + appPath); var content = fs @@ -82,6 +94,31 @@ prompt( }); console.log(); + // Create .babelrc from dev and prod configs + var babelrc = { + env: { + test: { + presets: babelDevConfig.presets, + plugins: babelDevConfig.plugins + }, + development: { + presets: babelDevConfig.presets, + plugins: babelDevConfig.plugins + }, + production: { + presets: babelProdConfig.presets, + plugins: babelProdConfig.plugins + } + } + }; + + console.log('Writing config/.babelrc to ' + appPath ); + fs.writeFileSync( + path.join(appPath, 'config', '.babelrc'), + JSON.stringify(babelrc, null, 2) + ); + console.log(); + var ownPackage = require(path.join(ownPath, 'package.json')); var appPackage = require(path.join(appPath, 'package.json')); @@ -115,6 +152,11 @@ prompt( extends: './config/eslint.js', }; + // Explicitly specify .babelrc config path + appPackage.babel = { + extends: './config/.babelrc' + }; + console.log('Writing package.json'); fs.writeFileSync( path.join(appPath, 'package.json'),