使用 React-hot-loader 3、React-router 4 和 Webpack-hot-middleware 进行 React Hot Reload
React Hot Reload with React-hot-loader 3, React-router 4, and Webpack-hot-middleware
我正在尝试让 React-hot-loader 3 与 React-hot-loader 3、React-router 4 和 Webpack-hot-middleware(最新版本,2.18.2)一起工作。
这是我的 server.js
:
const express = require('express');
const bodyParser = require('body-parser');
const cookiesMiddleware = require('universal-cookie-express');
/* eslint-disable import/no-extraneous-dependencies */
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpackHotServerMiddleware = require('webpack-hot-server-middleware');
/* eslint-enable import/no-extraneous-dependencies */
const clientConfig = require('./webpack.config.dev.client');
const serverConfig = require('./webpack.config.dev.server');
const PORT_NUMBER = process.env.PORT || 3000;
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookiesMiddleware());
app.use(express.static('public'));
const multiCompiler = webpack([clientConfig, serverConfig]);
const clientCompiler = multiCompiler.compilers[0];
app.use(webpackDevMiddleware(multiCompiler, {
publicPath: clientConfig.output.publicPath,
noInfo: true,
stats: { children: false },
}));
app.use(webpackHotMiddleware(clientCompiler));
app.use(webpackHotServerMiddleware(multiCompiler, {
serverRendererOptions: { outputPath: clientConfig.output.path },
}));
app.listen(PORT_NUMBER, () => {
// eslint-disable-next-line no-console
console.log(`Server listening at port ${PORT_NUMBER}`);
});
我的client entry point
:
import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import * as Bundles from './components/Bundles';
import App from './App';
const doRender = () => {
render(
<AppContainer>
<App type="client" />
</AppContainer>,
document.getElementById('content'),
);
};
const splitPoints = window.splitPoints || [];
Promise.all(splitPoints.map(chunk => Bundles[chunk].loadComponent()))
.then(doRender);
if (module.hot) {
module.hot.accept('./App', doRender);
}
.babelrc
:
{
"plugins": [
"transform-decorators-legacy",
"transform-object-rest-spread"
],
"presets": [
["es2015", { "modules": false }],
"react",
"stage-0"
],
"env": {
"development": {
"plugins": ["react-hot-loader/babel"]
},
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}
看起来我遵循了 react-hot-loader's README 的每一步,但每次我更改组件中的一些代码时,我都会在控制台中收到此消息:
[HMR] bundle rebuilding
client.js:207 [HMR] bundle rebuilt in 8218ms
process-update.js:27 [HMR] Checking for updates on the server...
process-update.js:81 [HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
有人无意中发现了这个吗?提前致谢!
编辑:这是我的客户端 webpack 配置:
const path = require('path');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const notifier = require('node-notifier');
const configFileName = './.env.development.json';
let envConfig;
try {
// eslint-disable-next-line import/no-dynamic-require, global-require
envConfig = require(configFileName);
} catch (e) {
envConfig = {};
}
const eslintSettings = {
extends: path.join(__dirname, '.eslintrc.js'),
configFile: path.join(__dirname, '.eslintrc.js'),
emitWarning: true,
cache: true,
};
const babelSettings = {
extends: path.join(__dirname, '.babelrc'),
cacheDirectory: true,
};
const excludes = [
/node_modules(?![/\]@local-package[/\])/,
];
const roots = [
path.join(__dirname, '../../node_modules'),
path.join(__dirname, 'node_modules'),
path.join(__dirname, 'client'),
];
const getCommonCSSLoaders = enableCSSModules => [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: enableCSSModules,
importLoaders: 1,
localIdentName: '[name]_[local]_[hash:base64:3]',
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
ident: 'postcss',
plugins: () => [
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
require('postcss-flexbugs-fixes'),
autoprefixer({
env: 'development',
flexbox: 'no-2009',
}),
],
},
},
];
const rules = [
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: eslintSettings,
},
{
test: /\.js$/,
exclude: excludes,
loader: 'babel-loader',
options: babelSettings,
},
{
test: /\.css$/,
exclude: excludes,
use: [
...getCommonCSSLoaders(true),
],
},
{
test: /\.css$/,
include: excludes,
use: [
...getCommonCSSLoaders(false),
],
},
{
test: /\.scss$/,
exclude: excludes,
use: [
...getCommonCSSLoaders(true),
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /.*\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
name: 'images/[name].[hash].[ext]',
limit: 20000,
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
quality: 80,
},
pngquant: {
quality: '80-90',
},
bypassOnDebug: true,
},
},
],
},
];
const plugins = [
new webpack.LoaderOptionsPlugin({
debug: true,
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new StyleLintPlugin({
configFile: path.join(__dirname, '.stylelintrc.js'),
files: [
'**/*.s?(a|c)ss',
'../shared/**/*.s?(a|c)ss',
],
emitErrors: false,
}),
new webpack.NormalModuleReplacementPlugin(/\/components\/Bundles/, './components/AsyncBundles'),
new webpack.NormalModuleReplacementPlugin(/\/Bundles/, './AsyncBundles'),
new webpack.optimize.CommonsChunkPlugin({
name: 'client',
async: 'common',
children: true,
minChunks: (module, count) => {
if (module.resource && (/^.*\.(css|scss)$/).test(module.resource)) {
return false;
}
return count >= 3 && module.context && !module.context.includes('node_modules');
},
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'client',
children: true,
minChunks: module => module.context && module.context.includes('node_modules'),
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
minChunks: module => module.context && module.context.includes('node_modules'),
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// eslint-disable-next-line func-names
function () {
this.plugin('done', (stats) => {
notifier.notify({
title: 'Webpack : Build Succeeded',
message: `${stats.compilation.errors.length} Error(s) - ${stats.compilation.warnings.length} Warning(s)`,
});
});
this.plugin('failed', () => {
notifier.notify({
title: 'Webpack',
message: 'Build Failed HARD',
});
});
},
];
const config = {
name: 'client',
target: 'web',
devtool: 'inline-source-map',
entry: ['webpack-hot-middleware/client', 'react-hot-loader/patch', './client/src/entry/js/polyfills', './client/src/entry/js/client'],
output: {
filename: 'client/[name].js',
chunkFilename: 'client/chunks/[name].chunk.js',
path: path.join(__dirname, 'public/dist'),
publicPath: '/dist/',
pathinfo: true,
},
module: {
rules,
},
plugins,
resolve: {
modules: roots,
},
resolveLoader: {
modules: roots,
},
node: {
fs: 'empty',
net: 'empty',
tls: 'empty',
},
};
module.exports = config;
可能与您的 webpack.config 文件有关?您的条目中是否设置了热门内容?
const config = {
entry: [
'babel-polyfill',
'react-hot-loader/patch', // activate HMR for React
`webpack-hot-middleware/client?path=http://${HOST}:${PORT}/__webpack_hmr`, // bundle the client for webpack-hot-middleware and connect to the provided endpoint
'./src/client.jsx',
],
我使用 Hapi 作为带有 webpack-hot-middleware 和 webpack-dev-middleware 的服务器时运气更好。这是一个片段
import Webpack from 'webpack';
import HapiWebpackPlugin from 'hapi-webpack-plugin';
const config = require('../../../webpack.config.js'); // eslint-disable-line global-require
const compiler = Webpack(config);
const options = {
assets: {
// webpack-dev-middleware options - https://github.com/webpack/webpack-dev-middleware
index: '/public/index.html',
},
hot: {
// webpack-hot-middleware options - https://github.com/glenjamin/webpack-hot-middleware
},
compiler,
};
server.register({
register: HapiWebpackPlugin,
options,
}, (error) => {
if (error) {
console.error(error);
}
});
如果你想尝试 Hapi,请查看我的hapi-react-hot-loader-example
这是我的全文webpack.config
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const RobotstxtPlugin = require('robotstxt-webpack-plugin').default;
const PORT = process.env.PORT || 3000;
const HOST = process.env.HOST || 'localhost';
const NODE_ENV = process.env.NODE_ENV || 'production';
const isProduction = (NODE_ENV === 'production');
const isDevelopment = (NODE_ENV === 'development');
const config = {
entry: isDevelopment
? [
'babel-polyfill',
'react-hot-loader/patch', // activate HMR for React
`webpack-hot-middleware/client?path=http://${HOST}:${PORT}/__webpack_hmr`, // bundle the client for webpack-hot-middleware and connect to the provided endpoint
'./src/client.jsx',
]
: [
'babel-polyfill',
'./src/client.jsx',
],
resolve: {
extensions: ['.js', '.jsx', '.json'],
},
output: {
path: path.join(__dirname, 'dist/public/'),
filename: isDevelopment
? 'main.js'
: 'assets/scripts/[name].[chunkhash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['css-hot-loader'].concat(
ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {minimize: true},
},
{
loader: 'postcss-loader',
},
],
})
),
},
{
test: /\.jsx?$/,
use: ['babel-loader'],
include: path.join(__dirname, 'src'),
},
],
},
plugins: [
new ProgressBarPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
}),
isDevelopment
? null
: new webpack.optimize.ModuleConcatenationPlugin(),
isDevelopment
? new webpack.HotModuleReplacementPlugin() // enable HMR globally
: null,
isDevelopment
? new webpack.NamedModulesPlugin() // prints more readable module names in the browser console on HMR updates
: null,
isDevelopment
? new webpack.NoEmitOnErrorsPlugin() // do not emit compiled assets that include errors
: null,
new ExtractTextPlugin({
filename: isDevelopment
? 'assets/styles/main.css'
: 'assets/styles/[name].[chunkhash].css',
}),
isDevelopment
? null
: new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: module => /node_modules/.test(module.resource),
}),
isDevelopment
? null
: new webpack.optimize.CommonsChunkPlugin({name: 'manifest'}),
isProduction
? new webpack.optimize.UglifyJsPlugin()
: null,
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src/index.html'),
minify: isProduction ? {collapseWhitespace: true, collapseInlineTagWhitespace: true} : false,
alwaysWriteToDisk: true,
}),
new HtmlWebpackHarddiskPlugin(),
new CopyWebpackPlugin([
{
context: 'src/assets/media',
from: '**/*',
to: 'assets/media',
},
]),
new RobotstxtPlugin({
policy: [
isProduction
? {userAgent: '*', allow: '/'}
: {userAgent: '*', disallow: '/'},
],
}),
].filter(Boolean),
devtool: isProduction
? 'none'
: 'cheap-module-eval-source-map',
performance: {
maxAssetSize: 500000,
},
};
module.exports = config;
我正在尝试让 React-hot-loader 3 与 React-hot-loader 3、React-router 4 和 Webpack-hot-middleware(最新版本,2.18.2)一起工作。
这是我的 server.js
:
const express = require('express');
const bodyParser = require('body-parser');
const cookiesMiddleware = require('universal-cookie-express');
/* eslint-disable import/no-extraneous-dependencies */
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpackHotServerMiddleware = require('webpack-hot-server-middleware');
/* eslint-enable import/no-extraneous-dependencies */
const clientConfig = require('./webpack.config.dev.client');
const serverConfig = require('./webpack.config.dev.server');
const PORT_NUMBER = process.env.PORT || 3000;
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookiesMiddleware());
app.use(express.static('public'));
const multiCompiler = webpack([clientConfig, serverConfig]);
const clientCompiler = multiCompiler.compilers[0];
app.use(webpackDevMiddleware(multiCompiler, {
publicPath: clientConfig.output.publicPath,
noInfo: true,
stats: { children: false },
}));
app.use(webpackHotMiddleware(clientCompiler));
app.use(webpackHotServerMiddleware(multiCompiler, {
serverRendererOptions: { outputPath: clientConfig.output.path },
}));
app.listen(PORT_NUMBER, () => {
// eslint-disable-next-line no-console
console.log(`Server listening at port ${PORT_NUMBER}`);
});
我的client entry point
:
import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import * as Bundles from './components/Bundles';
import App from './App';
const doRender = () => {
render(
<AppContainer>
<App type="client" />
</AppContainer>,
document.getElementById('content'),
);
};
const splitPoints = window.splitPoints || [];
Promise.all(splitPoints.map(chunk => Bundles[chunk].loadComponent()))
.then(doRender);
if (module.hot) {
module.hot.accept('./App', doRender);
}
.babelrc
:
{
"plugins": [
"transform-decorators-legacy",
"transform-object-rest-spread"
],
"presets": [
["es2015", { "modules": false }],
"react",
"stage-0"
],
"env": {
"development": {
"plugins": ["react-hot-loader/babel"]
},
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}
看起来我遵循了 react-hot-loader's README 的每一步,但每次我更改组件中的一些代码时,我都会在控制台中收到此消息:
[HMR] bundle rebuilding
client.js:207 [HMR] bundle rebuilt in 8218ms
process-update.js:27 [HMR] Checking for updates on the server...
process-update.js:81 [HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
有人无意中发现了这个吗?提前致谢!
编辑:这是我的客户端 webpack 配置:
const path = require('path');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const notifier = require('node-notifier');
const configFileName = './.env.development.json';
let envConfig;
try {
// eslint-disable-next-line import/no-dynamic-require, global-require
envConfig = require(configFileName);
} catch (e) {
envConfig = {};
}
const eslintSettings = {
extends: path.join(__dirname, '.eslintrc.js'),
configFile: path.join(__dirname, '.eslintrc.js'),
emitWarning: true,
cache: true,
};
const babelSettings = {
extends: path.join(__dirname, '.babelrc'),
cacheDirectory: true,
};
const excludes = [
/node_modules(?![/\]@local-package[/\])/,
];
const roots = [
path.join(__dirname, '../../node_modules'),
path.join(__dirname, 'node_modules'),
path.join(__dirname, 'client'),
];
const getCommonCSSLoaders = enableCSSModules => [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: enableCSSModules,
importLoaders: 1,
localIdentName: '[name]_[local]_[hash:base64:3]',
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
ident: 'postcss',
plugins: () => [
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
require('postcss-flexbugs-fixes'),
autoprefixer({
env: 'development',
flexbox: 'no-2009',
}),
],
},
},
];
const rules = [
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: eslintSettings,
},
{
test: /\.js$/,
exclude: excludes,
loader: 'babel-loader',
options: babelSettings,
},
{
test: /\.css$/,
exclude: excludes,
use: [
...getCommonCSSLoaders(true),
],
},
{
test: /\.css$/,
include: excludes,
use: [
...getCommonCSSLoaders(false),
],
},
{
test: /\.scss$/,
exclude: excludes,
use: [
...getCommonCSSLoaders(true),
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /.*\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
name: 'images/[name].[hash].[ext]',
limit: 20000,
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
quality: 80,
},
pngquant: {
quality: '80-90',
},
bypassOnDebug: true,
},
},
],
},
];
const plugins = [
new webpack.LoaderOptionsPlugin({
debug: true,
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new StyleLintPlugin({
configFile: path.join(__dirname, '.stylelintrc.js'),
files: [
'**/*.s?(a|c)ss',
'../shared/**/*.s?(a|c)ss',
],
emitErrors: false,
}),
new webpack.NormalModuleReplacementPlugin(/\/components\/Bundles/, './components/AsyncBundles'),
new webpack.NormalModuleReplacementPlugin(/\/Bundles/, './AsyncBundles'),
new webpack.optimize.CommonsChunkPlugin({
name: 'client',
async: 'common',
children: true,
minChunks: (module, count) => {
if (module.resource && (/^.*\.(css|scss)$/).test(module.resource)) {
return false;
}
return count >= 3 && module.context && !module.context.includes('node_modules');
},
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'client',
children: true,
minChunks: module => module.context && module.context.includes('node_modules'),
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
minChunks: module => module.context && module.context.includes('node_modules'),
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// eslint-disable-next-line func-names
function () {
this.plugin('done', (stats) => {
notifier.notify({
title: 'Webpack : Build Succeeded',
message: `${stats.compilation.errors.length} Error(s) - ${stats.compilation.warnings.length} Warning(s)`,
});
});
this.plugin('failed', () => {
notifier.notify({
title: 'Webpack',
message: 'Build Failed HARD',
});
});
},
];
const config = {
name: 'client',
target: 'web',
devtool: 'inline-source-map',
entry: ['webpack-hot-middleware/client', 'react-hot-loader/patch', './client/src/entry/js/polyfills', './client/src/entry/js/client'],
output: {
filename: 'client/[name].js',
chunkFilename: 'client/chunks/[name].chunk.js',
path: path.join(__dirname, 'public/dist'),
publicPath: '/dist/',
pathinfo: true,
},
module: {
rules,
},
plugins,
resolve: {
modules: roots,
},
resolveLoader: {
modules: roots,
},
node: {
fs: 'empty',
net: 'empty',
tls: 'empty',
},
};
module.exports = config;
可能与您的 webpack.config 文件有关?您的条目中是否设置了热门内容?
const config = {
entry: [
'babel-polyfill',
'react-hot-loader/patch', // activate HMR for React
`webpack-hot-middleware/client?path=http://${HOST}:${PORT}/__webpack_hmr`, // bundle the client for webpack-hot-middleware and connect to the provided endpoint
'./src/client.jsx',
],
我使用 Hapi 作为带有 webpack-hot-middleware 和 webpack-dev-middleware 的服务器时运气更好。这是一个片段
import Webpack from 'webpack';
import HapiWebpackPlugin from 'hapi-webpack-plugin';
const config = require('../../../webpack.config.js'); // eslint-disable-line global-require
const compiler = Webpack(config);
const options = {
assets: {
// webpack-dev-middleware options - https://github.com/webpack/webpack-dev-middleware
index: '/public/index.html',
},
hot: {
// webpack-hot-middleware options - https://github.com/glenjamin/webpack-hot-middleware
},
compiler,
};
server.register({
register: HapiWebpackPlugin,
options,
}, (error) => {
if (error) {
console.error(error);
}
});
如果你想尝试 Hapi,请查看我的hapi-react-hot-loader-example
这是我的全文webpack.config
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const RobotstxtPlugin = require('robotstxt-webpack-plugin').default;
const PORT = process.env.PORT || 3000;
const HOST = process.env.HOST || 'localhost';
const NODE_ENV = process.env.NODE_ENV || 'production';
const isProduction = (NODE_ENV === 'production');
const isDevelopment = (NODE_ENV === 'development');
const config = {
entry: isDevelopment
? [
'babel-polyfill',
'react-hot-loader/patch', // activate HMR for React
`webpack-hot-middleware/client?path=http://${HOST}:${PORT}/__webpack_hmr`, // bundle the client for webpack-hot-middleware and connect to the provided endpoint
'./src/client.jsx',
]
: [
'babel-polyfill',
'./src/client.jsx',
],
resolve: {
extensions: ['.js', '.jsx', '.json'],
},
output: {
path: path.join(__dirname, 'dist/public/'),
filename: isDevelopment
? 'main.js'
: 'assets/scripts/[name].[chunkhash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['css-hot-loader'].concat(
ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {minimize: true},
},
{
loader: 'postcss-loader',
},
],
})
),
},
{
test: /\.jsx?$/,
use: ['babel-loader'],
include: path.join(__dirname, 'src'),
},
],
},
plugins: [
new ProgressBarPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
}),
isDevelopment
? null
: new webpack.optimize.ModuleConcatenationPlugin(),
isDevelopment
? new webpack.HotModuleReplacementPlugin() // enable HMR globally
: null,
isDevelopment
? new webpack.NamedModulesPlugin() // prints more readable module names in the browser console on HMR updates
: null,
isDevelopment
? new webpack.NoEmitOnErrorsPlugin() // do not emit compiled assets that include errors
: null,
new ExtractTextPlugin({
filename: isDevelopment
? 'assets/styles/main.css'
: 'assets/styles/[name].[chunkhash].css',
}),
isDevelopment
? null
: new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: module => /node_modules/.test(module.resource),
}),
isDevelopment
? null
: new webpack.optimize.CommonsChunkPlugin({name: 'manifest'}),
isProduction
? new webpack.optimize.UglifyJsPlugin()
: null,
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src/index.html'),
minify: isProduction ? {collapseWhitespace: true, collapseInlineTagWhitespace: true} : false,
alwaysWriteToDisk: true,
}),
new HtmlWebpackHarddiskPlugin(),
new CopyWebpackPlugin([
{
context: 'src/assets/media',
from: '**/*',
to: 'assets/media',
},
]),
new RobotstxtPlugin({
policy: [
isProduction
? {userAgent: '*', allow: '/'}
: {userAgent: '*', disallow: '/'},
],
}),
].filter(Boolean),
devtool: isProduction
? 'none'
: 'cheap-module-eval-source-map',
performance: {
maxAssetSize: 500000,
},
};
module.exports = config;