From c38094e7d62e2efdd4c97b4023e1f52e80d367ef Mon Sep 17 00:00:00 2001 From: Ville Immonen Date: Mon, 19 Sep 2016 02:12:19 +0300 Subject: [PATCH 001/494] Set up a monorepo with Lerna --- bin/react-scripts.js | 22 + config/babel.dev.js | 51 + config/babel.prod.js | 49 + config/env.js | 26 + config/eslint.js | 211 ++++ config/flow/css.js.flow | 1 + config/flow/file.js.flow | 2 + config/jest/CSSStub.js | 13 + config/jest/FileStub.js | 13 + config/jest/transform.js | 14 + config/paths.js | 83 ++ config/polyfills.js | 25 + config/webpack.config.dev.js | 214 +++++ config/webpack.config.prod.js | 249 +++++ package.json | 81 ++ scripts/build.js | 177 ++++ scripts/eject.js | 135 +++ scripts/init.js | 118 +++ scripts/start.js | 337 +++++++ scripts/test.js | 29 + .../utils/WatchMissingNodeModulesPlugin.js | 35 + scripts/utils/checkRequiredFiles.js | 33 + scripts/utils/chrome.applescript | 50 + scripts/utils/createJestConfig.js | 39 + scripts/utils/prompt.js | 42 + template/README.md | 904 ++++++++++++++++++ template/gitignore | 14 + template/index.html | 22 + template/src/App.css | 24 + template/src/App.js | 21 + template/src/App.test.js | 8 + template/src/favicon.ico | Bin 0 -> 24838 bytes template/src/index.css | 5 + template/src/index.js | 9 + template/src/logo.svg | 7 + 35 files changed, 3063 insertions(+) create mode 100755 bin/react-scripts.js create mode 100644 config/babel.dev.js create mode 100644 config/babel.prod.js create mode 100644 config/env.js create mode 100644 config/eslint.js create mode 100644 config/flow/css.js.flow create mode 100644 config/flow/file.js.flow create mode 100644 config/jest/CSSStub.js create mode 100644 config/jest/FileStub.js create mode 100644 config/jest/transform.js create mode 100644 config/paths.js create mode 100644 config/polyfills.js create mode 100644 config/webpack.config.dev.js create mode 100644 config/webpack.config.prod.js create mode 100644 package.json create mode 100644 scripts/build.js create mode 100644 scripts/eject.js create mode 100644 scripts/init.js create mode 100644 scripts/start.js create mode 100644 scripts/test.js create mode 100644 scripts/utils/WatchMissingNodeModulesPlugin.js create mode 100644 scripts/utils/checkRequiredFiles.js create mode 100644 scripts/utils/chrome.applescript create mode 100644 scripts/utils/createJestConfig.js create mode 100644 scripts/utils/prompt.js create mode 100644 template/README.md create mode 100644 template/gitignore create mode 100644 template/index.html create mode 100644 template/src/App.css create mode 100644 template/src/App.js create mode 100644 template/src/App.test.js create mode 100644 template/src/favicon.ico create mode 100644 template/src/index.css create mode 100644 template/src/index.js create mode 100644 template/src/logo.svg diff --git a/bin/react-scripts.js b/bin/react-scripts.js new file mode 100755 index 00000000000..58381833957 --- /dev/null +++ b/bin/react-scripts.js @@ -0,0 +1,22 @@ +#!/usr/bin/env node +var spawn = require('cross-spawn'); +var script = process.argv[2]; +var args = process.argv.slice(3); + +switch (script) { +case 'build': +case 'eject': +case 'start': +case 'test': + var result = spawn.sync( + 'node', + [require.resolve('../scripts/' + script)].concat(args), + {stdio: 'inherit'} + ); + process.exit(result.status); + break; +default: + console.log('Unknown script "' + script + '".'); + console.log('Perhaps you need to update react-scripts?'); + break; +} diff --git a/config/babel.dev.js b/config/babel.dev.js new file mode 100644 index 00000000000..0113b847824 --- /dev/null +++ b/config/babel.dev.js @@ -0,0 +1,51 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * 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. We use findCacheDir() because of: + // https://github.com/facebookincubator/create-react-app/issues/483 + 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')) + }] + ] +}; diff --git a/config/babel.prod.js b/config/babel.prod.js new file mode 100644 index 00000000000..f53094ababd --- /dev/null +++ b/config/babel.prod.js @@ -0,0 +1,49 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * 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') + ] +}; diff --git a/config/env.js b/config/env.js new file mode 100644 index 00000000000..66acf119b84 --- /dev/null +++ b/config/env.js @@ -0,0 +1,26 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +// @remove-on-eject-end + +// 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'); + +module.exports = Object + .keys(process.env) + .filter(key => REACT_APP.test(key)) + .reduce((env, key) => { + env['process.env.' + key] = JSON.stringify(process.env[key]); + return env; + }, { + 'process.env.NODE_ENV': NODE_ENV + }); diff --git a/config/eslint.js b/config/eslint.js new file mode 100644 index 00000000000..a7c955dbea5 --- /dev/null +++ b/config/eslint.js @@ -0,0 +1,211 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +// @remove-on-eject-end + +// Inspired by https://github.com/airbnb/javascript but less opinionated. + +// We use eslint-loader so even warnings are very visibile. +// This is why we only use "WARNING" level for potential errors, +// and we don't use "ERROR" level at all. + +// In the future, we might create a separate list of rules for production. +// It would probably be more strict. + +module.exports = { + root: true, + + parser: 'babel-eslint', + + // import plugin is temporarily disabled, scroll below to see why + plugins: [/*'import', */'flowtype', 'jsx-a11y', 'react'], + + env: { + browser: true, + commonjs: true, + es6: true, + jest: true, + node: true + }, + + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + ecmaFeatures: { + jsx: true, + generators: true, + experimentalObjectRestSpread: true + } + }, + + settings: { + 'import/ignore': [ + 'node_modules', + '\\.(json|css|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$', + ], + 'import/extensions': ['.js'], + 'import/resolver': { + node: { + extensions: ['.js', '.json'] + } + } + }, + + rules: { + // http://eslint.org/docs/rules/ + 'array-callback-return': 'warn', + 'default-case': ['warn', { commentPattern: '^no default$' }], + 'dot-location': ['warn', 'property'], + eqeqeq: ['warn', 'allow-null'], + 'guard-for-in': 'warn', + 'new-parens': 'warn', + 'no-array-constructor': 'warn', + 'no-caller': 'warn', + 'no-cond-assign': ['warn', 'always'], + 'no-const-assign': 'warn', + 'no-control-regex': 'warn', + 'no-delete-var': 'warn', + 'no-dupe-args': 'warn', + 'no-dupe-class-members': 'warn', + 'no-dupe-keys': 'warn', + 'no-duplicate-case': 'warn', + 'no-empty-character-class': 'warn', + 'no-empty-pattern': 'warn', + 'no-eval': 'warn', + 'no-ex-assign': 'warn', + 'no-extend-native': 'warn', + 'no-extra-bind': 'warn', + 'no-extra-label': 'warn', + 'no-fallthrough': 'warn', + 'no-func-assign': 'warn', + 'no-implied-eval': 'warn', + 'no-invalid-regexp': 'warn', + 'no-iterator': 'warn', + 'no-label-var': 'warn', + 'no-labels': ['warn', { allowLoop: false, allowSwitch: false }], + 'no-lone-blocks': 'warn', + 'no-loop-func': 'warn', + 'no-mixed-operators': ['warn', { + groups: [ + ['&', '|', '^', '~', '<<', '>>', '>>>'], + ['==', '!=', '===', '!==', '>', '>=', '<', '<='], + ['&&', '||'], + ['in', 'instanceof'] + ], + allowSamePrecedence: false + }], + 'no-multi-str': 'warn', + 'no-native-reassign': 'warn', + 'no-negated-in-lhs': 'warn', + 'no-new-func': 'warn', + 'no-new-object': 'warn', + 'no-new-symbol': 'warn', + 'no-new-wrappers': 'warn', + 'no-obj-calls': 'warn', + 'no-octal': 'warn', + 'no-octal-escape': 'warn', + 'no-redeclare': 'warn', + 'no-regex-spaces': 'warn', + 'no-restricted-syntax': [ + 'warn', + 'LabeledStatement', + 'WithStatement', + ], + 'no-script-url': 'warn', + 'no-self-assign': 'warn', + 'no-self-compare': 'warn', + 'no-sequences': 'warn', + 'no-shadow-restricted-names': 'warn', + 'no-sparse-arrays': 'warn', + 'no-template-curly-in-string': 'warn', + 'no-this-before-super': 'warn', + 'no-throw-literal': 'warn', + 'no-undef': 'error', + 'no-unexpected-multiline': 'warn', + 'no-unreachable': 'warn', + 'no-unused-expressions': 'warn', + 'no-unused-labels': 'warn', + 'no-unused-vars': ['warn', { + vars: 'local', + varsIgnorePattern: '^_', + args: 'none' + }], + 'no-use-before-define': ['warn', 'nofunc'], + 'no-useless-computed-key': 'warn', + 'no-useless-concat': 'warn', + 'no-useless-constructor': 'warn', + 'no-useless-escape': 'warn', + 'no-useless-rename': ['warn', { + ignoreDestructuring: false, + ignoreImport: false, + ignoreExport: false, + }], + 'no-with': 'warn', + 'no-whitespace-before-property': 'warn', + 'operator-assignment': ['warn', 'always'], + radix: 'warn', + 'require-yield': 'warn', + 'rest-spread-spacing': ['warn', 'never'], + strict: ['warn', 'never'], + 'unicode-bom': ['warn', 'never'], + 'use-isnan': 'warn', + 'valid-typeof': 'warn', + + // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/ + + // TODO: import rules are temporarily disabled because they don't play well + // with how eslint-loader only checks the file you change. So if module A + // imports module B, and B is missing a default export, the linter will + // record this as an issue in module A. Now if you fix module B, the linter + // will not be aware that it needs to re-lint A as well, so the error + // will stay until the next restart, which is really confusing. + + // This is probably fixable with a patch to eslint-loader. + // When file A is saved, we want to invalidate all files that import it + // *and* that currently have lint errors. This should fix the problem. + + // 'import/default': 'warn', + // 'import/export': 'warn', + // 'import/named': 'warn', + // 'import/namespace': 'warn', + // 'import/no-amd': 'warn', + // 'import/no-duplicates': 'warn', + // 'import/no-extraneous-dependencies': 'warn', + // 'import/no-named-as-default': 'warn', + // 'import/no-named-as-default-member': 'warn', + // 'import/no-unresolved': ['warn', { commonjs: true }], + + // https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules + 'react/jsx-equals-spacing': ['warn', 'never'], + 'react/jsx-no-duplicate-props': ['warn', { ignoreCase: true }], + 'react/jsx-no-undef': 'warn', + 'react/jsx-pascal-case': ['warn', { + allowAllCaps: true, + ignore: [], + }], + 'react/jsx-uses-react': 'warn', + 'react/jsx-uses-vars': 'warn', + 'react/no-deprecated': 'warn', + 'react/no-direct-mutation-state': 'warn', + 'react/no-is-mounted': 'warn', + 'react/react-in-jsx-scope': 'warn', + 'react/require-render-return': 'warn', + + // https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules + 'jsx-a11y/aria-role': 'warn', + 'jsx-a11y/img-has-alt': 'warn', + 'jsx-a11y/img-redundant-alt': 'warn', + 'jsx-a11y/no-access-key': 'warn', + + // https://github.com/gajus/eslint-plugin-flowtype + 'flowtype/define-flow-type': 'warn', + 'flowtype/require-valid-file-annotation': 'warn', + 'flowtype/use-flow-type': 'warn' + } +}; diff --git a/config/flow/css.js.flow b/config/flow/css.js.flow new file mode 100644 index 00000000000..46e7f7c0456 --- /dev/null +++ b/config/flow/css.js.flow @@ -0,0 +1 @@ +// @flow diff --git a/config/flow/file.js.flow b/config/flow/file.js.flow new file mode 100644 index 00000000000..701b6700f23 --- /dev/null +++ b/config/flow/file.js.flow @@ -0,0 +1,2 @@ +// @flow +declare export default string; diff --git a/config/jest/CSSStub.js b/config/jest/CSSStub.js new file mode 100644 index 00000000000..05810269ac6 --- /dev/null +++ b/config/jest/CSSStub.js @@ -0,0 +1,13 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// @remove-on-eject-end + +module.exports = {}; diff --git a/config/jest/FileStub.js b/config/jest/FileStub.js new file mode 100644 index 00000000000..c95c3e790a1 --- /dev/null +++ b/config/jest/FileStub.js @@ -0,0 +1,13 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// @remove-on-eject-end + +module.exports = "test-file-stub"; diff --git a/config/jest/transform.js b/config/jest/transform.js new file mode 100644 index 00000000000..3a085e93e65 --- /dev/null +++ b/config/jest/transform.js @@ -0,0 +1,14 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +// @remove-on-eject-end + +const babelDev = require('../babel.dev'); +const babelJest = require('babel-jest'); + +module.exports = babelJest.createTransformer(babelDev); diff --git a/config/paths.js b/config/paths.js new file mode 100644 index 00000000000..314bcc2051f --- /dev/null +++ b/config/paths.js @@ -0,0 +1,83 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +// @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); +} + +// We support resolving modules according to `NODE_PATH`. +// This lets you use absolute paths in imports inside large monorepos: +// https://github.com/facebookincubator/create-react-app/issues/253. + +// It works similar to `NODE_PATH` in Node itself: +// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders + +// We will export `nodePaths` as an array of absolute paths. +// It will then be used by Webpack configs. +// Jest doesn’t need this because it already handles `NODE_PATH` out of the box. + +var nodePaths = (process.env.NODE_PATH || '') + .split(process.platform === 'win32' ? ';' : ':') + .filter(Boolean) + .map(resolveApp); + +// config after eject: we're in ./config/ +module.exports = { + appBuild: resolveApp('build'), + appHtml: resolveApp('index.html'), + appIndexJs: resolveApp('src/index.js'), + appPackageJson: resolveApp('package.json'), + appSrc: resolveApp('src'), + testsSetup: resolveApp('src/setupTests.js'), + appNodeModules: resolveApp('node_modules'), + ownNodeModules: resolveApp('node_modules'), + nodePaths: nodePaths +}; + +// @remove-on-eject-begin +function resolveOwn(relativePath) { + return path.resolve(__dirname, relativePath); +} + +// config before eject: we're in ./node_modules/react-scripts/config/ +module.exports = { + appBuild: resolveApp('build'), + appHtml: resolveApp('index.html'), + appIndexJs: resolveApp('src/index.js'), + appPackageJson: resolveApp('package.json'), + appSrc: resolveApp('src'), + testsSetup: resolveApp('src/setupTests.js'), + appNodeModules: resolveApp('node_modules'), + // this is empty with npm3 but node resolution searches higher anyway: + ownNodeModules: resolveOwn('../node_modules'), + nodePaths: nodePaths +}; +// @remove-on-eject-end + +// @remove-on-publish-begin +module.exports = { + appBuild: resolveOwn('../../../build'), + appHtml: resolveOwn('../template/index.html'), + appIndexJs: resolveOwn('../template/src/index.js'), + appPackageJson: resolveOwn('../package.json'), + appSrc: resolveOwn('../template/src'), + testsSetup: resolveOwn('../template/src/setupTests.js'), + appNodeModules: resolveOwn('../node_modules'), + ownNodeModules: resolveOwn('../node_modules'), + nodePaths: nodePaths +}; +// @remove-on-publish-end diff --git a/config/polyfills.js b/config/polyfills.js new file mode 100644 index 00000000000..a1353ca3d2d --- /dev/null +++ b/config/polyfills.js @@ -0,0 +1,25 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +// @remove-on-eject-end + +if (typeof Promise === 'undefined') { + // Rejection tracking prevents a common issue where React gets into an + // inconsistent state due to an error, but it gets swallowed by a Promise, + // and the user has no idea what causes React's erratic future behavior. + require('promise/lib/rejection-tracking').enable(); + window.Promise = require('promise/lib/es6-extensions.js'); +} + +// fetch() polyfill for making API calls. +require('whatwg-fetch'); + +// Object.assign() is commonly used with React. +// It will use the native implementation if it's present and isn't buggy. +Object.assign = require('object-assign'); diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js new file mode 100644 index 00000000000..cfc971e609e --- /dev/null +++ b/config/webpack.config.dev.js @@ -0,0 +1,214 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +// @remove-on-eject-end + +var path = require('path'); +var autoprefixer = require('autoprefixer'); +var webpack = require('webpack'); +var HtmlWebpackPlugin = require('html-webpack-plugin'); +var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); +var WatchMissingNodeModulesPlugin = require('../scripts/utils/WatchMissingNodeModulesPlugin'); +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: + paths.appIndexJs + // 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: { + // This allows you to set a fallback for where Webpack should look for modules. + // We read `NODE_PATH` environment variable in `paths.js` and pass paths here. + // We use `fallback` instead of `root` because we want `node_modules` to "win" + // if there any conflicts. This matches Node resolution mechanism. + // https://github.com/facebookincubator/create-react-app/issues/253 + fallback: paths.nodePaths, + // These are the reasonable defaults supported by the Node ecosystem. + // We also include JSX as a common component filename extension to support + // some tools, although we do not recommend using it, see: + // https://github.com/facebookincubator/create-react-app/issues/290 + extensions: ['.js', '.json', '.jsx', ''], + alias: { + // Support React Native Web + // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ + 'react-native': 'react-native-web' + } + }, + // 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|jsx)$/, + loader: 'eslint', + include: paths.appSrc, + } + ], + loaders: [ + // Process JS with Babel. + { + test: /\.(js|jsx)$/, + 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