From cca16dfb2ef0e45f759f74ad1cb102150ed6e953 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sat, 11 Feb 2017 14:11:00 -0500 Subject: [PATCH] Upgrade webpack (#1291) * Upgrade webpack * Address more webpack v2 ... * Update html-webpack-plugin * Remove LoaderOptionsPlugin from dev config * ExtractTextPlugin still uses webpack 1 syntax ... and doesn't support complex options (yet) * Grammar nit * Update extract text webpack plugin * - Remove webpack.LoaderOptionsPlugin - Update deps * Lerna hoists packages * Update extract-text-webpack-plugin * Update webpack-dev-server * Remove imports for the tests * stop removing babelrc --- packages/babel-preset-react-app/index.js | 6 +- .../config/webpack.config.dev.js | 87 +++++++++------ .../config/webpack.config.prod.js | 105 ++++++++++-------- .../fixtures/kitchensink/.babelrc | 3 +- .../kitchensink/.template.dependencies.json | 1 + packages/react-scripts/package.json | 11 +- packages/react-scripts/scripts/start.js | 3 +- tasks/e2e-kitchensink.sh | 3 - 8 files changed, 122 insertions(+), 97 deletions(-) diff --git a/packages/babel-preset-react-app/index.js b/packages/babel-preset-react-app/index.js index a028babc06c..8a42f885e31 100644 --- a/packages/babel-preset-react-app/index.js +++ b/packages/babel-preset-react-app/index.js @@ -88,7 +88,11 @@ if (env === 'test') { module.exports = { presets: [ // Latest stable ECMAScript features - require.resolve('babel-preset-latest'), + [require.resolve('babel-preset-latest'), { + 'es2015': { + modules: false + } + }], // JSX, Flow require.resolve('babel-preset-react') ], diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index fb8569be5c7..9f43f55cf8f 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -81,15 +81,15 @@ module.exports = { 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. + // We placed these paths second because we want `node_modules` to "win" + // if there are any conflicts. This matches Node resolution mechanism. // https://github.com/facebookincubator/create-react-app/issues/253 - fallback: paths.nodePaths, + modules: ['node_modules'].concat(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', ''], + 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/ @@ -100,21 +100,32 @@ module.exports = { // Resolve loaders (webpack plugins for CSS, images, transpilation) from the // directory of `react-scripts` itself rather than the project directory. resolveLoader: { - root: paths.ownNodeModules, - moduleTemplates: ['*-loader'] + modules: [ + paths.ownNodeModules, + // Lerna hoists everything, so we need to look in our app directory + paths.appNodeModules + ] }, // @remove-on-eject-end module: { - // First, run the linter. - // It's important to do this before Babel processes the JS. - preLoaders: [ + rules: [ + // First, run the linter. + // It's important to do this before Babel processes the JS. { test: /\.(js|jsx)$/, - loader: 'eslint', - include: paths.appSrc, - } - ], - loaders: [ + enforce: 'pre', + use: [{ + // @remove-on-eject-begin + // Point ESLint to our predefined config. + options: { + configFile: path.join(__dirname, '../.eslintrc'), + useEslintrc: false + }, + // @remove-on-eject-end + loader: 'eslint-loader' + }], + include: paths.appSrc + }, // ** ADDING/UPDATING LOADERS ** // The "url" loader handles all assets unless explicitly excluded. // The `exclude` list *must* be updated with every change to loader extensions. @@ -131,8 +142,8 @@ module.exports = { /\.json$/, /\.svg$/ ], - loader: 'url', - query: { + loader: 'url-loader', + options: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]' } @@ -141,8 +152,8 @@ module.exports = { { test: /\.(js|jsx)$/, include: paths.appSrc, - loader: 'babel', - query: { + loader: 'babel-loader', + options: { // @remove-on-eject-begin babelrc: false, presets: [require.resolve('babel-preset-react-app')], @@ -160,19 +171,26 @@ module.exports = { // in development "style" loader enables hot editing of CSS. { test: /\.css$/, - loader: 'style!css?importLoaders=1!postcss' - }, - // JSON is not enabled by default in Webpack but both Node and Browserify - // allow it implicitly so we also enable it. - { - test: /\.json$/, - loader: 'json' + use: [ + 'style-loader', { + loader: 'css-loader', + options: { + importLoaders: 1 + } + }, { + loader: 'postcss-loader', + options: { + ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options + plugins: postcss + } + } + ] }, // "file" loader for svg { test: /\.svg$/, - loader: 'file', - query: { + loader: 'file-loader', + options: { name: 'static/media/[name].[hash:8].[ext]' } } @@ -180,15 +198,6 @@ module.exports = { // Remember to add the new extension(s) to the "url" loader exclusion list. ] }, - // @remove-on-eject-begin - // Point ESLint to our predefined config. - eslint: { - configFile: './.eslintrc', - useEslintrc: false - }, - // @remove-on-eject-end - // We use PostCSS for autoprefixing only. - postcss: postcss, plugins: [ // Makes some environment variables available in index.html. // The public URL is available as %PUBLIC_URL% in index.html, e.g.: @@ -224,5 +233,11 @@ module.exports = { fs: 'empty', net: 'empty', tls: 'empty' + }, + // Turn off performance hints during development because we don't do any + // splitting or minification in interest of speed. These warnings become + // cumbersome. + performance: { + hints: false } }; diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 7ea1b8a6d7e..1e1860d295d 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -55,8 +55,8 @@ const cssFilename = 'static/css/[name].[contenthash:8].css'; // To have this structure working with relative paths, we have to use custom options. const extractTextPluginOptions = shouldUseRelativeAssetPaths // Making sure that the publicPath goes back to to build folder. - ? { publicPath: Array(cssFilename.split('/').length).join('../') } - : undefined; + ? {publicPath: Array(cssFilename.split('/').length).join('../')} + : {}; // This is the production configuration. // It compiles slowly and is focused on producing a fast and minimal bundle. @@ -86,15 +86,15 @@ module.exports = { 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. + // We placed these paths second because we want `node_modules` to "win" + // if there are any conflicts. This matches Node resolution mechanism. // https://github.com/facebookincubator/create-react-app/issues/253 - fallback: paths.nodePaths, + modules: ['node_modules'].concat(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', ''], + 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/ @@ -105,21 +105,34 @@ module.exports = { // Resolve loaders (webpack plugins for CSS, images, transpilation) from the // directory of `react-scripts` itself rather than the project directory. resolveLoader: { - root: paths.ownNodeModules, - moduleTemplates: ['*-loader'] + modules: [ + paths.ownNodeModules, + // Lerna hoists everything, so we need to look in our app directory + paths.appNodeModules + ] }, // @remove-on-eject-end module: { - // First, run the linter. - // It's important to do this before Babel processes the JS. - preLoaders: [ + rules: [ + // First, run the linter. + // It's important to do this before Babel processes the JS. { test: /\.(js|jsx)$/, - loader: 'eslint', + enforce: 'pre', + use: [{ + // @remove-on-eject-begin + // Point ESLint to our predefined config. + options: { + // TODO: consider separate config for production, + // e.g. to enable no-console and no-debugger only in production. + configFile: path.join(__dirname, '../.eslintrc'), + useEslintrc: false + }, + // @remove-on-eject-end + loader: 'eslint-loader' + }], include: paths.appSrc - } - ], - loaders: [ + }, // ** ADDING/UPDATING LOADERS ** // The "url" loader handles all assets unless explicitly excluded. // The `exclude` list *must* be updated with every change to loader extensions. @@ -136,8 +149,8 @@ module.exports = { /\.json$/, /\.svg$/ ], - loader: 'url', - query: { + loader: 'url-loader', + options: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]' } @@ -146,9 +159,9 @@ module.exports = { { test: /\.(js|jsx)$/, include: paths.appSrc, - loader: 'babel', + loader: 'babel-loader', // @remove-on-eject-begin - query: { + options: { babelrc: false, presets: [require.resolve('babel-preset-react-app')], }, @@ -168,24 +181,30 @@ module.exports = { // in the main CSS file. { test: /\.css$/, - loader: ExtractTextPlugin.extract( - 'style', - 'css?importLoaders=1!postcss', - extractTextPluginOptions - ) + loader: ExtractTextPlugin.extract(Object.assign({ + fallback: 'style-loader', + use: [ + { + loader: 'css-loader', + options: { + importLoaders: 1 + } + }, { + loader: 'postcss-loader', + options: { + ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options + plugins: postcss + } + } + ] + }, extractTextPluginOptions)) // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, - // JSON is not enabled by default in Webpack but both Node and Browserify - // allow it implicitly so we also enable it. - { - test: /\.json$/, - loader: 'json' - }, // "file" loader for svg { test: /\.svg$/, - loader: 'file', - query: { + loader: 'file-loader', + options: { name: 'static/media/[name].[hash:8].[ext]' } } @@ -193,17 +212,6 @@ module.exports = { // Remember to add the new extension(s) to the "url" loader exclusion list. ] }, - // @remove-on-eject-begin - // Point ESLint to our predefined config. - eslint: { - // TODO: consider separate config for production, - // e.g. to enable no-console and no-debugger only in production. - configFile: path.join(__dirname, '../.eslintrc'), - useEslintrc: false - }, - // @remove-on-eject-end - // We use PostCSS for autoprefixing only. - postcss: postcss, plugins: [ // Makes some environment variables available in index.html. // The public URL is available as %PUBLIC_URL% in index.html, e.g.: @@ -233,10 +241,6 @@ module.exports = { // It is absolutely essential that NODE_ENV was set to production here. // Otherwise React will be compiled in the very slow development mode. new webpack.DefinePlugin(env.stringified), - // This helps ensure the builds are consistent if source hasn't changed: - new webpack.optimize.OccurrenceOrderPlugin(), - // Try to dedupe duplicated modules, if any: - new webpack.optimize.DedupePlugin(), // Minify the code. new webpack.optimize.UglifyJsPlugin({ compress: { @@ -249,10 +253,13 @@ module.exports = { output: { comments: false, screw_ie8: true - } + }, + sourceMap: true }), // Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`. - new ExtractTextPlugin(cssFilename), + new ExtractTextPlugin({ + filename: cssFilename + }), // Generate a manifest file which contains a mapping of all asset filenames // to their corresponding output file so that tools can pick it up without // having to parse `index.html`. diff --git a/packages/react-scripts/fixtures/kitchensink/.babelrc b/packages/react-scripts/fixtures/kitchensink/.babelrc index c14b2828d16..14397221e3b 100644 --- a/packages/react-scripts/fixtures/kitchensink/.babelrc +++ b/packages/react-scripts/fixtures/kitchensink/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["react-app"] + "presets": ["react-app"], + "plugins": ["babel-plugin-transform-es2015-modules-commonjs"] } diff --git a/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json b/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json index 50511b3d16a..a20139318c1 100644 --- a/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json +++ b/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json @@ -1,6 +1,7 @@ { "dependencies": { "babel-register": "6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "6.22.0", "babel-polyfill": "6.20.0", "chai": "3.5.0", "jsdom": "9.8.3", diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 49cc09e2cf2..452a647ea3c 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -39,20 +39,19 @@ "dotenv": "2.0.0", "eslint": "3.8.1", "eslint-config-react-app": "^0.5.1", - "eslint-loader": "1.6.0", + "eslint-loader": "1.6.1", "eslint-plugin-flowtype": "2.21.0", "eslint-plugin-import": "2.0.1", "eslint-plugin-jsx-a11y": "2.2.3", "eslint-plugin-react": "6.4.1", - "extract-text-webpack-plugin": "1.0.1", + "extract-text-webpack-plugin": "2.0.0-rc.3", "file-loader": "0.10.0", "filesize": "3.3.0", "fs-extra": "0.30.0", "gzip-size": "3.0.0", - "html-webpack-plugin": "2.24.0", + "html-webpack-plugin": "2.28.0", "http-proxy-middleware": "0.17.3", "jest": "18.1.0", - "json-loader": "0.5.4", "object-assign": "4.1.1", "postcss-loader": "1.2.2", "postcss-cssnext": "^2.9.0", @@ -73,8 +72,8 @@ "style-loader": "0.13.1", "tachyons": "^4.6.1", "url-loader": "0.5.7", - "webpack": "1.14.0", - "webpack-dev-server": "1.16.2", + "webpack": "2.2.1", + "webpack-dev-server": "2.3.0", "webpack-manifest-plugin": "1.1.0", "whatwg-fetch": "2.0.2" }, diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index c326b9b94d9..6943f6bb95b 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -268,7 +268,8 @@ function runDevServer(host, port, protocol) { }, // Enable HTTPS if the HTTPS environment variable is set to 'true' https: protocol === "https", - host: host + host: host, + overlay: false, }); // Our custom middleware proxies requests to /index.html or a remote API. diff --git a/tasks/e2e-kitchensink.sh b/tasks/e2e-kitchensink.sh index 3c750feca53..4bb45d72853 100755 --- a/tasks/e2e-kitchensink.sh +++ b/tasks/e2e-kitchensink.sh @@ -167,9 +167,6 @@ npm link $root_path/packages/eslint-config-react-app npm link $root_path/packages/react-dev-utils npm link $root_path/packages/react-scripts -# ...and we need to remove template's .babelrc -rm .babelrc - # Test the build REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ NODE_PATH=src \