开发环境
处理css
...
module:{
rules:[
{
test: /\.css$/,
// style-loader生产style标签,使得html可以引入css。
// css-loader,将css翻译成js可以认识的文件
// use是一个数组,调用顺序也是类似栈的调用顺序,先进后出,也就是先右后左,或先下后上。
use:['style-loader','css-loader']
}
]
}
...
处理less
...
module:{
rules:[
{
test: /\.less$/,
// style-loader生产style标签,使得html可以引入css。
// css-loader,将css翻译成js可以认识的文件
// use是一个数组,调用顺序也是类似栈的调用顺序,先进后出,也就是先右后左,或先下后上。
// 需要同时下载less-loader和less2个包
use:['style-loader','css-loader','less-loader']
}
]
}
...
处理html
...
module:{
plugins:[
new HtmlWebpackPlugin(
// 改插件会根据public下的index.hmtl为模板生产index.html输出到dist目录
template:'./public/index.html'
)
]
}
...
处理图片
...
module:{
rules:[
// 默认处理不了html内的图片
{
test: /\.(jpg|png|gif)$/
// 需要下载url-loader和file-loader
use:'url-loader',
options:{
// 图片小于8kb时候,就会被base64处理
// 优点:减少请求数量(减轻服务器压力)
// 缺点:图片体积会变大
limit:8*1024
// 因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
// 所以要关闭url-loader的es6模块化,使用commonjs解析
esModule:false,
// [hash:10]取图片hash的前10位
// [ext]取源文件的拓展名
name:'[hash:10].[ext]',
// 设置输出文件目录
outputPath:'imgs'
}
},
{
test:/\.html$/,
// 处理html文件的img图片(负责引入img,从而能被url-loader处理)
use:'html-loader'
}
]
}
...
处理其他类型文件
例如iconfont的字体文件
...
module:{
rules:[
{
// 排除css/js/html资源
exclude:/\.(css|js|html)$/,
loader:'file-loader',
options:{
name:'[hash:10].[ext]',
outputPath:'media'
}
},
]
}
...
devServer
用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
...
// 特点:只会在内存中编译打包,不会输出到磁盘
// 启动命令npx webpack-dev-server
// 需要安装webpack-dev-server包
devServer:{
contentBase:resolve(__dirname,'build'),
//启动gzip压缩
compress:true,
// 端口号
port:3000,
// 自动打开浏览器
open:true
}
...
生产环境
提取css为单独文件
安装mini-css-extract-plugin
...
module:{
rules:[
{
test:/\.css$/,
use:[
//'style-loader',
// 使用这个loader取代style-loader
// 用来提取js中css为单独文件
MiniCssExtractPlugin.loader
'css-loader'
]
}
]
},
plugins:[
new MiniCssExtractPlugin({
// 指定输出文件位置
filename:'css/build.css'
})
]
...
css兼容性处理
需要安装 postcss postcss-loader postcss-preset-env
postcss-preset-env 帮助postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
// webpack.config.js
...
process.env.NODE_ENV='development'// 为了使用browserslist 的开发环境配置
module:{
rules:[
{
test:/\.css$/,
use:[
//'style-loader',
// 使用这个loader取代style-loader
// 用来提取js中css为单独文件
MiniCssExtractPlugin.loader
'css-loader',
// 需要配置loader 需要这样写
{
loader:'postcss-loader',
options:{
ident:'postcss',
plugins:()=>[
require('postcss-preset-env')
]
}
}
]
}
]
},
plugins:[
new MiniCssExtractPlugin({
// 指定输出文件位置
filename:'css/build.css'
})
]
...
// package.json
...
"browserslist":{
"development":[
"last 1 chrome version",
],
"production":[
">0.2%",
"not dead",
"not op_mini all"
]
}
...
压缩css
optimize-css-assets-webpack-plugin
// webpack.config.js
...
process.env.NODE_ENV='development'// 为了使用browserslist 的开发环境配置
module:{
rules:[
{
test:/\.css$/,
use:[
//'style-loader',
// 使用这个loader取代style-loader
// 用来提取js中css为单独文件
MiniCssExtractPlugin.loader
'css-loader',
// 需要配置loader 需要这样写
{
loader:'postcss-loader',
options:{
ident:'postcss',
plugins:()=>[
require('postcss-preset-env')
]
}
}
]
}
]
},
plugins:[
new MiniCssExtractPlugin({
// 指定输出文件位置
filename:'css/build.css'
}),
new OptimizeCssAssetsWebpackPlugin()
]
...
语法检查
eslint-loader eslint
// webpack.config.js
...
process.env.NODE_ENV='development'// 为了使用browserslist 的开发环境配置
module:{
rules:[
{
//只检查自己的源代码,第三方库不用检查
test:/.js$/,
exclude:/node_modules/,
loader:'eslint-loader',
options:{
//自动化修复eslint错误
fix:true
}
}
]
},
plugins:[
new MiniCssExtractPlugin({
// 指定输出文件位置
filename:'css/build.css'
}),
new OptimizeCssAssetsWebpackPlugin()
]
...
设置规则
package.json中的eslintConfig中设置
推荐airbnb设置
--> eslint-config-airbnb-base eslint eslint-plugin-import
// package.json
...
"eslintConfig":{
"extends":"airbnb-base"
}
...
js兼容性处理
安装 babel-loader @babel/core
基本的js兼容性 @babel/preset-env
全部的js兼容性 @babel/polyfill 缺点 完全兼容,性能差。 4kb-->400kb😂
按需加载 corejs
// webpack.config.js
...
module:{
rules:[
{
test:/\.js$/,
exclude:/node_modules/,
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
{
// 按需加载
useBuiltIns:'usage',
// 指定core-js版本
corejs:{
version:3
},
// 指定兼容性做到哪个版本
target:{
chrome:'60',
ie:'9'
}
}
]
}
}
]
}
js压缩
// webpack.config.js
...
// 生产环境自动压缩js
// 自带uglifyjsPlugin
mode:'production'
...
html压缩
// webpack.config.js
...
plugins:[
new HtmlWebPackPlugin({
template:'./src/index.html',
minify:{
// 移除空格
collapseWhitespace:true,
// 移除注释
removeComments:true
}
})
]
...
loader优先执行
eslint 和babel都是对js进行处理,先执行babel再执行eslint,可能会有问题:babel转译js后,eslint进行语法检查,可能就会报错。
所以eslint要先于babel执行,方法如下:
rules:[
{
test:'/\js$/',
...
enforce:'pre'
}
]
只要在loader中,添加enforce为‘pre’即可。
详见 Rule.enforce
webpack优化配置
HMR
作用:一个模块发生变化。只会重新打包这个模块,提升构建速度
开启:devServer中 hot设置为true
样式文件:可以使用hmr功能:因为style-loader内部实现了Hmr功能。这也是为什么开发环境使用style-loader而线上环境为了性能使用MiniCssExtractPlugin的原因
js文件:默认没有hmr功能
html文件:默认没有hmr功能,同时导致问题:html文件不能热更新了(不需要hmr功能)
解决:修改entry入口,将html文件引入 entry:['./src/js/index.js','./src/index.html']
OneOf
默认情况下 ,文件回经历所有的loader,
所以优化点就是,被其中一个处理过后,就不会继续匹配剩下的loader
rules:[
oneOf:[
...loaders
]
]
source map
source-map :[inline-|hidden=|eval-][nosources-][cheap-[module-]]source-map
...
devtool:'source-map'
...
开发环境下我会选择 eval-cheap-module-source-map。
缓存
babel缓存
...
{
test:/\.js$/,
exclude:/node_modules/,
loader:'babel-loader',
options:{
...
// 开启缓存
cacheDirectory:true
}
}
文件缓存
文件服务器(例如nginx)添加一个缓存header
问题:重新部署的文件,没法立即被展示出来,用户还是用的是缓存文件
hash
输出文件加一个hash值
output js/build.[hash:10].js
问题:因为js和css同时使用一个hash值,如果重新打包,会导致所有缓存失效
chunkhash
输出文件加一个chunkhash值
output js/build.[chunkhash:10].js
如果打包来自同一个chunk,那么hash值一样
问题:js和csshash还是一样
因为css是js引入的,所以是同一个chunk
contenthash:
根据文件内容生产hash,不同文件hash不一样
output js/build.[contenthash:10].js
最优方法✅
多进程打包
安装thread-loader
一般给babel-loader用
在babel-loader前加一个 thread-loader
弊端:
进程启动大概600ms,进程通信也有开销
只有工作耗时时间比较长,才需要多进程打包
// webpack.config.js
...
module:{
rules:[
{
loader:'thread-loader',
options:{
workers:2 //进程2个
}
},
{
test:/\.js$/,
exclude:/node_modules/,
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
{
// 按需加载
useBuiltIns:'usage',
// 指定core-js版本
corejs:{
version:3
},
// 指定兼容性做到哪个版本
target:{
chrome:'60',
ie:'9'
}
}
]
}
}
]
}
externals
有些文件不需要被打包,需要通过cdn形式加载,需要被webpack忽略
// webpack.config.js
externals:{
//忽略库名:忽略npm包名
jquery:'jQuery'
}
code split
将node_module的文件和自己代码 分开打包
//webpack.config.js
optimization:{
splitChunks:{
chunks:'all'
}
}
自己代码分开打包
import动态导入语法:能将摸狗文件大度打包
document.getElementById('btn').onclick = function(){
import(/*webpackChunkName:'test'*/,'./test').then(({num})=>{
console.log(num(4,5))
})
}
懒加载 预加载
普通模式:
import {num} from './test
document.getElementById('btn').onclick = function(){
console.log(num(4,5))
}
懒加载:
document.getElementById('btn').onclick = function(){
import(/*webpackChunkName:'test'*/,'./test').then(({num})=>{
console.log(num(4,5))
})
}
预加载:
document.getElementById('btn').onclick = function(){
import(/*webpackChunkName:'test',webpackPrefetch:true */,'./test').then(({num})=>{
console.log(num(4,5))
})
}
区别:
懒加载:当文件需要时候才加载
预加载:在使用之前,提前加载(有兼容性问题,ie和移动端不行)
正常加载可以认为是并行加载(同一时间加载多个文件)
预加载:等其他资源加载完毕了,浏览器空闲了,再偷偷加载
tree-shaking
去除无用代码
前提:1、必须使用es6模块化
2、开启production环境
dll
对某些库(第三方库,react、vue、jquery)进行单独打包
运行 指令 weboack --config webpack.dll.js
// webpack.dll.js
entry:{
jquery:['jquery']
},
output:{
filename:'[name].js',
path:resolve(__dirname,'dll'),
library:'[name]_[hash]'
},
plugins:[
new webpack.DllPlugin({
name:'[name]_[hash]',
path:resolve(__dirname,'dll/manifest.json')
})
]
使用dll
安装 add-asset-html-webpack-webpack-plugin
// webpack.config.js
...
plugins:[
new webpack.DllReferencePlugin({
manifest:resolve(__dirname,'dll/manifest.json')
}),
// 告诉webpack不用打包的文件 位置在哪
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,'dll/jquery.js')
})
]