HotModuleReplacement
(HMR/热模块替换)
开发时我们修改了其中一个模块代码,
Webpack
默认会将所有模块全部重新打包编译,速度很慢
所以我们需要做到修改某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度就能很快
使用
HotModuleReplacement
(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面
使用流程
1.基本配置
module.exports ={// 其他省略devServer:{host:"localhost",// 启动服务器域名port:"3000",// 启动服务器端口号open:true,// 是否自动打开浏览器hot:true,// 开启HMR功能(只能用于开发环境,生产环境不需要了)},};
此时
css
样式经过
style-loader
处理,已经具备
HMR
功能了。 但是
js
还不行
配置js
// main.jsimport count from"./js/count";import sum from"./js/sum";// 引入资源,Webpack才会对其打包import"./css/iconfont.css";import"./css/index.css";import"./less/index.less";import"./sass/index.sass";import"./sass/index.scss";import"./styl/index.styl";const result1 =count(2,1);
console.log(result1);const result2 =sum(1,2,3,4);
console.log(result2);// 判断是否支持HMR功能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(1,2,3,4);
console.log(result2);});}
上面这样写会很麻烦,所以实际开发我们会使用其他
loader
来解决。
比如:
vue-loader
,
react-hot-loader
OneOf
打包时每个文件都会经过所有
loader
处理,虽然因为
test
正则原因实际没有处理上,但是都要过一遍,比较慢
使用
OneOf
:顾名思义就是只能匹配上一个
loader
, 剩下的就不匹配了
使用流程
const path =require("path");const ESLintWebpackPlugin =require("eslint-webpack-plugin");const HtmlWebpackPlugin =require("html-webpack-plugin");
module.exports ={entry:"./src/main.js",output:{path:undefined,// 开发模式没有输出,不需要指定输出目录filename:"static/js/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:/\.s[ac]ss$/,use:["style-loader","css-loader","sass-loader"],},{test:/\.styl$/,use:["style-loader","css-loader","stylus-loader"],},{test:/\.(png|jpe?g|gif|webp)$/,type:"asset",parser:{dataUrlCondition:{maxSize:10*1024,// 小于10kb的图片会被base64处理},},generator:{// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename:"static/imgs/[hash:8][ext][query]",},},{test:/\.(ttf|woff2?)$/,type:"asset/resource",generator:{filename:"static/media/[hash:8][ext][query]",},},{test:/\.js$/,exclude:/node_modules/,// 排除node_modules代码不编译loader:"babel-loader",},],},],},plugins:[newESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname,"../src"),}),newHtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname,"../public/index.html"),}),],// 开发服务器devServer:{host:"localhost",// 启动服务器域名port:"3000",// 启动服务器端口号open:true,// 是否自动打开浏览器hot:true,// 开启HMR功能},mode:"development",devtool:"cheap-module-source-map",};
Include/Exclude
开发时我们需要使用第三方的库或插件,所有文件都下载到
node_modules
中了。而这些文件是不需要编译可以直接使用的。
所以我们在对
js
文件处理时,要排除
node_modules
下面的文件
**使用
Include/Exclude
:**
include
包含,只处理
xxx
文件
exclude
排除,除了
xxx
文件以外其他文件都处理
使用流程
const path =require("path");const ESLintWebpackPlugin =require("eslint-webpack-plugin");const HtmlWebpackPlugin =require("html-webpack-plugin");
module.exports ={entry:"./src/main.js",output:{path:undefined,// 开发模式没有输出,不需要指定输出目录filename:"static/js/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:/\.s[ac]ss$/,use:["style-loader","css-loader","sass-loader"],},{test:/\.styl$/,use:["style-loader","css-loader","stylus-loader"],},{test:/\.(png|jpe?g|gif|webp)$/,type:"asset",parser:{dataUrlCondition:{maxSize:10*1024,// 小于10kb的图片会被base64处理},},generator:{// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename:"static/imgs/[hash:8][ext][query]",},},{test:/\.(ttf|woff2?)$/,type:"asset/resource",generator:{filename:"static/media/[hash:8][ext][query]",},},{test:/\.js$/,// exclude: /node_modules/, // 排除node_modules代码不编译include: path.resolve(__dirname,"../src"),// 也可以用包含loader:"babel-loader",},],},],},plugins:[newESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname,"../src"),exclude:"node_modules",// 默认值}),newHtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname,"../public/index.html"),}),],// 开发服务器devServer:{host:"localhost",// 启动服务器域名port:"3000",// 启动服务器端口号open:true,// 是否自动打开浏览器hot:true,// 开启HMR功能},mode:"development",devtool:"cheap-module-source-map",};
Cache
每次打包时
js
文件都要经过
Eslint
检查 和
Babel
编译,速度比较慢。
我们可以缓存之前的
Eslint
检查 和
Babel
编译结果,这样第二次打包时速度就会更快了
**使用
Cache
** : 对
Eslint
检查 和
Babel
编译结果进行缓存
使用流程
const path =require("path");const ESLintWebpackPlugin =require("eslint-webpack-plugin");const HtmlWebpackPlugin =require("html-webpack-plugin");
module.exports ={entry:"./src/main.js",output:{path:undefined,// 开发模式没有输出,不需要指定输出目录filename:"static/js/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:/\.s[ac]ss$/,use:["style-loader","css-loader","sass-loader"],},{test:/\.styl$/,use:["style-loader","css-loader","stylus-loader"],},{test:/\.(png|jpe?g|gif|webp)$/,type:"asset",parser:{dataUrlCondition:{maxSize:10*1024,// 小于10kb的图片会被base64处理},},generator:{// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename:"static/imgs/[hash:8][ext][query]",},},{test:/\.(ttf|woff2?)$/,type:"asset/resource",generator:{filename:"static/media/[hash:8][ext][query]",},},{test:/\.js$/,// exclude: /node_modules/, // 排除node_modules代码不编译include: path.resolve(__dirname,"../src"),// 也可以用包含loader:"babel-loader",options:{cacheDirectory:true,// 开启babel编译缓存cacheCompression:false,// 缓存文件不要压缩},},],},],},plugins:[newESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname,"../src"),exclude:"node_modules",// 默认值cache:true,// 开启缓存// 缓存目录cacheLocation: path.resolve(
__dirname,"../node_modules/.cache/.eslintcache"),}),newHtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname,"../public/index.html"),}),],// 开发服务器devServer:{host:"localhost",// 启动服务器域名port:"3000",// 启动服务器端口号open:true,// 是否自动打开浏览器hot:true,// 开启HMR功能},mode:"development",devtool:"cheap-module-source-map",};
Thead
当项目越来越庞大时,打包速度越来越慢,甚至于需要一个下午才能打包出来代码。这个速度是比较慢的。
我们想要继续提升打包速度,其实就是要提升
js
的打包速度,因为其他文件都比较少。
而对
js
文件处理主要就是
eslint
、
babel
、
Terser
三个工具,所以我们要提升它们的运行速度。
我们可以开启多进程同时处理
js
文件,这样速度就比之前的单进程打包更快了
**使用
Thead
多进程打包**:开启电脑的多个进程同时干一件事,速度更快。
需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为
600ms
左右开销
使用流程
我们启动进程的数量就是我们
CPU
的核数
**1.如何获取
CPU
的核数,因为每个电脑都不一样**
// nodejs核心模块,直接使用const os =require("os");// cpu核数const threads = os.cpus().length;
2.下载包
npm i thread-loader -D
3.使用
const os =require("os");const path =require("path");const ESLintWebpackPlugin =require("eslint-webpack-plugin");const HtmlWebpackPlugin =require("html-webpack-plugin");const MiniCssExtractPlugin =require("mini-css-extract-plugin");const CssMinimizerPlugin =require("css-minimizer-webpack-plugin");const TerserPlugin =require("terser-webpack-plugin");// cpu核数const threads = os.cpus().length;// 获取处理样式的LoadersconstgetStyleLoaders=(preProcessor)=>{return[
MiniCssExtractPlugin.loader,"css-loader",{loader:"postcss-loader",options:{postcssOptions:{plugins:["postcss-preset-env",// 能解决大多数样式兼容性问题],},},},
preProcessor,].filter(Boolean);};
module.exports ={entry:"./src/main.js",output:{path: path.resolve(__dirname,"../dist"),// 生产模式需要输出filename:"static/js/main.js",// 将 js 文件输出到 static/js 目录中clean:true,},module:{rules:[{oneOf:[{// 用来匹配 .css 结尾的文件test:/\.css$/,// use 数组里面 Loader 执行顺序是从右到左use:getStyleLoaders(),},{test:/\.less$/,use:getStyleLoaders("less-loader"),},{test:/\.s[ac]ss$/,use:getStyleLoaders("sass-loader"),},{test:/\.styl$/,use:getStyleLoaders("stylus-loader"),},{test:/\.(png|jpe?g|gif|webp)$/,type:"asset",parser:{dataUrlCondition:{maxSize:10*1024,// 小于10kb的图片会被base64处理},},generator:{// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename:"static/imgs/[hash:8][ext][query]",},},{test:/\.(ttf|woff2?)$/,type:"asset/resource",generator:{filename:"static/media/[hash:8][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:[newESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname,"../src"),exclude:"node_modules",// 默认值cache:true,// 开启缓存// 缓存目录cacheLocation: path.resolve(
__dirname,"../node_modules/.cache/.eslintcache"),
threads,// 开启多进程}),newHtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname,"../public/index.html"),}),// 提取css成单独文件newMiniCssExtractPlugin({// 定义输出文件名和目录filename:"static/css/main.css",}),// css压缩// new CssMinimizerPlugin(),],optimization:{minimize:true,minimizer:[// css压缩也可以写到optimization.minimizer里面,效果一样的newCssMinimizerPlugin(),// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了newTerserPlugin({parallel: threads // 开启多进程})],},// devServer: {// host: "localhost", // 启动服务器域名// port: "3000", // 启动服务器端口号// open: true, // 是否自动打开浏览器// },mode:"production",devtool:"source-map",};
版权归原作者 Luxine. 所有, 如有侵权,请联系我们删除。