1.热模块更新
webpack.config.js设置:
entry : ['./src/js/index.js','./src/index.html'],
入口文件inde:x.js监听非入口js文件:
if(module.hot){
module.hot.accept("./print.js",function(){
echo()
})
}
if(module.hot){
module.hot.accept("./test.js",function(){
test1
})
}
2.开发环境代码映射source-map
devtool : 'source-map'
//外部映射:生成额外map文件,内部映射:映射代码写在built.js文件内
//source-map 外部映射,显示错误代码准确信息和详细位置
//inline-source-map 内联映射,显示错误代码准确信息和详细位置
//hidden-source-map 外部映射, 显示错误代码准确信息,显示构建后错误代码位置,不显示源代码错误位置
//eval-source-map 内联映射, 显示错误代码准确信息,显示构建后错误代码位置,显示源代码错误位置(在文件hash值冒号后面),源代码文件会加hash值
//nosources-source-map 外部映射,显示错误代码准确信息和详细位置,不显示任何源代码
//cheap-source-map 外部映射,显示错误代码准确信息和详细位置,只精确到一整行
//cheap-module-source-map 与cheap-source-map类似,会将loader的source-map加入
//速度 eval>inline>cheap... eval-cheap-source-map最快,适合开发环境
//调试友好 source-map
//开发环境最终选择 eval-source-map 或者 eval-cheap-module-source-map
//生产环境下,内联会让代码体积庞大,所以只选外部映射,可选source-map,考虑隐藏源代码可加hidden或者nosources
3.oneOf
优化点: 每个不同类型的文件在loader转换时,遍历时会被module中rules中所有loader命中,设置oneOf后遍历时被一个loader命中的文件不会继续被其他loader命中,相当于break;利用了每个文件只能被一个loader转换;
当需要一个文件被多个loader转换时,在oneOf中保留一个loader配置,其他的放在oneOf外面即可,例如:
rules : [
/*
* 正常情况一个文件只能被一个loader处理;
* 当一个文件被多个loader处理,一定要指定loader执行的先后顺序
* 先执行eslint,再执行babel
*/
{
//js语法规范检查,还需要在packge.json中配置eslintConfig,选择airbnb语法规范
test : /\.js$/,
exclude : /node_modules/,
loader :"eslint-loader",
enforce : "pre", //优先执行
options : {
//自动修复语法不规范
fix : true
}
},
{
oneOf : [
{
test : /\.css$/,
use : [...commonCssLoader]
},
{
test : /\.less$/,
use : [ ...commonCssLoader,"less-loader" ]
},
{
//es6新语法兼容性处理
test : /\.js$/,
exclude : /node_modules/,
loader : 'babel-loader',
options : {
presets : [
[
//兼容简单的es6改进语法
"@babel/preset-env",
{
//按需加载promise,await等新语法
useBuiltIns : 'usage',
corejs : { version : 3 },
targets : {
chrome : "60",
firefox : "50",
ie : "9",
safari : "10",
edge : "17"
}
}
]
]
}
},
{
//解析css内的图片
test : /\.(jpg|png|gif)$/,
generator : {
filename : 'imgs/[hash][ext]'
}
},
{
//解析html内的图片
test : /\.html$/,
use : ["html-loader"]
},
{
//解析其他文件
exclude : /\.(js|css|less|sass|html|jpg|png|gif)$/,
generator : {
filename : "media/[hash][ext]"
}
}
]
},
]
4.生产环境缓存配置
1.babel缓存,只更新改变的浏览器兼容代码,第二次打包的速度更快。
{
//es6新语法兼容性处理
test : /\.js$/,
exclude : /node_modules/,
loader : 'babel-loader',
options : {
presets : [
[
//兼容简单的es6改进语法
"@babel/preset-env",
{
//按需加载promise,await等新语法
useBuiltIns : 'usage',
corejs : { version : 3 },
targets : {
chrome : "60",
firefox : "50",
ie : "9",
safari : "10",
edge : "17"
}
}
]
],
cacheDirectory : true
}
},
2.文件资源缓存,给每个编译文件加个hash值,文件内容变更的时候生成新的编译文件;
存在一个问题,所以文件共用一个hash值,当一个文件更新,其他文件全都会生产新的编译文件
output : {
filename : "js/built[hash:10].js",
path : resolve(__dirname,"build")
},
plugins : [
//以src/index.html文件为html模板文件
new HttpWebpackPlugin({
template : "./src/index.html",
minify : {
collapseWhitespace : true, //压缩html内空格,
removeComments : true //去除html注释
}
}),
new MiniCssExtractPlugin({
filename : "css/built[hash:10].css"
}),
],
chunkhash,如果编译文件来源于同一个chunk,那么他们的hash值是一样的,
chunk定义: 由于上面的例子中,index.css,print.css,test.css都在index.js中被引用,那么他们一个chunk;
所以上面的编译文件用chunkhash的话,当一个文件改变了,其他文件也会生成新的编译文件,因为他们是同一个chunk;
contenthash:根据文件内容生成hash值,不同文件的hash值不一样,当改变一个文件的内容,编译时其他文件不会产生影响;
output : {
filename : "js/built[contenthash:10].js",
path : resolve(__dirname,"build")
},
plugins : [
//以src/index.html文件为html模板文件
new HttpWebpackPlugin({
template : "./src/index.html",
minify : {
collapseWhitespace : true, //压缩html内空格,
removeComments : true //去除html注释
}
}),
new MiniCssExtractPlugin({
filename : "css/built[contenthash:10].css"
}),
],
让代码上线运行更快
5.tree shaking
去除无用代码
前提:1.必须使用es6模块化;2.必须是production环境
optimization: {
//CSS压缩
minimizer: [
new CssMinimizerPlugin(),
],
minimize: true,
},
设置此选项貌似会默认设置开发环境,导致js代码不会压缩,tree-shaking无法执行
默认css文件会被当作无用文件尔不被执行,修改方法:packge.json配置:
"sideEffects" : ["*.css","*.less"]
6.code_split文件分割
拆分文件
1.拆分入口,单入口改多入口:
//多入口,有一个入口就生成一个bundle
entry : {
main : './src/js/index.js',
test2 : './src/js/test2.js'
},
output : {
//[name]根据入口文件名,生成bundle文件名
filename : "js/[name][contenthash:10].js",
path : resolve(__dirname,"build")
},
单页面应用使用单入口,多页面应用使用多入口;
2.设置optimization:
将node_modules中的代码单独打包成一个chunk,如果是多入口共用同一个node_modules也只生成一个node_modules
optimization : {
splitChunks : {
chunks : "all"
}
},
3.在单入口应用下,分割文件
使用import方法引入文件:
import(/* webpackChunkName: 'test2' */"./test2.js").then(res=>{
console.log(res.minus(8,1));
}).catch(err=>{
console.log(err);
})
7.JS文件懒加载
懒加载:当文件需要时加载
预加载:会在js使用之前提前加载文件
document.getElementById("d1").onclick=function(){
import(/* webpackChunkName:'test2', webpackPrefetch:true*/"./test2.js").then(res=>{
console.log(res.minus(101,1));
})
}
正常加载与预加载的区别:
正常加载可以认为是并行加载(同一时间加载多个文件),懒加载是等其他资源加载完毕,浏览器空闲后再加载其他资源
8.PWA-渐进式网络应用开发程序(离线可访问)
npm i workbox-webpack-plugin -D
webpack.config.js配置
const WorkboxWebpackPlugin=require("workbox-webpack-plugin")
plugins : [
//以src/index.html文件为html模板文件
new HttpWebpackPlugin({
template : "./src/index.html",
}),
new WorkboxWebpackPlugin.GenerateSW({
//帮助serviceworker快速启动
clientsClaim : true,
//删除旧的serviceworker,生成一个servicewoker配置文件
skipWaiting : true
})
],
入口文件index.js引入:
注意:需要在服务器环境运行
//注册serviceworker
//处理兼容性问题
if("serviceWorker" in navigator){
window.addEventListener('load',()=>{
//service-worker.js由webpack的workbox-webpack-plugin插件生成
navigator.serviceWorker.register('./service-worker.js').then(()=>{
console.log("sw registed success");
}).catch(error=>{
console.log("sw registed error",error);
})
})
}else{
console.log("no support");
}
9.多进程打包
npm i thread-loader -D
在babel之后引入
有利有弊:进程启动需要600ms,进程通信也有开销;只有工作消耗时间比较长才需要多进程打包
module : {
rules : [
{
//es6新语法兼容性处理
test : /\.js$/,
exclude : /node_modules/,
use : [
//多进程打包
"thread-loader",
{
loader : 'babel-loader',
}
],
}
]
},
详细配置
rules : [
{
//es6新语法兼容性处理
test : /\.js$/,
exclude : /node_modules/,
use : [
//多进程打包
{
loader : "thread-loader",
options : {
workers : 2 //2个进程
}
},
{
loader : 'babel-loader',
}
],
}
]
10.externals
忽略打包项,不生成bundle,一般不将cdn(引用)文件打包成bundle,优化打包速度
//与entry同级
externals : {
//忽略库名--npm包名
jQuery : 'jQuery'
}
11.dll单入口库文件单独打包
webpack.dll.js文件(与webpack.config.js同级):
/*
使用dll技术,对某些库(jquery,react,vue)进行单独打包,
当运行webpack时,默认查找webpack.config.js
需求:需要运行webpack.dll.js文件
webpack --config webpack.dll.js
*/
let {resolve}= require("path")
let Webpack=require("webpack")
module.exports={
entry : {
//最终打包生成的[name]--要打包的库名称
jquery : ['jquery']
},
output : {
filename : '[name].js',
path : resolve(__dirname,"dll"),
library:'[name]_[hash]',
},
plugins : [
//打包生成mainfest.json,提供jquery映射
new Webpack.DllPlugin({
name : '[name]_[hash]', //映射库的暴露内容的名称
path : resolve(__dirname,"dll/mainfest.json")
})
],
mode : "production"
}
webpack.config.js:
npm i add-asset-html-webpack-plugin -D
const { resolve }=require("path")
const HttpWebpackPlugin=require("html-webpack-plugin")
let Webpack=require("webpack")
let AddAssetHtmlWebpackPlugin=require("add-asset-html-webpack-plugin")
module.exports={
entry : './src/js/index.js',
output : {
//[name]根据入口文件名,生成bundle文件名
filename : "js/[name].js",
path : resolve(__dirname,"build")
},
module : {
},
plugins : [
//以src/index.html文件为html模板文件
new HttpWebpackPlugin({
template : "./src/index.html",
}),
//告诉webpack哪些库不参与打包,同时修改使用名称
new Webpack.DllReferencePlugin({
manifest : resolve(__dirname,'dll/mainfast.json')
}),
//将dll文件夹中某个文件打包输出出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath : resolve(__dirname,'dll/jquery.js'),
outputPath : "auto"
})
],
mode : 'production', //生产环境js自动压缩
devServer : {
hot : true
},
}