为了更好的开发体验,一般都是在watch模式下运行webpack。尝试运行webpack --watch。现在每次进行一些更改时,Webpack都会重新构建重建您的项目代码并输出。Webpack-dev-server可以做到这一点。它不是将文件写入目标目录,而是在内存中处理它们。
运行webpack-dev-server
首先要做的就是安装它。
npm install webpack-dev-server
接下来是将它添加到package.json中的脚本中。
"scripts": {
"build": "webpack",
"start": "webpack-dev-server"
}
现在运行它,只需输入npm start。您将收到如下消息:
「wds」: Project is running at http://localhost:8080/
接下来就是在浏览器中打开http://localhost:8080/。每次对代码进行更改时,网站都会更新,刷新页面后,您可以看到所做的更改。
Hot Module Replacement热更新模块
当您对某些样式进行更改时,无需重新加载整个应用程序即可查看更改。
当您运行webpack-dev-server时,它使用与常规构建相同的配置文件。您可以添加一个参数到webpack.config.js,它允许您提供一些其他选项。它被称为devServer。我们需要它来启用热更新模块。
devServer: {
hot: true,
}
剩下要做的就是添加webpack.HotModuleReplacementPlugin到你的插件。
webpack.config.js
const webpack = require('webpack');
module.exports = {
devServer: {
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
}
要注意的是运行带有--hot标志的的webpack-dev-server也会将HotModuleReplacementPlugin添加到您的插件中。这样您就运行了两次是不可取的。
对于我们的CSS来说,工作起来很有魅力,但是对于javascript来说,它还需要一个额外的步骤。
index.js
import { divide } from "./divide";
console.log(`6 / 2 = ${divide(6,2)}`);
if(module.hot) {
module.hot.accept();
}
divide.js
export function divide(a, b) {
return a/b;
}
运行module.hot.accept()将使模块可替换。这也适用于它导入的所有其他模块。使用上面的代码意味着在index.js中运行accept()也可以使divide模块可替换。函数module.hot.accept()可以通过其他配置运行。如果您感兴趣,请查看文档。
在使用HotModuleReplacementPlugin时,在输出文件名中使用chunkhash时会遇到一些问题。最好只在开发服务器上使用hotmodulereplacementplugin(而不是使用chunkash)。
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDevServer = require.main.filename.includes('webpack-dev-server');
const plugins = [
new HtmlWebpackPlugin({ template: './src/index.html' }),
];
if(isDevServer) {
plugins.push(new webpack.HotModuleReplacementPlugin());
}
module.exports = {
output: {
filename: isDevServer ? '[name].bundle.js' : '[name].[chunkhash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
plugins,
devServer: {
hot: true
}
}
mode: “development”
在Webpack4模式(mode)及production内置优化中,我们已经介绍mode:"production"。这里让我们来看看mode:"development"为我们做了什么。
DefinePlugin
此插件允许您创建在编译时解析的全局常量 。当然它也用于mode:"production"生产模式,有关更详细的说明,请查看这里。
这里的值是"process.env.NODE_ENV": JSON.stringify("development"):
module.exports = {
mode: "development",
// using mode: "development" attaches the following configuration:
plugins: [
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("development")
}),
]
}
NamedModulesPlugin命名模块插件
使用HotModuleReplacementPlugin热更新模块时很有用。由于使用NamedModulesPlugin命名模块插件,我们可以看到被替换模块的相对路径。
[WDS] App updated. Recompiling...
[WDS] App hot update...
[HMR] Checking for updates on the server...
[HMR] Updated modules:
[HMR] - ./src/style.css
[HMR] App is up to date
否则,我们只看到模块的ID,而不是,例如,../src/style.css。
NamedChunksPlugin
它与NamedModulesPlugin有一些类似的用途。多亏了NamedChunksPlugin,不仅您的模块会有一个名称,而且还有块。当应用程序在浏览器中运行时,可以在window.webpackJsonp属性中查找它们。
NamedModulesPlugin和NamedChunksPlugin的另一个优点是,您不再使用可以随着添加和删除依赖项而更改的ID。由于ID或名称在实际输出文件中使用,即使模块的内容没有更改,更改它们也会更改文件的哈希值,使用NamedModulesPlugin和NamedChunksPlugin将帮助您处理浏览器中的缓存。让我们比较一些输出代码。
没有NamedModulesPlugin和NamedChunksPlugin:
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{
/***/ 6:
(...) // divide.js module output code
/***/ 7:
(...) // substract.js module output code
]);
使用NamedModulesPlugin和NamedChunksPlugin:
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["utilities~main"],{
/***/ "./src/utilities/divide.js":
(...) // divide.js module output code
/***/ "./src/utilities/substract.js":
(...) // substract.js module output code
]);
Devtool
mode: "production" 中它通过将devtool的值设置为eval来启用源映射。
module.exports = {
mode: "development",
// using mode: "development" attaches the following configuration:
devtool: "eval"
}
代码经历了Transpiling, uglifying 和 bundling之后会更小并且性能更好。但调试这样的代码确实很困难。因此,引入Source Maps。它们将输出代码映射到源文件。多亏了这一点,您可以更轻松地使用调试器并在查看实际代码时设置断点,而不是提供给浏览器的断点。更多请查看文档。