Webpack 4 教程 - 6. 增强开发体验
我们今天要涉及到把mode属性设置为development(时的情形)。这会让webpack自动配置成更适合开发(时用)。此外,我们也将涉及到webpack-dev-server和webpack-serve - 其包括了热模块替换(译注:webpack-serve现在已不推荐使用,用好webpack-dev-server就够了,详见https://github.com/webpack-co...)。开始吧!
Webpack 4教程: 一个开发服务器
增强开发体验的一个前置步骤是以观察模式运行webpack,试着以webpack --watch启动,现在,每当你做了些修改,webpack就会重建你的项目且输出相应的信息(译注: 原文是”and outputs he code“,小小疑惑一下)。而Webpack-dev-server就更强大了,做得更多。(使用Webpack-dev-server时)输出文件不是写到磁盘的目标目录中,而是在内存里处理。构建之后,这些输出启动了一个本地服务器。
运行webpack-dev-server
首先要安装
npm install webpack-dev-server
其次在package.json中添加脚本
"scripts": { "build": "webpack", "start": "webpack-dev-sever" }
现在启动它,只需输入 npm start(译注:在前面的教程中,作者写的启动脚本的命令形如npm run build,实际上在较高版本的npm中,可以省略这个run了)。你就会看到下面的信息:
「wds」: Project is running at http://localhost:8080/
剩下的事情就只需你在浏览器中打开http://localhost:8080/了
每当对代码做了些修改,站点就会得到更新(因为重建项目了啊),刷新页面之后,你就会看到这些改变了的效果。
热模块替换
为了使开发体验更佳,可以使用热模块替换来避免总是手动刷新。比如,每当你改变了一些样式,你无需重载整个应用来观察改变的效果。
注意,在教程4中我们用到了MiniCssExtractPlugin这个插件,到写这篇文章的时候为止,MiniCssExtractPlugin还不支持热模块替换。更多信息请参考GitHub issue。因此现在你在开发模式下还需继续要用到style-loader这个加载器。(译注:style-loader的作用就是把你的样式插入到<style>标签中,在开发模式下,输出都是放在内存中,因此把css抽取出来还是放在<style>标签中,都无所谓了,不用考虑太多)正规情况下,webpack-dev-server也是通过同一个配置文件(即webpack.config.js)来运行。能在webpack.config.js中添加一个叫devServer的参数来设置附加的配置选项。我们在其上启用热模块替换。
devServer: { hot: true, }
剩下最后一件事情就是将webpack.HotModuleReplacementPlugin写到plugins属性里。
// webpack.config.js const webpack = require('webpack'); module.exports = { devServer: { hot: true }, plugins: [ new webpack.HotModuleReplacementPlugin() ] }注意启动webpack-dev-server时加上 -hot参数也会加载HotModuleReplacementPlugin插件。你要是不经意加载了两次,可能会给你带来一些麻烦。
现在工作于CSS中已经非常奏效了,但在javascript中,我们还需要进一步。
index.js import { divide } from "./divide"; console.log(`6 / 2 = ${divide(6,2)}`); if(module.hot) { module.hot.accept(); }
// divider.js export function divide(a, b) { return a/b; }
运行module.hot.accept()将使得模块可替换。这也会在它导出的模块身上起效果。上面的代码例子意味着在index.js中运行了accept(),则它导出的divide模块也变成可替换的了。(译注:我们在一些开箱即用的框架中往往看到作者为你配了一个类似dev-client.js的文件,这个文件的作用就是让后面被它导出的模块能够热替换)。
函数module.hot.accept()可以附加配置来运行,如果感兴趣,请参阅文档使用HotModuleReplacementPlugin插件时,如果在输出文件名中用了chunkhash,会碰到问题。因此,最好HotModuleReplacementPlugin只用在开发服务器中(且不使用chunkhash)。
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 } }
webpack-serve
(译注:因为webpack-serve官方已不推荐使用,我们略过这一节的巴拉巴拉)
mode: “development”
在前面的教程中,我们已经涉及了mode为production时的情况。现在我们来看看当其值为development时,对我们做了什么。
DefinePlugin插件
就象前面所说的,这个插件创建全局常量编译时解析。
更多细节讲述请参阅教程5。现在其值是 "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插件
这是在设置mode:"development"时另一个默认加载的内置插件。在使用热模块替换时起作用。由于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插件
NameChunksPlugin插件的作用与NamedModulesPlugin插件有点相似。有了NamedChunksPlugin插件,不但你的模块有了名字,chunks也有了。 当在浏览器中运行应用时,你能在window.webpackJsonp属性中找到它们。
NamedModulesPlugin和NamedChunksPlugin另外一个优势是你无需使用模块id(ids),ids在增删依赖时可能会发生变化。因为ids或名字用在实际输出的文件里,即使你模块的内容没有变化,改变ids或名字也会改变文件的hash。所以使用NamedModulesPlugin和NamedChunksPlugin插件将帮助你更好的应付浏览器缓存机制。我们比较一下输出代码。
// Without NamedModulesPlugin and NamedChunksPlugin (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{ /***/ 6: (...) // divide.js module output code /***/ 7: (...) // substract.js module output code ]);
// Using NamedModulesPlugin and 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: "development"(译注:原文误为production)时还多做了一件事,它通过设置devtool属性为eval来启用源码映射(Source Maps)。
module.exports = { mode: "development", // using mode: "development" attaches the following configuration: devtool: "eval" }
转换,丑化,打包你的代码会让用户(体验)更爽,在这些措施之后,代码变小了,执行变快了。然而调式这些代码变困难了。因此,引入了源码映射机制。它们映射输出代码到源文件,使得调式器用起来更简单及能在源代码中打断点。我们将在接下来的教程中深挖源码映射,但如果你现在就想去定制,请查阅文档。
小结
Webpack是开发现代web应用强有力的工具。它不但优化你的产品代码,也能通过定制的方式来提升开发体验。这一次我们涉及到了运行一个开发服务器和设置mode属性为development。我们也学习了如何使用热模块替换。这些结合起来会大大帮助你更快更容易的开发应用。