带有 webpack-dev-server 的 HMR 不会重新加载 (webpack 4)
HMR with webpack-dev-server doesn't reload (webpack 4)
我正在为静态站点开发我的新 JS 入门程序,我想要一个类似 create-react-app 的架构。我所有的 webpack 配置都基于 create-react-app webpack 配置,但使用的是 Webpack 4。
当我启动 start.js 脚本时,使用 hot: true
选项创建了一个使用节点 API 的新 WebpackDevServer,但是热重载根本不起作用。
这是我的 webpack 配置:
const webpack = require('webpack')
const autoprefixer = require('autoprefixer')
const path = require('path')
const paths = require('./paths')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const getClientEnvironment = require('./env')
// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/'
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = ''
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl)
// 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 = {
mode: process.env.NODE_ENV,
entry: [require.resolve('./polyfills'), paths.appIndexJs],
output: {
pathinfo: true,
filename: 'static/js/bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\/g, '/')
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: ['.js', '.json', '.jsx'],
alias: {
src: path.resolve(paths.appSrc),
locales: path.resolve(paths.appSrc, 'locales'),
app: path.resolve(paths.appSrc, 'app'),
config: path.resolve(paths.appSrc, 'config'),
components: path.resolve(paths.appSrc, 'components'),
values: path.resolve(paths.appSrc, 'values'),
utils: path.resolve(paths.appSrc, 'utils'),
helpers: path.resolve(paths.appSrc, 'utils/helpers')
}
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx)$/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
[
'@babel/preset-react',
{
pragma: 'h'
}
]
],
cacheDirectory: true
}
},
{
loader: 'eslint-loader',
options: { emitWarning: true }
}
],
exclude: /node_modules/,
include: paths.appSrc
},
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
test: /\.scss$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
modules: true,
localIdentName: '[local]___[hash:base64:5]',
importLoaders: 2,
alias: {
src: path.resolve(__dirname, '../src')
}
}
},
{
loader: 'sass-loader',
options: {
includePaths: ['./src'],
data: '@import "config.scss";'
}
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9'
],
flexbox: 'no-2009'
})
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml
}),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin(env.stringified),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
performance: {
hints: false
}
}
这是我的启动脚本:
'use strict'
process.env.BABEL_ENV = 'development'
process.env.NODE_ENV = 'development'
const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const paths = require('../config/paths')
const config = require('../config/webpack.config.dev')
const compiler = webpack(config)
const server = new WebpackDevServer(compiler, {
contentBase: paths.appPublic,
publicPath: config.output.publicPath,
inline: true,
hot: true,
watchContentBase: true,
// quiet: true
historyApiFallback: true,
stats: { colors: true }
})
server.listen(8080, 'localhost', () => {
console.log('Starting server on http://localhost:8080')
})
如果你想测试这个项目,有一个repo on Github。
通过向我的 webpack 开发配置添加两个新的入口点,HMR 正在运行。
入口点现在是:
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/dev-server',
require.resolve('./polyfills'),
paths.appIndexJs
你可以查看参考文献Issue on Github。
我正在为静态站点开发我的新 JS 入门程序,我想要一个类似 create-react-app 的架构。我所有的 webpack 配置都基于 create-react-app webpack 配置,但使用的是 Webpack 4。
当我启动 start.js 脚本时,使用 hot: true
选项创建了一个使用节点 API 的新 WebpackDevServer,但是热重载根本不起作用。
这是我的 webpack 配置:
const webpack = require('webpack')
const autoprefixer = require('autoprefixer')
const path = require('path')
const paths = require('./paths')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const getClientEnvironment = require('./env')
// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/'
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = ''
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl)
// 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 = {
mode: process.env.NODE_ENV,
entry: [require.resolve('./polyfills'), paths.appIndexJs],
output: {
pathinfo: true,
filename: 'static/js/bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\/g, '/')
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: ['.js', '.json', '.jsx'],
alias: {
src: path.resolve(paths.appSrc),
locales: path.resolve(paths.appSrc, 'locales'),
app: path.resolve(paths.appSrc, 'app'),
config: path.resolve(paths.appSrc, 'config'),
components: path.resolve(paths.appSrc, 'components'),
values: path.resolve(paths.appSrc, 'values'),
utils: path.resolve(paths.appSrc, 'utils'),
helpers: path.resolve(paths.appSrc, 'utils/helpers')
}
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx)$/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
[
'@babel/preset-react',
{
pragma: 'h'
}
]
],
cacheDirectory: true
}
},
{
loader: 'eslint-loader',
options: { emitWarning: true }
}
],
exclude: /node_modules/,
include: paths.appSrc
},
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
test: /\.scss$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
modules: true,
localIdentName: '[local]___[hash:base64:5]',
importLoaders: 2,
alias: {
src: path.resolve(__dirname, '../src')
}
}
},
{
loader: 'sass-loader',
options: {
includePaths: ['./src'],
data: '@import "config.scss";'
}
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9'
],
flexbox: 'no-2009'
})
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml
}),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin(env.stringified),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
performance: {
hints: false
}
}
这是我的启动脚本:
'use strict'
process.env.BABEL_ENV = 'development'
process.env.NODE_ENV = 'development'
const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const paths = require('../config/paths')
const config = require('../config/webpack.config.dev')
const compiler = webpack(config)
const server = new WebpackDevServer(compiler, {
contentBase: paths.appPublic,
publicPath: config.output.publicPath,
inline: true,
hot: true,
watchContentBase: true,
// quiet: true
historyApiFallback: true,
stats: { colors: true }
})
server.listen(8080, 'localhost', () => {
console.log('Starting server on http://localhost:8080')
})
如果你想测试这个项目,有一个repo on Github。
通过向我的 webpack 开发配置添加两个新的入口点,HMR 正在运行。
入口点现在是:
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/dev-server',
require.resolve('./polyfills'),
paths.appIndexJs
你可以查看参考文献Issue on Github。