由于转战webpack5的写法
将近几年累积的webpack4的部分实用写法作为记录
最后迭代版本(webpack V4.41 webpack-cli V3.31)
基础常量以及基础插件
const webpack = require('webpack')
const path = require('path')
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// css处理以及打包时生成css文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 压缩css
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const addAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
// 用于minimizer
const TerserWebpackPlugin = require('terser-webpack-plugin')
// 设置nodejs环境变量
// process.env.NODE_ENV = 'development'
// MiniCssExtractPlugin复用
const commonCssLoader=[
MiniCssExtractPlugin.loader,
'css-loader',
{
loader:"postcss-loader",
ident: 'postcss',
options:{
postcssOptions: {
//或者将插件引入写在单独的配置js中
config: './postcss.config.js',
// plugins: () => [
// require('postcss-preset-env')()
// ]
}
}
}
]
注(postcss.config.js)
module.exports = {
plugins: [
//使用postcss插件
require('postcss-preset-env')
]
}
derServer
/*
devServer
开发环境的配置
contentBase -->运行代码的目录
watchContentBase --> 监视contentBase 下的所有文件,一旦文件变化就会reload true/false
watchOption --> 忽略文件
compress --> 启动gzip压缩增加速率
port --> 运行端口号
host --> 域名
hot --> HMR热更新功能 true/false
clientLogLevel --> 不显示启动服务器的日志信息 none
quiet --> 除了一些基本启动的信息之外,其他内容都不要显示 true/false
overlay --> 如果出现错误不要全屏提示
proxy --> 服务器代理
*/
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:3009,
hot:true,
clientLogLevel:'none',
quiet:true,
watchOption:{
// 忽略文件
ignored:/node_modules/
},
overlay:false,
proxy:{
'/api':{
target:'http://xxxx',
// 发送请求时 请求路径重写:将/api/xx -->/xx 去掉api
pathRewrite:{
'^/api':''
}
}
}
},
entry
/*
entry:入口起点
1.string --> './src/index.js'
单入口
打包形成一个chunk,输出一个bundle文件
此时的chunk默认名称是main
2.array --> ['./src/index.js','./src/xx.js'],
多入口
所有的入口文件最终只会形成一个chunk,输出出去也只有一个bundle文件
-->只有在HMR功能中让html热更新生效
3.object
多入口
有几个入口文件就形成几个chunk,输出几个bundle文件
此时chunk的名称是key
--> 特殊用法 object中也可以数组格式放入 数组中的文件会放入对应的key bundle文件中
*/
entry: {
index:"./src/index.js"
},
output
output: {
// 文件名称
filename: "./js/[name].[contenthash:10].js",
// 输出文件目录
path: resolve(__dirname,"build"),
// 所有资源引入公共路径前缀 --> 'img/a.jpg' --> '/img/a.jpg'
publicPath:'/',
// 非入口chunk的名称 (import 引入的js文件 )
chunkFilename:'./js/[name].[contenthash:10]_chunk.js',
// 整个库向外暴露的变量名
// library:'[name]',
// 变量名添加到那个环境上
// libraryTarget:'window'
// libraryTarget:'global'
// libraryTarget:'commonjs'
},
optimization
/*
optimization
1-可以将node_module中代码单独打包一个chunk最终输出
2-自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
optimization:{
spliteChunks:{
chunks:'all',
以下配置如果不写则有默认值
minSize:30*1024 分割chunk最小为30kb
maxSize:0 最大没有限制
minChunks:1 要提取的chunk最少被引用1次
maxAsyncRequest:5 按需加载时并行加载文件的最大数量
maxInitialRequest:3 入口js文件最大并行请求数量
automaticNameDelimiter:'~' 名称链接符
name:true 可以使用命名规则
分割chunk的组
cacheGroup:{
node_modules 文件会被打爆到venders 组的chunk中 -->vendors~xxx.js
vendors:{
test:/[\\/]node_modules[\\/]/
priority:-10 优先级为-10
},
default:{
要提取的chunk最少被引用2次
minChunks:2,
priority:-30,
如果当前要打包的模块,和之前已经被提取的模块是同一个 就会复用。而不是重新打包
reuseExistingChunk:true
}
}
}
将当前模块的记录模块的hash单独打包为一个文件runtime
// 解决 修改a文件导致b文件的contenthash变化
runtimeChunk:{
name:entrypoint =>`runtime-${entrypoint.name}`
}
}
*/
optimization:{
// spliteChunks:{
// chunks:'all',
// },
runtimeChunk:{
name:entrypoint =>`runtime-${entrypoint.name}`
},
// 配置生产环境的压缩方案 js和css
minimizer:[
new TerserWebpackPlugin({
// 开启缓存
// cache:true,
// 开启多进程打包
parallel:true,
terserOptions: {
ecma: undefined,
warnings: false,
parse: {},
compress: {
drop_console: true,
drop_debugger: false,
pure_funcs: ['console.log'], // 移除console
},
},
// 启动source-map
// sourceMap:true,
})
]
},
module
/*
module
为webpack下的文件做兼容与优化操作
exclude --> 排除某些目录下的文件
include --> 只检查某些目录下的文件
loader --> arrary|string 多个loader时 使用 use:[loader,loader]
enforce --> 'pre'优先执行 'post'延后执行 不写就是中间执行
options --> loader下的配置
oneOf --> 以下配置只会执行一个
*/
module:{
rules:[
// 语法检查 eslint-loader eslint
// package.json中eslintConfig中设置
// aribnb --> eslint-config-airbnb-base eslint eslint-plugin-import
// js想忽略 输入 eslint-disable-next-line
{
test:/\.js$/,
// 刨除node包
exclude:'/node-modules/',
enforce:'pre',
loader:"eslint-loader",
include:[path.resolve(__dirname,'src')],
options:{
// 自动修复eslint 的错误
fix:true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型的文件
oneOf:[
// css loader
{
test:/\.css$/,
use:[
...commonCssLoader
],
},
// less loader
{
test:/\.less$/,
use:[
...commonCssLoader,
// 需要less-loader 和less
'less-loader',
]
},
// scss loader
{
test:/\.scss$/,
use:[
...commonCssLoader,
'sass-loader'
]
},
// 图片资源
{
test:/\.(png|jpe?g|gif|svg)(\?.*)?$/,
// 需要下载url-loader file-loader
loader:'url-loader',
include: [resolve('static'),resolve('src')],
options:{
// 小于8kb被base64处理
limit:8*1024,
// 关闭es6模块使用commonjs
// esModule:false
// 图片设置名称
name:"njl_[hash:10].[ext]",
outputPath:"images"
}
},
{
test:/\.html$/,
// 处理html中img引入问题
loader:'html-loader'
},
// 打包其他文件
{
// 刨除
exclude:/\.(css|js|html|scss|less|png|jpe?g|gif|svg)$/,
loader:'file-loader',
options:{
name:"other_[hash:10].[ext]",
outputPath:"media"
}
},
// js兼容性处理
// babel-loader @babel/preset-env @babel/core 基本js的兼容 如promise等不能转换
// js全部兼容性处理 --> @babel/polyfill 直接在文件中引用
// 按需加载兼容 -->core-js 用这个 就不介意用 @babel/polyfill
{
test:/\.js$/,
exclude:"/node_modules/",
use:[
/*
thread-loader
开启多线程打包
进程启动大概为600MS,进程通信有开销
只有工作耗时长,才需要打包
*/
{
loader:'thread-loader',
options:{
worker:2 // 设置进程数
}
},
{
loader:"babel-loader",
options:{
// 预设:指示做什么样的兼容性处理
presets:[
[
'@babel/preset-env',
// core.js目前与MiniCssExtractPlugin有冲突
// {
// // 按需加载
// useBuiltIns:'usage',
// // 指定core-js版本
// corejs:{
// version:3
// },
// // 指定兼容性做到哪个版本浏览器
// targets:{
// chrome:"60",
// firefox:"60",
// ie:"9",
// safari:"10",
// edge:"17"
// }
// }
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory:true
}
}
],
},
]
}
]
},
plugins
// 默认创建空的HTML 引入打包输出的资源
new HtmlWebpackPlugin({
// 模板html
template:"./public/index.html",
minify:{
// 移除空格
collapseWhitespace:true,
// 移除注释
removeComments:true
}
}),
new MiniCssExtractPlugin({
filename:"css/main.[contenthahs:10].css"
}),
new optimizeCssAssetsWebpackPlugin(),
/*
通知webpack那些库不参与打包 使用时名称改变
new webpack.DllReferencePlugin({
manifest:resolve(__dirname,'dll/manifest.json')
}),
将文件打包输出去并在html中自动引入资源
new addAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,'dll/jquery')
})
*/
resolve
/*
resolve
解析模块的规则
alias --> 配置解析模块的路径别名
extensions --> 配置省略文件路径的后缀名 ['.js','.json','css','vue','jsx']
modules --> 告诉webpack解析模块是去哪个目录找文件
*/
resolve:{
alias:{
$css:resolve(__dirname,'src/css'),
'@':resolve(__dirname,'src')
},
extensions:['.js','.json','css'],
modules:['node_modules']
}
devtool
devtool:"source-map",
/*
source-map 一种提供源代码到构建后代码映射
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
source-map 外部
错误代码准确信息和源代码错误位置
inline-source-map 内联
错误代码准确信息和源代码错误位置
只生成一个内联source-map
hidden-source-map
错误代码错误原因 没有错误位置不能追踪源代码错误位置,只能看到构建后的错误代码位置(隐藏源代码)
eval-source-map
每一个文件都会生成对应的source-map 都在eval
nosources-source-map 外部
错误代码准确信息,但是没有任何源代码信息 (隐藏源代码)
cheap-source-map 外部
错误代码准确信息和源代码错误位置
只能精确到行 列不行
cheap--module-source-map 外部
*/
webpack中部分部署概念
HMR热部署
/*
HMR 热模块替换
模块打包 不会打包所有模块
css:可以使用HMR
js:默认不使用HMR
html:默认不使用HMR
修改 entry将html文件引入
*/
缓存
缓存:
babel缓存
cacheDirectory:true
--》 让第二次打包构建速度更快
文件资源缓存 (hash|chunkhash|contenthash)
hash:每次webpack构建时会生成一个唯一的hash值
问题:因为js和css同时使用一个hash值
如果重新打包,会导致所有缓存失效
chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunk那么hash值一样
问题:js和css的hash值还是一样的
因为css是在js中呗引入的 ,所以同属于一个chunk
contenthash:根据文件的内容生成hash值。不同文件hash值一定不一样
--》让代码上线运行缓存更好的使用
tree shaking(树摇)(生产环境时直接抛弃无用代码)
/*
tree shaking 去除无用代码
前提: 1.必须使用es6模块化 2.开启production环境
作用: 减少代码体积
package.json中配置
"sideEffects":false 所有代码都没有副作用 (全部可以tree shaking)
问题 : 可能会把css / @babel/polyfill 文件被干掉
"sideEffects":["*.css", "*.less"]
*/