diff --git a/config/babel.dev.js b/config/babel.dev.js index 2c41ed9149a..89096734713 100644 --- a/config/babel.dev.js +++ b/config/babel.dev.js @@ -8,19 +8,31 @@ */ 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 OS temporary directory for faster rebuilds. cacheDirectory: true, presets: [ + // let, const, destructuring, classes, modules require.resolve('babel-preset-es2015'), + // exponentiation require.resolve('babel-preset-es2016'), + // JSX, Flow require.resolve('babel-preset-react') ], plugins: [ + // function x(a, b, c,) { } require.resolve('babel-plugin-syntax-trailing-function-commas'), + // await fetch() require.resolve('babel-plugin-syntax-async-functions'), + // 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'), + // Polyfills the runtime needed for async/await and generators [require.resolve('babel-plugin-transform-runtime'), { helpers: false, polyfill: false, diff --git a/config/babel.prod.js b/config/babel.prod.js index 754302a20d9..92491bfcacb 100644 --- a/config/babel.prod.js +++ b/config/babel.prod.js @@ -8,23 +8,34 @@ */ module.exports = { + // Don't try to find .babelrc because we want to force this configuration. babelrc: false, presets: [ + // let, const, destructuring, classes, modules require.resolve('babel-preset-es2015'), + // exponentiation require.resolve('babel-preset-es2016'), + // JSX, Flow require.resolve('babel-preset-react') ], plugins: [ + // function x(a, b, c,) { } require.resolve('babel-plugin-syntax-trailing-function-commas'), + // await fetch() require.resolve('babel-plugin-syntax-async-functions'), + // class { handleClick = () => { } } require.resolve('babel-plugin-transform-class-properties'), + // { ...todo, completed: true } require.resolve('babel-plugin-transform-object-rest-spread'), - require.resolve('babel-plugin-transform-react-constant-elements'), + // function* () { yield 42; yield 43; } require.resolve('babel-plugin-transform-regenerator'), + // Polyfills the runtime needed for async/await and generators [require.resolve('babel-plugin-transform-runtime'), { helpers: false, polyfill: false, regenerator: true - }] + }], + // Optimization: hoist JSX that never changes out of render() + require.resolve('babel-plugin-transform-react-constant-elements') ] }; diff --git a/config/env.js b/config/env.js index a560425738d..cfa10c75b44 100644 --- a/config/env.js +++ b/config/env.js @@ -7,6 +7,9 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be +// injected into the application via DefinePlugin in Webpack configuration. + var REACT_APP = /^REACT_APP_/i; var NODE_ENV = JSON.stringify(process.env.NODE_ENV || 'development'); diff --git a/config/polyfills.js b/config/polyfills.js index 0a0bd950493..1f71e4ac4f2 100644 --- a/config/polyfills.js +++ b/config/polyfills.js @@ -6,4 +6,5 @@ if (typeof Promise === 'undefined') { window.Promise = require('promise/lib/es6-extensions.js'); } +// fetch() polyfill for making API calls. require('whatwg-fetch'); diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index cba0738c2a8..a3db11f8ec7 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -16,22 +16,56 @@ var WatchMissingNodeModulesPlugin = require('../scripts/utils/WatchMissingNodeMo var paths = require('./paths'); var env = require('./env'); +// This is the development configuration. +// It is focused on developer experience and fast rebuilds. +// The production configuration is different and lives in a separate file. module.exports = { + // This makes the bundle appear split into separate modules in the devtools. + // We don't use source maps here because they can be confusing: + // https://github.com/facebookincubator/create-react-app/issues/343#issuecomment-237241875 + // You may want 'cheap-module-source-map' instead if you prefer source maps. devtool: 'eval', + // These are the "entry points" to our application. + // This means they will be the "root" imports that are included in JS bundle. + // The first two entry points enable "hot" CSS and auto-refreshes for JS. entry: [ + // Include WebpackDevServer client. It connects to WebpackDevServer via + // sockets and waits for recompile notifications. When WebpackDevServer + // recompiles, it sends a message to the client by socket. If only CSS + // was changed, the app reload just the CSS. Otherwise, it will refresh. + // The "?/" bit at the end tells the client to look for the socket at + // the root path, i.e. /sockjs-node/. Otherwise visiting a client-side + // route like /todos/42 would make it wrongly request /todos/42/sockjs-node. + // The socket server is a part of WebpackDevServer which we are using. + // The /sockjs-node/ path I'm referring to is hardcoded in WebpackDevServer. require.resolve('webpack-dev-server/client') + '?/', + // Include Webpack hot module replacement runtime. Webpack is pretty + // low-level so we need to put all the pieces together. The runtime listens + // to the events received by the client above, and applies updates (such as + // new CSS) to the running application. require.resolve('webpack/hot/dev-server'), + // We ship a few polyfills by default. require.resolve('./polyfills'), + // Finally, this is your app's code: path.join(paths.appSrc, 'index') + // We include the app code last so that if there is a runtime error during + // initialization, it doesn't blow up the WebpackDevServer client, and + // changing JS code would still trigger a refresh. ], output: { // Next line is not used in dev but WebpackDevServer crashes without it: path: paths.appBuild, + // Add /* filename */ comments to generated require()s in the output. pathinfo: true, + // This does not produce a real file. It's just the virtual path that is + // served by WebpackDevServer in development. This is the JS bundle + // containing code from all our entry points, and the Webpack runtime. filename: 'static/js/bundle.js', + // In development, we always serve from the root. This makes config easier. publicPath: '/' }, resolve: { + // These are the reasonable defaults supported by the Node ecosystem. extensions: ['.js', '.json', ''], alias: { // This `alias` section can be safely removed after ejection. @@ -45,11 +79,16 @@ module.exports = { 'babel-runtime/regenerator': require.resolve('babel-runtime/regenerator') } }, + // Resolve loaders (webpack plugins for CSS, images, transpilation) from the + // directory of `react-scripts` itself rather than the project directory. + // You can remove this after ejecting. resolveLoader: { root: paths.ownNodeModules, moduleTemplates: ['*-loader'] }, module: { + // First, run the linter. + // It's important to do this before Babel processes the JS. preLoaders: [ { test: /\.js$/, @@ -58,22 +97,33 @@ module.exports = { } ], loaders: [ + // Process JS with Babel. { test: /\.js$/, include: paths.appSrc, loader: 'babel', query: require('./babel.dev') }, + // "postcss" loader applies autoprefixer to our CSS. + // "css" loader resolves paths in CSS and adds assets as dependencies. + // "style" loader turns CSS into JS modules that inject