- [x] Upgrade to webpack 4.8.X (#4077)

- [x] Utilize webpack 4 development and production modes
- [x] Upgrade webpack dev server
- [x] Webpack 4 compatible release of thread-loader
- [x] Webpack 4 compatible release of HtmlWebpackPlugin
- [x] Webpack 4 compatible release of SwPrecacheWebpackPlugin
- [x] Webpack 4 compatible release of WebpackManifestPlugin
- [x] Update README
- [x] Update WebpackDevServerUtils
- [x] Update InterpolateHtmlPlugin
- [x] Update ModuleScopePlugin
- [x] Update WatchMissingNodeModulesPlugin
- [x] Move UglifyJS options to webpack 4 optimize
- [x] Move InterpolateHtmlPlugin to make it tapable on HtmlWebpackPlugin
- [x] vendor splitting via splitChunks.splitChunks (https://twitter.com/wSokra/status/969633336732905474)
- [x] long term caching via splitChunks.runtimeChunk (https://twitter.com/wSokra/status/969679223278505985)
- [x] Make sure process.env.NODE_ENV is proxied correctly to `react-error-overlay`
- [x] Implicit webpack.NamedModulesPlugin in dev config as its default in webpack 4
- [x] Disable webpack performance hints as we have our own filesize reporter
- [x] Replace ExtractTextPlugin with MiniCssExtractPlugin
- [x] Switch to css whole file minification via OptimizeCSSAssetsPlugin rather than per module css minification to gain performance
This commit is contained in:
Andreas Cederström
2018-05-20 19:22:24 +02:00
committed by Dan Abramov
parent 493a379c21
commit d72678fb0c
17 changed files with 304 additions and 301 deletions

View File

@@ -19,16 +19,16 @@
"precommit": "lint-staged"
},
"devDependencies": {
"eslint": "4.15.0",
"execa": "^0.9.0",
"husky": "^0.13.2",
"lerna": "2.6.0",
"lerna-changelog": "^0.6.0",
"eslint": "4.19.1",
"execa": "^0.10.0",
"husky": "^0.14.3",
"lerna": "2.9.1",
"lerna-changelog": "^0.7.0",
"lint-staged": "^7.0.5",
"meow": "^4.0.0",
"multimatch": "^2.1.0",
"prettier": "1.6.1",
"svg-term-cli": "^2.0.3",
"prettier": "1.12.1",
"svg-term-cli": "^2.1.1",
"tempy": "^0.2.1"
},
"lint-staged": {

View File

@@ -27,6 +27,6 @@
"@babel/preset-react": "7.0.0-beta.46",
"babel-plugin-macros": "2.2.1",
"babel-plugin-transform-dynamic-import": "2.0.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.12"
"babel-plugin-transform-react-remove-prop-types": "0.4.13"
}
}

View File

@@ -16,6 +16,6 @@
"index.js"
],
"devDependencies": {
"jest": "22.4.1"
"jest": "22.4.3"
}
}

View File

@@ -16,7 +16,7 @@
"eslint-plugin-flowtype": "^2.34.1",
"eslint-plugin-import": "^2.6.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.7.0"
"eslint-plugin-react": "^7.8.2"
},
"dependencies": {
"confusing-browser-globals": "^1.0.0"

View File

@@ -22,10 +22,10 @@ class InterpolateHtmlPlugin {
}
apply(compiler) {
compiler.plugin('compilation', compilation => {
compilation.plugin(
'html-webpack-plugin-before-html-processing',
(data, callback) => {
compiler.hooks.compilation.tap('InterpolateHtmlPlugin', compilation => {
compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tap(
'InterpolateHtmlPlugin',
data => {
// Run HTML through a series of user-specified string replacements.
Object.keys(this.replacements).forEach(key => {
const value = this.replacements[key];
@@ -34,7 +34,6 @@ class InterpolateHtmlPlugin {
value
);
});
callback(null, data);
}
);
});

View File

@@ -18,70 +18,72 @@ class ModuleScopePlugin {
apply(resolver) {
const { appSrcs } = this;
resolver.plugin('file', (request, callback) => {
// Unknown issuer, probably webpack internals
if (!request.context.issuer) {
return callback();
}
if (
// If this resolves to a node_module, we don't care what happens next
request.descriptionFileRoot.indexOf('/node_modules/') !== -1 ||
request.descriptionFileRoot.indexOf('\\node_modules\\') !== -1 ||
// Make sure this request was manual
!request.__innerRequest_request
) {
return callback();
}
// Resolve the issuer from our appSrc and make sure it's one of our files
// Maybe an indexOf === 0 would be better?
if (
appSrcs.every(appSrc => {
const relative = path.relative(appSrc, request.context.issuer);
// If it's not in one of our app src or a subdirectory, not our request!
return relative.startsWith('../') || relative.startsWith('..\\');
})
) {
return callback();
}
const requestFullPath = path.resolve(
path.dirname(request.context.issuer),
request.__innerRequest_request
);
if (this.allowedFiles.has(requestFullPath)) {
return callback();
}
// Find path from src to the requested file
// Error if in a parent directory of all given appSrcs
if (
appSrcs.every(appSrc => {
const requestRelative = path.relative(appSrc, requestFullPath);
return (
requestRelative.startsWith('../') ||
requestRelative.startsWith('..\\')
);
})
) {
callback(
new Error(
`You attempted to import ${chalk.cyan(
request.__innerRequest_request
)} which falls outside of the project ${chalk.cyan(
'src/'
)} directory. ` +
`Relative imports outside of ${chalk.cyan(
'src/'
)} are not supported. ` +
`You can either move it inside ${chalk.cyan(
'src/'
)}, or add a symlink to it from project's ${chalk.cyan(
'node_modules/'
)}.`
),
request
resolver.hooks.file.tapAsync(
'ModuleScopePlugin',
(request, contextResolver, callback) => {
// Unknown issuer, probably webpack internals
if (!request.context.issuer) {
return callback();
}
if (
// If this resolves to a node_module, we don't care what happens next
request.descriptionFileRoot.indexOf('/node_modules/') !== -1 ||
request.descriptionFileRoot.indexOf('\\node_modules\\') !== -1 ||
// Make sure this request was manual
!request.__innerRequest_request
) {
return callback();
}
// Resolve the issuer from our appSrc and make sure it's one of our files
// Maybe an indexOf === 0 would be better?
if (
appSrcs.every(appSrc => {
const relative = path.relative(appSrc, request.context.issuer);
// If it's not in one of our app src or a subdirectory, not our request!
return relative.startsWith('../') || relative.startsWith('..\\');
})
) {
return callback();
}
const requestFullPath = path.resolve(
path.dirname(request.context.issuer),
request.__innerRequest_request
);
} else {
callback();
}
if (this.allowedFiles.has(requestFullPath)) {
return callback();
}
// Find path from src to the requested file
// Error if in a parent directory of all given appSrcs
if (
appSrcs.every(appSrc => {
const requestRelative = path.relative(appSrc, requestFullPath);
return (
requestRelative.startsWith('../') ||
requestRelative.startsWith('..\\')
);
})
) {
callback(
new Error(
`You attempted to import ${chalk.cyan(
request.__innerRequest_request
)} which falls outside of the project ${chalk.cyan(
'src/'
)} directory. ` +
`Relative imports outside of ${chalk.cyan(
'src/'
)} are not supported. ` +
`You can either move it inside ${chalk.cyan(
'src/'
)}, or add a symlink to it from project's ${chalk.cyan(
'node_modules/'
)}.`
),
request
);
} else {
callback();
}
});
}
}

View File

@@ -38,6 +38,11 @@ module.exports = {
},
// ...
plugins: [
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: path.resolve('public/index.html'),
}),
// Makes the public URL available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
new InterpolateHtmlPlugin({
@@ -45,11 +50,6 @@ module.exports = {
// You can pass any key-value pairs, this was just an example.
// WHATEVER: 42 will replace %WHATEVER% with 42 in index.html.
}),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: path.resolve('public/index.html'),
}),
// ...
],
// ...
@@ -198,11 +198,11 @@ var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
var compiler = webpack(config);
compiler.plugin('invalid', function() {
compiler.hooks.invalid.tap('invalid', function() {
console.log('Compiling...');
});
compiler.plugin('done', function(stats) {
compiler.hooks.done.tap('done', function(stats) {
var rawMessages = stats.toJson({}, true);
var messages = formatWebpackMessages(rawMessages);
if (!messages.errors.length && !messages.warnings.length) {

View File

@@ -17,17 +17,15 @@ class WatchMissingNodeModulesPlugin {
}
apply(compiler) {
compiler.plugin('emit', (compilation, callback) => {
var missingDeps = compilation.missingDependencies;
compiler.hooks.emit.tap('WatchMissingNodeModulesPlugin', compilation => {
var missingDeps = Array.from(compilation.missingDependencies);
var nodeModulesPath = this.nodeModulesPath;
// If any missing files are expected to appear in node_modules...
if (missingDeps.some(file => file.indexOf(nodeModulesPath) !== -1)) {
if (missingDeps.some(file => file.includes(nodeModulesPath))) {
// ...tell webpack to watch node_modules recursively until they appear.
compilation.contextDependencies.push(nodeModulesPath);
compilation.contextDependencies.add(nodeModulesPath);
}
callback();
});
}
}

View File

@@ -131,7 +131,7 @@ function createCompiler(webpack, config, appName, urls, useYarn) {
// recompiling a bundle. WebpackDevServer takes care to pause serving the
// bundle, so if you refresh, it'll wait instead of serving the old one.
// "invalid" is short for "bundle invalidated", it doesn't imply any errors.
compiler.plugin('invalid', () => {
compiler.hooks.invalid.tap('invalid', () => {
if (isInteractive) {
clearConsole();
}
@@ -142,7 +142,7 @@ function createCompiler(webpack, config, appName, urls, useYarn) {
// "done" event fires when Webpack has finished recompiling the bundle.
// Whether or not you have warnings or errors, you will get this event.
compiler.plugin('done', stats => {
compiler.hooks.done.tap('done', stats => {
if (isInteractive) {
clearConsole();
}

View File

@@ -40,29 +40,29 @@
"dependencies": {
"@babel/code-frame": "7.0.0-beta.46",
"address": "1.0.3",
"browserslist": "2.11.3",
"chalk": "2.3.0",
"cross-spawn": "5.1.0",
"browserslist": "3.2.6",
"chalk": "2.4.1",
"cross-spawn": "6.0.5",
"detect-port-alt": "1.1.6",
"escape-string-regexp": "1.0.5",
"filesize": "3.5.11",
"filesize": "3.6.1",
"find-pkg": "1.0.0",
"global-modules": "1.0.0",
"globby": "7.1.1",
"globby": "8.0.1",
"gzip-size": "4.1.0",
"inquirer": "5.0.0",
"inquirer": "5.1.0",
"is-root": "1.0.0",
"opn": "5.2.0",
"opn": "5.3.0",
"pkg-up": "2.0.0",
"react-error-overlay": "^4.0.0",
"recursive-readdir": "2.2.1",
"recursive-readdir": "2.2.2",
"shell-quote": "1.6.1",
"sockjs-client": "1.1.4",
"strip-ansi": "4.0.0",
"text-table": "0.2.0"
},
"devDependencies": {
"jest": "22.4.1"
"jest": "22.4.3"
},
"scripts": {
"test": "jest"

View File

@@ -36,31 +36,32 @@
"anser": "1.4.6",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^8.2.2",
"babel-jest": "^22.4.1",
"babel-jest": "^22.4.3",
"babel-loader": "^8.0.0-beta.0",
"babel-preset-react-app": "^3.1.1",
"chalk": "^2.1.0",
"chokidar": "^2.0.0",
"cross-env": "5.1.3",
"eslint": "4.15.0",
"chalk": "^2.3.2",
"chokidar": "^2.0.2",
"cross-env": "5.1.4",
"eslint": "4.19.1",
"eslint-config-react-app": "^2.1.0",
"eslint-plugin-flowtype": "2.41.0",
"eslint-plugin-import": "2.8.0",
"eslint-plugin-flowtype": "2.46.1",
"eslint-plugin-import": "2.9.0",
"eslint-plugin-jsx-a11y": "6.0.3",
"eslint-plugin-react": "7.7.0",
"eslint-plugin-react": "7.8.2",
"flow-bin": "^0.63.1",
"html-entities": "1.2.1",
"jest": "22.4.1",
"jest-fetch-mock": "1.2.1",
"jest": "22.4.3",
"jest-fetch-mock": "1.5.0",
"object-assign": "4.1.1",
"promise": "8.0.1",
"raw-loader": "^0.5.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"rimraf": "^2.6.1",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"rimraf": "^2.6.2",
"settle-promise": "1.0.0",
"source-map": "0.5.6",
"webpack": "^3.6.0"
"uglifyjs-webpack-plugin": "1.2.5",
"webpack": "^4.8.1"
},
"jest": {
"setupFiles": [

View File

@@ -8,8 +8,10 @@
const path = require('path');
const webpack = require('webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
entry: './src/iframeScript.js',
output: {
path: path.join(__dirname, './lib'),
@@ -43,6 +45,24 @@ module.exports = {
},
],
},
optimization: {
minimizer: [
// This code is embedded as a string, so it would never be optimized
// elsewhere.
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
comparisons: false,
},
output: {
comments: false,
ascii_only: false,
},
},
}),
],
},
plugins: [
new webpack.DefinePlugin({
// We set process.env.NODE_ENV to 'production' so that React is built
@@ -51,17 +71,5 @@ module.exports = {
// This prevents our bundled React from accidentally hijacking devtools.
__REACT_DEVTOOLS_GLOBAL_HOOK__: '({})',
}),
// This code is embedded as a string, so it would never be optimized
// elsewhere.
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
comparisons: false,
},
output: {
comments: false,
ascii_only: false,
},
}),
],
};

View File

@@ -9,6 +9,7 @@
const path = require('path');
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
entry: './src/index.js',
output: {
path: path.join(__dirname, './lib'),
@@ -34,4 +35,14 @@ module.exports = {
iframeScript$: path.resolve(__dirname, './lib/iframe-bundle.js'),
},
},
optimization: {
nodeEnv: false,
},
node: {
fs: 'empty',
process: false,
},
performance: {
hints: false,
},
};

View File

@@ -31,21 +31,6 @@ const publicUrl = '';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
const postCSSLoaderOptions = {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
flexbox: 'no-2009',
}),
],
};
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
@@ -61,8 +46,21 @@ const getStyleLoaders = (cssOptions, preProcessor) => {
options: cssOptions,
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: postCSSLoaderOptions,
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
flexbox: 'no-2009',
}),
],
},
},
];
if (preProcessor) {
@@ -75,6 +73,7 @@ const getStyleLoaders = (cssOptions, preProcessor) => {
// It is focused on developer experience and fast rebuilds.
// The production configuration is different and lives in a separate file.
module.exports = {
mode: 'development',
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebook/create-react-app/issues/343.
devtool: 'cheap-module-source-map',
@@ -116,6 +115,18 @@ module.exports = {
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
},
optimization: {
// Automatically split vendor and commons
// https://twitter.com/wSokra/status/969633336732905474
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
splitChunks: {
chunks: 'all',
name: 'vendors',
},
// Keep the runtime chunk seperated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985
runtimeChunk: true,
},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
@@ -335,18 +346,16 @@ module.exports = {
],
},
plugins: [
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In development, this will be an empty string.
new InterpolateHtmlPlugin(env.raw),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
// Add module names to factory functions so they appear in browser profiler.
new webpack.NamedModulesPlugin(),
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In development, this will be an empty string.
new InterpolateHtmlPlugin(env.raw),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env.stringified),
@@ -368,6 +377,7 @@ module.exports = {
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
@@ -377,10 +387,7 @@ module.exports = {
tls: 'empty',
child_process: '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,
},
// Turn off performance processing because we utilize
// our own hints via the FileSizeReporter
performance: false,
};

View File

@@ -13,7 +13,8 @@ const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
@@ -26,9 +27,6 @@ const getClientEnvironment = require('./env');
// Webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
const publicPath = paths.servedPath;
// Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths.
const shouldUseRelativeAssetPaths = publicPath === './';
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
@@ -44,34 +42,6 @@ if (env.stringified['process.env'].NODE_ENV !== '"production"') {
throw new Error('Production builds must have NODE_ENV=production.');
}
// Note: defined here because it will be used more than once.
const cssFilename = 'static/css/[name].[contenthash:8].css';
// ExtractTextPlugin expects the build output to be flat.
// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
// However, our output is structured with css, js and media folders.
// 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('../') }
: {};
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
const postCSSLoaderOptions = {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
flexbox: 'no-2009',
}),
],
sourceMap: shouldUseSourceMap,
};
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
@@ -81,13 +51,28 @@ const sassModuleRegex = /\.module\.(scss|sass)$/;
// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
MiniCssExtractPlugin.loader,
{
loader: require.resolve('css-loader'),
options: cssOptions,
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: postCSSLoaderOptions,
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
flexbox: 'no-2009',
}),
],
sourceMap: shouldUseSourceMap,
},
},
];
if (preProcessor) {
@@ -98,26 +83,14 @@ const getStyleLoaders = (cssOptions, preProcessor) => {
},
});
}
return ExtractTextPlugin.extract(
Object.assign(
{
fallback: {
loader: require.resolve('style-loader'),
options: {
hmr: false,
},
},
use: loaders,
},
extractTextPluginOptions
)
);
return loaders;
};
// This is the production configuration.
// It compiles slowly and is focused on producing a fast and minimal bundle.
// The development configuration is different and lives in a separate file.
module.exports = {
mode: 'production',
// Don't attempt to continue if there are any errors.
bail: true,
// We generate sourcemaps in production. This is slow but gives good results.
@@ -141,6 +114,58 @@ module.exports = {
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/'),
},
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
parse: {
// we want uglify-js to parse ecma 8 code. However, we don't want it
// to apply any minfication steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebook/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
},
mangle: {
safari10: true,
},
output: {
ecma: 5,
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488
ascii_only: true,
},
},
// Use multi-process parallel running to improve the build speed
// Default number of concurrent runs: os.cpus().length - 1
parallel: true,
// Enable file caching
cache: true,
sourceMap: shouldUseSourceMap,
}),
new OptimizeCSSAssetsPlugin(),
],
// Automatically split vendor and commons
// https://twitter.com/wSokra/status/969633336732905474
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
splitChunks: {
chunks: 'all',
name: 'vendors',
},
// Keep the runtime chunk seperated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985
runtimeChunk: true,
},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
@@ -284,28 +309,18 @@ module.exports = {
},
],
},
// The notation here is somewhat confusing.
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader normally turns CSS into JS modules injecting <style>,
// but unlike in development configuration, we do something different.
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
// (second argument), then grabs the result CSS and puts it into a
// separate file in our build process. This way we actually ship
// a single CSS file in production instead of JS code injecting <style>
// tags. If you use code splitting, however, any async bundles will still
// use the "style" loader inside the async code so CSS from them won't be
// in the main CSS file.
// `MiniCSSExtractPlugin` extracts styles into CSS
// files. If you use code splitting, async bundles will have their own separate CSS chunk file.
// By default we support CSS Modules with the extension .module.css
{
test: cssRegex,
exclude: cssModuleRegex,
loader: getStyleLoaders({
importLoaders: 1,
minimize: true,
sourceMap: shouldUseSourceMap,
}),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
@@ -313,12 +328,10 @@ module.exports = {
test: cssModuleRegex,
loader: getStyleLoaders({
importLoaders: 1,
minimize: true,
sourceMap: shouldUseSourceMap,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
}),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
// Opt-in support for SASS. The logic here is somewhat similar
// as in the CSS routine, except that "sass-loader" runs first
@@ -331,12 +344,10 @@ module.exports = {
loader: getStyleLoaders(
{
importLoaders: 2,
minimize: true,
sourceMap: shouldUseSourceMap,
},
'sass-loader'
),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
// Adds support for CSS Modules, but using SASS
// using the extension .module.scss or .module.sass
@@ -345,14 +356,12 @@ module.exports = {
loader: getStyleLoaders(
{
importLoaders: 2,
minimize: true,
sourceMap: shouldUseSourceMap,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
},
'sass-loader'
),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
// The GraphQL loader preprocesses GraphQL queries in .graphql files.
{
@@ -381,12 +390,6 @@ module.exports = {
],
},
plugins: [
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In production, it will be an empty string unless you specify "homepage"
// in `package.json`, in which case it will be the pathname of that URL.
new InterpolateHtmlPlugin(env.raw),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
@@ -404,52 +407,22 @@ module.exports = {
minifyURLs: true,
},
}),
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In production, it will be an empty string unless you specify "homepage"
// in `package.json`, in which case it will be the pathname of that URL.
new InterpolateHtmlPlugin(env.raw),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// 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),
// Minify the code.
new UglifyJsPlugin({
uglifyOptions: {
parse: {
// we want uglify-js to parse ecma 8 code. However, we don't want it
// to apply any minfication steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebook/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
},
mangle: {
safari10: true,
},
output: {
ecma: 5,
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488
ascii_only: true,
},
},
// Use multi-process parallel running to improve the build speed
// Default number of concurrent runs: os.cpus().length - 1
parallel: true,
// Enable file caching
cache: true,
sourceMap: shouldUseSourceMap,
}),
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
new ExtractTextPlugin({
filename: cssFilename,
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
}),
// 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
@@ -503,4 +476,7 @@ module.exports = {
tls: 'empty',
child_process: 'empty',
},
// Turn off performance processing because we utilize
// our own hints via the FileSizeReporter
performance: false,
};

View File

@@ -69,7 +69,7 @@ module.exports = function(proxy, allowedHost) {
// as we specified in the config. In development, we always serve from /.
publicPath: config.output.publicPath,
// WebpackDevServer is noisy by default so we emit custom message instead
// by listening to the compiler events with `compiler.plugin` calls above.
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
quiet: true,
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebook/create-react-app/issues/293

View File

@@ -23,56 +23,57 @@
"dependencies": {
"@babel/core": "7.0.0-beta.46",
"@babel/runtime": "7.0.0-beta.46",
"autoprefixer": "7.2.5",
"autoprefixer": "8.5.0",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "8.2.2",
"babel-jest": "22.4.1",
"babel-eslint": "8.2.3",
"babel-jest": "22.4.3",
"babel-loader": "8.0.0-beta.0",
"babel-plugin-named-asset-import": "^0.1.0",
"babel-preset-react-app": "^3.1.1",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "2.3.0",
"css-loader": "0.28.9",
"dotenv": "5.0.0",
"case-sensitive-paths-webpack-plugin": "2.1.2",
"chalk": "2.4.1",
"css-loader": "0.28.11",
"dotenv": "5.0.1",
"dotenv-expand": "4.2.0",
"eslint": "4.15.0",
"eslint": "4.19.1",
"eslint-config-react-app": "^2.1.0",
"eslint-loader": "1.9.0",
"eslint-plugin-flowtype": "2.41.0",
"eslint-plugin-import": "2.8.0",
"eslint-loader": "2.0.0",
"eslint-plugin-flowtype": "2.46.3",
"eslint-plugin-import": "2.11.0",
"eslint-plugin-jsx-a11y": "6.0.3",
"eslint-plugin-react": "7.7.0",
"extract-text-webpack-plugin": "3.0.2",
"file-loader": "1.1.6",
"eslint-plugin-react": "7.8.2",
"file-loader": "1.1.11",
"fs-extra": "5.0.0",
"graphql": "0.12.3",
"graphql-tag": "2.6.1",
"html-webpack-plugin": "2.30.1",
"graphql": "0.13.2",
"graphql-tag": "2.9.2",
"html-webpack-plugin": "3.2.0",
"identity-obj-proxy": "3.0.0",
"jest": "22.4.1",
"loader-utils": "^1.1.0",
"jest": "22.4.3",
"mini-css-extract-plugin": "^0.4.0",
"object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.10",
"postcss-flexbugs-fixes": "3.3.1",
"optimize-css-assets-webpack-plugin": "^4.0.1",
"postcss-loader": "2.1.5",
"promise": "8.0.1",
"raf": "3.4.0",
"react-dev-utils": "^5.0.0",
"resolve": "1.6.0",
"sass-loader": "7.0.1",
"style-loader": "0.19.1",
"style-loader": "0.21.0",
"svgr": "1.9.2",
"sw-precache-webpack-plugin": "0.11.4",
"thread-loader": "1.1.2",
"uglifyjs-webpack-plugin": "1.1.6",
"url-loader": "0.6.2",
"webpack": "3.10.0",
"webpack-dev-server": "2.11.0",
"webpack-manifest-plugin": "1.3.2",
"whatwg-fetch": "2.0.3"
"sw-precache-webpack-plugin": "0.11.5",
"thread-loader": "1.1.5",
"uglifyjs-webpack-plugin": "1.2.5",
"url-loader": "1.0.1",
"webpack": "4.8.3",
"webpack-dev-server": "3.1.4",
"webpack-manifest-plugin": "2.0.2",
"whatwg-fetch": "2.0.4"
},
"devDependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.3.2",
"react-dom": "^16.3.2"
},
"optionalDependencies": {
"fsevents": "1.2.0"