Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for custom babel configuration #1357

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/react-scripts/config/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand All @@ -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'),
Expand All @@ -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'),
Expand Down
9 changes: 7 additions & 2 deletions packages/react-scripts/config/webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '/';
Expand Down Expand Up @@ -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/
Expand Down
9 changes: 7 additions & 2 deletions packages/react-scripts/config/webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
},
Expand Down
1 change: 1 addition & 0 deletions packages/react-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 6 additions & 4 deletions packages/react-scripts/scripts/eject.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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');
Expand Down
32 changes: 31 additions & 1 deletion packages/react-scripts/scripts/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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');
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
13 changes: 13 additions & 0 deletions packages/react-scripts/template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 `[email protected]` and higher.
Expand Down
8 changes: 8 additions & 0 deletions packages/react-scripts/utils/isLocalBabelExists.js
Original file line number Diff line number Diff line change
@@ -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);
};