Webpack的打包过程?Webpack的 vendor 和model 有什么区别吗?Webpack 的 loader的作用?Webpack loader 和 plugin 的区别Webpack 做过哪些优化手段?有哪些优化手段?Webpack 插件的执行顺序(加载机制)?Webpack中怎么实现组件异步加载?Webpack如何配置压缩代码?压缩了什么?使用tree-shaking需要注意什么? 性能优化 ★★ 开发环境性能优化 打包构建速度优化 HMR(Hot Module Replacement) 模块热替换只重新构建发生变化的模块 代码调试优化,出错了告诉出错的源代码在哪里 source-map 提供源代码到构建后代码映射的技术 生产环境性能优化 打包构建速度优化 oneOf 找到一个loader就不会继续遍历了babel缓存 第二次构建时,会读取之前的缓存,只重新构建变化的文件tree shaking 去除没有使用的代码,减少代码体积,减少程序执行时间多进程打包externals 让某些库不打包,通过link引入dll 让某些库不打包(把库单独先打包好),后面直接用 (代码分为node_modules别人的库,和源代码,源代码可以通过import拆分打包,node_modules可以通过dll拆分打包) 代码运行的性能优化 文件资源缓存(hash-chunkhash-contenthash)tree shaking 去除没有使用的代码,减少代码体积,减少程序执行时间code split 代码分割懒加载/预加载pwa 离线也可以访问 开发环境性能优化 打包构建速度优化 HMRwebpack内容比较杂乱,先整理面试题,在学习的时候可以抓住重点。
HMR:hot module replacement 热模块替换
作用:一块发生变化,只会重新打包这一个模块,而不是打包所有模块。
webocak-dev-server:实现自动刷新整个页面的功能,从而实时预览代码修改后的结果。
HMR:不需要刷新整个页面,通过重新加载修改过的模块来实现实时预览
在webpack.config.js
里的devServer配置中开启HMR功能
devServer:{
contentBase:resolve(__dirname,"build"),
compress:true,
port:3000,
open:true,
//开启HMR功能
//当修改webpack配置,新配置想要生效,必须重启服务器。
hot:true
}
只有在通过devServer启动webpack时,配置文件里的devServer才会生效,因为这些参数所对应的功能都是devServer提供的,webpack本事并不认识devServer的配置项。
启动devServer指令为:npx webpack-dev-server
不同文件的说明
HTML文件:默认不使用HMR功能,html不需要做HMR功能同时会导致问题:html文件有修改时不能自动刷新整个页面。
解决办法:修改entry入口,将html文件引入之后html可以热更新了,但是仍然不能使用HMR功能。
module.exports={
entry:['./src/js/index.js','./src/index.html']
}
样式文件:可以使用HMR功能是因为style-loader内部实现了,所以在开发环境可以使用style-loader(可以使用HMR优化打包构建速度),而在生产环境为了把 css单独提取成一个文件就不使用了。js文件:默认不能使用HMR功能、如果需要使用HMR功能,需要修改js代码,让使用者触发热模块,添加支持HMR功能的代码。(不适用过于麻烦)
HRM功能只能处理非入口文件的js,入口文件一旦更新会重新引入其他模块,其他模块会重新执行
//使用者主动触发热模块
if(module.hot){
module.hot.accept('本js文件名',fuciton(){
//方法监听print.js文件的变化,一旦发生变化,其他文件默认不会重新打包构建
//这个回调函数,是当该js发生变化的时候需要执行的回调函数
})
}
代码调试优化 source-map
source-map:**提供源代码到构建后代码映射的技术,**如果构建后代码出错了,会通过映射追踪到源代码错误。
module.exports = {
//.....
devtool:"source-map"
}
devtool参数可选值:[inline-|hidden-|eval-] [nosources-] [cheap-[module]]source-map
可选值分类 内联和外部的区别
1.外部生成了单独的文件,内联没有,嵌入打包输出的文件中
2.内联速度构建更快
3.内联会让输出文件体积变得非常大,所以在生成环境不适用内联。
参数 | 内部/外部 | 补充 | 错误代码提示 | 是否可以追踪源代码的错误位置 |
---|---|---|---|---|
source-map | 外部 | 错误代码准确信息,如:源文件xx文件的xx错误 | √ | |
inline-source-map | 内联 | 只生成一个内联source-map | 错误代码准确信息 | √ |
hidden-source-map | 外部 | 错误代码错误原因,不能追踪到源代码的错误,只能提示到构建后代码的错误位置。 | × 隐藏源代码 | |
eval-source-map | 内联 | 每一个文件都生成对应的source-map,都在eval函数中 | 错误代码准确信息 | √ |
nosources-source-map | 外部 | 错误代码准确信息 | × 隐藏源代码 | |
cheap-source-map | 外部 | 错误代码准确信息 | √ 只精确到行,精确不到列。 | |
cheap-module-source-map | 外部 | module会将loader的source map加入 | 错误代码准确信息 | √ |
开发坏境:速度快,调试更友好。
速度快(eval>inline>cheap>…)eval-cheap-source-map>eval-source-map…
调试友好 source-map cheap-module-source-map
一般使用:eval-source-map
生产环境
× 内联 会让体积变大,所以选择外部
有隐藏需求:hidden-source-map(只隐藏源代码,会提示构建后代码的错误信息) nosources-source-map(全部隐藏)
一般使用:source-map
oneOf:oneOf数组里的loader只会匹配一个,一旦匹配到,则不会在继续匹配下面的loader了。**不能有两个配置处理同一种类型的文件
**,所以之前的两个js处理loader需要有一个放在外部。
比如css文件,我们匹配到css的loader之后可以返回了,不用继续去匹配less、js等loader
module.exports = {
module:{
rules:[
{eslint...},
{ //这里面只会匹配一个loader
oneOf:[{...},{另外一个js...}...]
}
]
}
打包构建速度优化 babel缓存
babel会对js代码进行编译处理,编译成浏览器能够识别的语法。
babe缓存: 第二次构建时,会读取之前的缓存,只重新构建变化的文件。
HMR基于devServer,生产环境不需要devServer
output:{
filename:"js/built.[hash:10].js"
//filename:"js/built.[chunkhash:10].js"
}
//兼容性处理
{
test:/\.js$/,
exclude:/node_modules/,
loader: "babel-loader",
options: {
presets:[//....],
//开启babel缓存
cacheDirectory:true
}
}
代码运行的性能优化 文件资源缓存
文件资源缓存:输出的文件,缓存在浏览器,一定时间内不会重新获取。
解决办法
资源名称添加版本号,当资源名称发生改变时,会重新请求资源。如果没有变才会走缓存。
存在问题:重新打包就会改变hash,即使没有修改的文件。
moudule.exports={
output:{
filename:"js/built.[hash:10].js"
}
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.[hash:10].css'
})
]
}
给资源名添加chunkhash值根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash就一样。
以入口文件构建依赖关系图 --> 引入依赖形成chunk代码块
存在问题
css与js的hash值一样,因为css被打包进了js,所以同属于一个chunk。
moudule.exports={
output:{
filename:"js/built.[chunkhash:10].js"
}
contenthash:**根据文件的内容生成hash值,不同文件的hash值不一样。**内容变化hash值才改变。
moudule.exports={
output:{
filename:"js/built.[contenthash:10].js"
}
tree shaking 去除没有使用的代码,减少代码体积
前提
使用 ES6 规范编写模块代码 ES6的模块依赖关系是确定的,和运行时状态无关生产环境下说明
Tree-Shaking 是一种基于 ES Module 规范的 Dead Code Elimination 技术,它会在运行过程中静态分析模块之间的导入导出,确定 **ESM 模块中哪些导出值未曾被其它模块使用,并将其删除,**以此实现打包产物的优化。
作用
tree shaking:去除没有使用的代码,减少代码体积,减少程序执行时间。
Tree shaking的本质是消除无用的JavaScript代码。
optimization: {
minimize: true // 此项不能设置为false,否者是导致 tree shaking 失效
}
webpack的tree shaking,默认只在 使用 mode 为 “production” 的配置项以启用,但是如果配置了不丑化压缩代码,webpack也会默认不是"production",然后就没开启tree shaking
代码运行的性能优化 code split 代码分割打包生产的一个chunk,拆分成多个文件,可以并行加载,提高加载速度,同时实现按需加载。
第一种:多入口页面例如有两个JS文件就输出两个JS文件
module.exports={
entry:{
//多入口:有一个入口,输出就有一个bundle
main:"./src/js/index.js",
test:"./src/js/test.js"
},
output:{
//[name]取入口文件的key比如main、test
filename:"js/[name].[contenthash:10].js",
path:Resolve(__dirname,"build")
},
plugins:[...],
mode:"production",
}
第二种:配置splitChunks
1.可以将node__mudules中代码单独打包成一个chunk输出(比如使用了jqury?)
2.会自动分析多入口chunk中,有没有公共的文件,如果有会打包成单独的一个chunk不会重复打包
module.exports={
entry:"./src/js/index.js",
output:{...},
plugins:[...],
optimization:{
splitChunks:{
chunks:"all"
}
},
mode:"production",
}
第三种:单页面常用 动态import
通过js代码,让某个文件被单独打包成一个chunk
import动态导入语法能将某个文件单独打包,添加该注释可以设置打包的名字
import(/* webpackChunkName:"test" */ "./test").then().catch()
lazy loading js文件懒加载 与 预加载
懒加载当文件需要用时才加载
预加载等其他资源加载完毕,浏览器空闲了,在偷偷加载资源,ie会有兼容性问题
正常加载可以认为是并行加载,同时加载多个文件
//懒加载,当文件需要用时才加载 ES11的动态import
//仅在点击按钮之后再加载,第二次加载直接从缓存中读取
document.getElementById("btn").onclick=function(){
import("./test").then(({mul})=>{
console.log(mul(4,5));
}).catch()
}
添加webpackPrefetch:true
实现预加载
//预加载,会提前加载在浏览器
document.getElementById("btn").onclick=function(){
import((/* webpackChunkName:"test",webpackPrefetch:true */"./test").then().catch()
}
PWA 离线可访问
PWA:Progressive Web App。渐进式网络开发应用程序(离线可访问)
需要依赖: workbox –> workbox-weboack-plugin
1.安装
npm i workbox-weboack-plugin
2.插件的引入及使用
//引入插件
const WorkboxWeboackPlugin = require('workbox-weboack-plugin');
plugins:[
new WorkboxWeboackPlugin.GenerateSW({//生成一个serviceworker配置文件,
/*
1.帮助serviceworker快速启动
2.删除旧的serviceworker
*/
clientsClaim:true,
skipWaiting:true
})
]
生成serviceworke配置文件后,一般在index.js里面注册serviceworker
//注册serviceworker
//处理兼容性问题
if("serviceWorker" in navigator){
window.addEventListener("load",()=>{
navigator.serviceWorker.register('/service-worker.js') //workbox-weboack-plugin生成/service-worker.js文件
.then(()=>{})
.catch(()=>{})
})
}
可能出现的问题
1.eslit不认识window、navigator全局变量
解决:需要修改package.json中eslintConfig配置
eslintConfig:{
"env":{
"browser":true //支持浏览器端全局变量
}
}
2.sw代码必须运行在服务器上
nodejs
进程启动和进程通信都有开销,工作时间比较长,才需要多进程打包
1.安装依赖thread-loader -D
,
npm i thread-loader -D
2.在babel中使用
{
test:/\.js$/,
exclude:/node_modules/,
usr:[
{
loader:'thread-loader',
options:{
workers:2 //两个进程
}
}, //开启多进程打包
{//...}
]
}
打包构建速度优化 externals 让某些库不打包
externals拒绝打包某资源,自己手动通过link引入
module.exports={
entry:"./src/js/index.js",
output:{...},
plugins:[...],
mode:"production",
externals:{
//库名 -- npm包名
//拒绝jQuery被打包进来,拒绝被打包时需要手动link引进来
jquery:'jQuery'
}
}
打包构建速度优化 DDL 库文件打包
正常情况下node_module会被打包成一个文件
使用dll技术,对某些库(第三方)进行单独打包,生成一个chunk
当运行webpack时,默认查找webpack.config.js 配置文件
需求:需要运行wbpack.dll.js
文件,这个名字可以自己取
解决办法:webpack --config webpack.dll.js
const{ resolve } =require("path");
const webpack = require("webpack");//引入webpack就足够了
module.exports = {
entry:{
//最终打包生成的name为属性名,属性值为要打包的库
jquery:['jquery']
},
output:{
filename:'[name].js',//输出jquery.js
path:resolve(__dirname),'dll',
library:"[name]_[hash]" //打包的库里面向外暴露出去的内容叫什么,打包后的文件 var jQuery_hash值 = ...
},
//以上内容专门用于打包jquery
plugins:[
//打包生成一个 manifest.json --> 提供和jquery映射
new webpack.DllPlugin(
name:'[name]_[hash]',//映射库的暴露的内容名称
path:resolve(__dirname,"dll/manifest.json") //输出文件的路径{"name":"var jQuery_hash值","content":在node_modules下的路径}
})
] ,
mode:"production"
}
打包之后配置webpack.config.js
,这样重复打包webpack.config.js时不再打包jquery库了
//-----webpack.config.js
const webpack = require("webpack");
const AddAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin")
//....
//告诉webpack哪些库不参与打包,同时使用时的名称也要变。所以打包出去的资源没有jQuery
new webpack.DllReferencePlugin({
manifest:resolve(__dirname,"dll/manifest.json")
}),
//需要将之前输出的jquery在html中自动引入该文件
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,"dll/jquery.js")
})
clean-webpack-plugin插件
clean-webpack-plugin:在打包时,先删除原来的再进行打包新的。
1.安装
npm i clean-webpack-plugin -D
2.引入清除文件插件与使用
const CleanWebpackPlugin = require('clean-webpack-plugin');
//使用
plugins:[
//匹配删除的文件
new CleanWebpackPlugin([
'dist', //删除dist文件夹
'build/*.*', //删除build文件夹下的所有文件
],{
//下面可以省略
root: __dirname, //根目录
verbose: true, //开启在控制台输出信息
dry: false //启用删除文件
}),
]
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)