webpack5提升打包构建速度(四)
1、SourceMap:找到映射后源代码出错位置
SourceMap(源代码映射)是一个用来生成源代码与构建后代码一一映射的文件的方案。
它会生成一个 xxx.map 文件,里面包含源代码和构建后代码每一行、每一列的映射关系。当构建后代码出错了,会通过 xxx.map 文件,从构建后代码出错位置找到映射后源代码出错位置,从而让浏览器提示源代码文件出错位置,帮助我们更快的找到错误根源。
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/less/index.less":
/*!**********************************************************************************************************!*\
!*** ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/less/index.less ***!
\**********************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".box2 {\\n width: 100px;\\n height: 100px;\\n background-color: deeppink;\\n}\\n\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://webpack5/./src/less/index.less?./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js");
/***/ }),
// 其他省略
打包完代码出错完全找不到哪里出错了,如果在配置文件中配置好属性,就能方便的找到打包后出错的代码所在行。
如何配置?
开发模式下配置:cheap-module-source-map
优点:打包编译速度快,只包含行映射
缺点:没有列映射
module.exports = {
// 其他省略
mode: "development",
devtool: "cheap-module-source-map",
};
生产模式:source-map
优点:包含行/列映射
缺点:打包编译速度更慢
module.exports = {
// 其他省略
mode: "production",
devtool: "source-map",
};
2、HMR/模块热替换(HotModuleReplacement):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面。
如何配置?
在devServer中配置hot:true
module.exports = {
// 其他省略
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了)
},
};
经过上面的设置, css 样式经过 style-loader 处理,已经具备 HMR 功能了。但是 js 还不行。js要经过下面的设置方式:
import count from './js/count'
import sum from './js/sum'
import './css/index.css'
import './css/index.less'
import './css/index.sass'
const result = count(8, 2)
console.log(result, 'result')
console.log(count(8, 2))
console.log(sum(2, 3))
// 判断是否支持HMR功能 这样设置是指这两个js文件更新时,局部刷新内容
if (module.hot) {
module.hot.accept("./js/count.js", function(count) {
const result1 = count(2, 1);
console.log(result1);
});
module.hot.accept("./js/sum.js", function(sum) {
const result2 = sum(5, 6);
console.log(result2);
});
}
上面的写法还是比较麻烦的,之后我们还是会用到loader去处理:vue-loader, react-hot-loader
3、OneOf:匹配上一个 loader, 剩下的就不忽略了。
如何配置?
在module中rules的loader用oneOf全部都包起来。生产模式也是这样配置。
module: {
rules: [{
oneOf: [{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.sass$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
//设置图片打包后的路径
generator: {
filename: 'dist/images/[hash:10][ext][query]'
}
},
]
}],
},
4、Include/Exclude:在对 js 文件处理时,要排除 node_modules 下面的文件。
include:包含,只处理 xxx 文件
exclude:排除,除了 xxx 文件以外其他文件都处理
如何设置
例如 module中这样设置:
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含
loader: "babel-loader",
},
插件中也可以这样设置:
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
}),
]
5、多进程打包:开启电脑的多个进程同时干一件事,速度更快
需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为 600ms 左右开销。
如何设置
我们启动进程的数量就是我们 CPU 的核数。
- 如何获取 CPU 的核数,因为每个电脑都不一样。
// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
- 下载包
npm i thread-loader -D
3.使用
在module的rules中的引入babel-loader的use中添加如下代码
{
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
},
在plugins的new ESLintWebpackPlugin中配置 threads, // 开启多进程
最后在optimization中new TerserPlugin中配置如下设置:
optimization: {
minimize: true,
minimizer: [
// css压缩也可以写到optimization.minimizer里面,效果一样的
new CssMinimizerPlugin(),
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({
parallel: threads // 开启多进程
})
],
},
所以总的module代码配置如下:
module.exports = {
//入口文件
entry: {
index: './src/main.js',
admin: './src/main2.js',
},
//出口文件
output: {
path: undefined, // 开发模式没有输出,不需要指定输出目录
filename: "static/js/[name]main.js", // 将 js 文件输出到 static/js 目录中
clean: true, // 开发模式没有输出,不需要清空输出结果
},
module: {
rules: [{
oneOf: [{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.sass$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
//设置图片打包后的路径
generator: {
filename: 'dist/images/[hash:10][ext][query]'
}
},
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含
use: [{
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
},
},
],
},
]
}],
},
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
// 缓存目录
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
threads, // 开启多进程
}),
],
optimization: {
minimize: true,
minimizer: [
// css压缩也可以写到optimization.minimizer里面,效果一样的
new CssMinimizerPlugin(),
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({
parallel: threads // 开启多进程
})
],
},
//模式
mode: "production",
devtool: "source-map",
}
这个时候再打包试试看,其实目前文件比较小的话,实际打包的速度比之前是慢的,只有文件的内容足够大时,处在一个临界值的时候,才发现用这个方法打包速度大大提高!