From ff0da30650174c7f8e488dfccdbcc7596e2488c1 Mon Sep 17 00:00:00 2001 From: Valeriy Sorokobatko Date: Fri, 6 Jan 2017 18:02:07 +0200 Subject: [PATCH 1/2] Check and use if exist local babel config (.babelrc or packegs.json babel attr) --- packages/react-scripts/config/paths.js | 3 ++ .../config/webpack.config.dev.js | 9 ++++-- .../config/webpack.config.prod.js | 9 ++++-- packages/react-scripts/package.json | 1 + packages/react-scripts/scripts/eject.js | 10 +++--- packages/react-scripts/scripts/start.js | 32 ++++++++++++++++++- packages/react-scripts/template/.babelrc | 3 ++ .../react-scripts/utils/isLocalBabelExists.js | 8 +++++ 8 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 packages/react-scripts/template/.babelrc create mode 100644 packages/react-scripts/utils/isLocalBabelExists.js diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 2f10ea2fb8a..eb24c39e4b3 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -42,6 +42,7 @@ var nodePaths = (process.env.NODE_PATH || '') // config after eject: we're in ./config/ module.exports = { + babelrc: resolveApp('.babelrc'), appBuild: resolveApp('build'), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), @@ -62,6 +63,7 @@ function resolveOwn(relativePath) { // config before eject: we're in ./node_modules/react-scripts/config/ module.exports = { + babelrc: resolveApp('.babelrc'), appBuild: resolveApp('build'), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), @@ -79,6 +81,7 @@ module.exports = { // config before publish: we're in ./packages/react-scripts/config/ if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) { module.exports = { + babelrc: resolveOwn('../template/.babelrc'), appBuild: resolveOwn('../../../build'), appPublic: resolveOwn('../template/public'), appHtml: resolveOwn('../template/public/index.html'), diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index 96fd632b795..4a6261459eb 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -23,6 +23,11 @@ var paths = require('./paths'); var path = require('path'); // @remove-on-eject-end +// @remove-on-eject-begin +var isLocalBabelExists = require('../utils/isLocalBabelExists'); +var localBabelExists = isLocalBabelExists(); +// @remove-on-eject-end + // Webpack uses `publicPath` to determine where the app is being served from. // In development, we always serve from the root. This makes config easier. var publicPath = '/'; @@ -147,8 +152,8 @@ module.exports = { loader: 'babel', query: { // @remove-on-eject-begin - babelrc: false, - presets: [require.resolve('babel-preset-react-app')], + babelrc: localBabelExists, + presets: !localBabelExists ? [require.resolve('babel-preset-react-app')] : null, // @remove-on-eject-end // This is a feature of `babel-loader` for webpack (not Babel itself). // It enables caching results in ./node_modules/.cache/babel-loader/ diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 058db0d7921..290a75547b6 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -24,6 +24,11 @@ var getClientEnvironment = require('./env'); var path = require('path'); // @remove-on-eject-end +// @remove-on-eject-begin +var isLocalBabelExists = require('../utils/isLocalBabelExists'); +var localBabelExists = isLocalBabelExists(); +// @remove-on-eject-end + function ensureSlash(path, needsSlash) { var hasSlash = path.endsWith('/'); if (hasSlash && !needsSlash) { @@ -153,8 +158,8 @@ module.exports = { loader: 'babel', // @remove-on-eject-begin query: { - babelrc: false, - presets: [require.resolve('babel-preset-react-app')], + babelrc: localBabelExists, + presets: !localBabelExists ? [require.resolve('babel-preset-react-app')] : null, }, // @remove-on-eject-end }, diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index c1986cd7541..77aeda8c91a 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -57,6 +57,7 @@ "promise": "7.1.1", "react-dev-utils": "^0.4.2", "recursive-readdir": "2.1.0", + "semver": "^5.3.0", "strip-ansi": "3.0.1", "style-loader": "0.13.1", "url-loader": "0.5.7", diff --git a/packages/react-scripts/scripts/eject.js b/packages/react-scripts/scripts/eject.js index aeed2967d06..b1c5e5420f4 100644 --- a/packages/react-scripts/scripts/eject.js +++ b/packages/react-scripts/scripts/eject.js @@ -11,6 +11,7 @@ var createJestConfig = require('../utils/createJestConfig'); var fs = require('fs-extra'); var path = require('path'); var paths = require('../config/paths'); +var isLocalBabelExists = require('../utils/isLocalBabelExists'); var prompt = require('react-dev-utils/prompt'); var spawnSync = require('cross-spawn').sync; var chalk = require('chalk'); @@ -128,10 +129,11 @@ prompt( true ); - // Add Babel config - - console.log(' Adding ' + cyan('Babel') + ' preset'); - appPackage.babel = babelConfig; + // Add Babel config if there is no local babel config + if (isLocalBabelExists()) { + console.log(' Adding ' + cyan('Babel') + ' preset'); + appPackage.babel = babelConfig; + } // Add ESlint config console.log(' Adding ' + cyan('ESLint') +' configuration'); diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 8615fb074a9..41b0ce5b83d 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -8,7 +8,6 @@ * of patent rights can be found in the PATENTS file in the same directory. */ // @remove-on-eject-end - process.env.NODE_ENV = 'development'; // Load environment variables from .env file. Suppress warnings using silent @@ -19,6 +18,7 @@ require('dotenv').config({silent: true}); var chalk = require('chalk'); var webpack = require('webpack'); +var semver = require('semver'); var WebpackDevServer = require('webpack-dev-server'); var historyApiFallback = require('connect-history-api-fallback'); var httpProxyMiddleware = require('http-proxy-middleware'); @@ -30,9 +30,15 @@ var getProcessForPort = require('react-dev-utils/getProcessForPort'); var openBrowser = require('react-dev-utils/openBrowser'); var prompt = require('react-dev-utils/prompt'); var fs = require('fs'); +var fse = require('fs-extra'); var config = require('../config/webpack.config.dev'); var paths = require('../config/paths'); +// @remove-on-eject-begin +var isLocalBabelExists = require('../utils/isLocalBabelExists'); +var babelPresetReactApp = require('babel-preset-react-app/package.json'); +// @remove-on-eject-end + var useYarn = fs.existsSync(paths.yarnLockFile); var cli = useYarn ? 'yarn' : 'npm'; var isInteractive = process.stdout.isTTY; @@ -42,6 +48,24 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { process.exit(1); } +// @remove-on-eject-begin +var wrongLocalBabelPresetReactAppVersion = false; + +if (isLocalBabelExists()) { + var appPackageJson = fse.readJsonSync(paths.appPackageJson); + var deps = appPackageJson.dependencies; + var devDeps = appPackageJson.devDependencies; + var reactAppPresetName = babelPresetReactApp.name; + + var localBabelPresetReactAppVersion = deps[reactAppPresetName] || devDeps[reactAppPresetName] + + if (localBabelPresetReactAppVersion && + !semver.satisfies(babelPresetReactApp.version, localBabelPresetReactAppVersion)) { + wrongLocalBabelPresetReactAppVersion = true; + } +} +// @remove-on-eject-end + // Tools like Cloud9 rely on this. var DEFAULT_PORT = process.env.PORT || 3000; var compiler; @@ -105,6 +129,12 @@ function setupCompiler(host, port, protocol) { console.log('Note that the development build is not optimized.'); console.log('To create a production build, use ' + chalk.cyan(cli + ' run build') + '.'); console.log(); + // @remove-on-eject-begin + if (wrongLocalBabelPresetReactAppVersion) { + console.log(chalk.yellow('Note that the local package "' + babelPresetReactApp.name + '" version is outdated.')); + } + // @remove-on-eject-end + console.log(); isFirstCompile = false; } diff --git a/packages/react-scripts/template/.babelrc b/packages/react-scripts/template/.babelrc new file mode 100644 index 00000000000..c14b2828d16 --- /dev/null +++ b/packages/react-scripts/template/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["react-app"] +} diff --git a/packages/react-scripts/utils/isLocalBabelExists.js b/packages/react-scripts/utils/isLocalBabelExists.js new file mode 100644 index 00000000000..78571aa4f0c --- /dev/null +++ b/packages/react-scripts/utils/isLocalBabelExists.js @@ -0,0 +1,8 @@ +var fse = require('fs-extra'); +var fs = require('fs'); +var paths = require('../config/paths'); + +module.exports = () => { + var appPackageJson = fse.readJsonSync(paths.appPackageJson); + return appPackageJson.hasOwnProperty('babel') || fs.existsSync(paths.babelrc); +}; From 0b6a5f36008050d60fe5568ace1fa3dac53e3d1c Mon Sep 17 00:00:00 2001 From: Valeriy Sorokobatko Date: Fri, 6 Jan 2017 18:30:12 +0200 Subject: [PATCH 2/2] add documentation about custom babel configuration --- packages/react-scripts/scripts/eject.js | 2 +- packages/react-scripts/template/.babelrc | 3 --- packages/react-scripts/template/README.md | 13 +++++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) delete mode 100644 packages/react-scripts/template/.babelrc diff --git a/packages/react-scripts/scripts/eject.js b/packages/react-scripts/scripts/eject.js index b1c5e5420f4..9b008fb7e2b 100644 --- a/packages/react-scripts/scripts/eject.js +++ b/packages/react-scripts/scripts/eject.js @@ -130,7 +130,7 @@ prompt( ); // Add Babel config if there is no local babel config - if (isLocalBabelExists()) { + if (!isLocalBabelExists()) { console.log(' Adding ' + cyan('Babel') + ' preset'); appPackage.babel = babelConfig; } diff --git a/packages/react-scripts/template/.babelrc b/packages/react-scripts/template/.babelrc deleted file mode 100644 index c14b2828d16..00000000000 --- a/packages/react-scripts/template/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["react-app"] -} diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index e55e6c9f4f8..533ef74994e 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -28,6 +28,7 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Using Global Variables](#using-global-variables) - [Adding Bootstrap](#adding-bootstrap) - [Adding Flow](#adding-flow) +- [Adding Custom Babel Configuration](#adding-custom-babel-configuration) - [Adding Custom Environment Variables](#adding-custom-environment-variables) - [Can I Use Decorators?](#can-i-use-decorators) - [Integrating with a Node Backend](#integrating-with-a-node-backend) @@ -494,6 +495,18 @@ In the future we plan to integrate it into Create React App even more closely. To learn more about Flow, check out [its documentation](https://flowtype.org/). +## Adding Custom Babel Configuration + +You can override builtin babel presets and plugins [via .babelrc or package.json](https://babeljs.io/docs/usage/babelrc/). + +>Note: Don't forget to install babel-preset-react-app and include "react-app" preset into your .babelrc or package.json babel configuration section. + +```js +{ + "presets": ["react-app", "stage-0"] +} +``` + ## Adding Custom Environment Variables >Note: this feature is available with `react-scripts@0.2.3` and higher.