webpack5详细配置(附带注释)
2021-10-26 本文已影响0人
他爱在黑暗中漫游
- webpack5详细配置,包含基本配置、开发环境配置、生成环境配置、打包优化。
// webpack.config.js
const webpack = require("webpack");
const { resolve } = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
const WorkboxWebpackPlugin = require("workbox-webpack-plugin");
const AddAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
/*
缓存:
babel缓存
cacheDirectory: true
--> 让第二次打包构建速度更快
文件资源缓存
hash: 每次wepack构建时会生成一个唯一的hash值。
问题: 因为js和css同时使用一个hash值。
如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)
chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
问题: js和css的hash值还是一样的
因为css是在js中被引入的,所以同属于一个chunk
contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样
--> 让代码上线运行缓存更好使用
*/
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = "production";
module.exports = {
// webpack配置
// 入口起点
entry: "./src/js/index.js",
// 输出
output: {
// 输入路径
path: resolve(__dirname, "dist"),
// 输出文件名
// filename: 'built.js',
filename: "js/[name].[contenthash:10].js",
// 资源文件地址
assetModuleFilename: "images/[hash:10][ext][query]",
},
module: {
/*
语法检查: eslint-loader eslint
注意:只检查自己写的源代码,第三方的库是不用检查的
设置检查规则:
package.json中eslintConfig中设置~
"eslintConfig": {
"extends": "airbnb-base"
}
airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
*/
rules: [
{
test: /\.css$/i,
use: [
// "style-loader",
// 这个loader取代style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
"css-loader",
// postcss的插件 css兼容性处理
// 在postcss.config.js 中
// module.exports = {
// plugins: [
// //使用postcss插件
// require("postcss-preset-env"),
// ],
// };
// 帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
// "browserslist": {
// // 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
// "development": [
// "last 1 chrome version",
// "last 1 firefox version",
// "last 1 safari version"
// ],
// // 生产环境:默认是看生产环境
// "production": [
// ">0.2%",
// "not dead",
// "not op_mini all"
// ]
// }
"postcss-loader",
],
},
{
test: /\.less$/i,
use: [
// compiles Less to CSSF
"style-loader",
"css-loader",
// 将less文件编译成css文件
// 需要下载 less-loader和less
"less-loader",
],
},
{
test: /\.(jpg|jpeg)$/i,
type: "asset/inline", // 替代url-loader
},
{
test: /\.(png|jpg|gif)$/i,
type: "asset/resource", // 替代file-loader
},
{
test: /\.(png|jpg|gif)$/i,
type: "asset",
// parser: {
// dataUrlCondition: {
// // 图片大小小于10kb,就会被base64处理
// maxSize: 10 * 1024, // 10kb
// },
// },
},
{
test: /\.html$/i,
// 处理html文件的img图片
loader: "html-withimg-loader",
options: {
esModule: false,
},
},
/*
js兼容性处理:babel-loader @babel/core
1. 基本js兼容性处理 --> @babel/preset-env
问题:只能转换基本语法,如promise高级语法不能转换
2. 全部js兼容性处理 --> @babel/polyfill
问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~
3. 需要做兼容性处理的就做:按需加载 --> core-js
*/
{
test: /\.js$/i,
exclude: /node_modules/,
use: [
// {
// loader: 'thread-loader',
// options: {
// workers: 2 // 进程2个
// }
// },
{
loader: "babel-loader",
options: {
// 自动修复eslint的错误
presets: [
[
"@babel/preset-env",
{
// 按需加载
useBuiltIns: "usage",
// 指定core-js版本
corejs: {
version: 3,
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: "60",
firefox: "60",
ie: "9",
safari: "10",
edge: "17",
},
},
],
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true,
},
},
],
},
{
test: /\.js$/i,
exclude: /node_modules/,
// 优先执行
enforce: "pre",
loader: "eslint-loader",
options: {
// 自动修复eslint的错误
fix: true,
},
},
],
},
plugins: [
// webpack 的 output.path 目录中的所有文件将被删除一次,但目录本身不会
// 如果使用 webpack 4+ 的默认配置,<PROJECT_DIR>/dist/ 下的所有内容都将被删除。
new CleanWebpackPlugin(),
// 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
// 需求:需要有结构的HTML文件
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template: "./src/index.html",
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true,
},
}),
new MiniCssExtractPlugin({
// 对输出的css文件进行重命名
filename: "css/boundle.css",
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin(),
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true,
}),
new webpack.ProgressPlugin(),
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变~
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, "dll/manifest.json"),
}),
// 将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, "dll/jquery.js"),
publicPath: "./",
}),
],
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
optimization: {
splitChunks: {
chunks: "all",
// 默认值,可以不写~
/* minSize: 30 * 1024, // 分割的chunk最小为30kb
maxSiza: 0, // 最大没有限制
minChunks: 1, // 要提取的chunk最少被引用1次
maxAsyncRequests: 5, // 按需加载时并行加载的文件的最大数量
maxInitialRequests: 3, // 入口js文件最大并行请求数量
automaticNameDelimiter: '~', // 名称连接符
name: true, // 可以使用命名规则
cacheGroups: {
// 分割chunk的组
// node_modules文件会被打包到 vendors 组的chunk中。--> vendors~xxx.js
// 满足上面的公共规则,如:大小超过30kb,至少被引用一次。
vendors: {
test: /[\\/]node_modules[\\/]/,
// 优先级
priority: -10
},
default: {
// 要提取的chunk最少被引用2次
minChunks: 2,
// 优先级
priority: -20,
// 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
reuseExistingChunk: true
}
}*/
},
// 将当前模块的记录其他模块的hash单独打包为一个文件 runtime
// 解决:修改a文件导致b文件的contenthash变化
runtimeChunk: {
name: (entrypoint) => `runtime-${entrypoint.name}`,
},
minimize: true,
minimizer: [
// 配置生产环境的压缩方案:js和css
new TerserWebpackPlugin({
// 开启多进程打包
parallel: true,
}),
],
},
// externals: {
// // 拒绝jQuery被打包进来
// jquery: 'jQuery'
// },
// 生产环境下会自动压缩js代码
mode: "production",
// 解析模块的规则
resolve: {
// 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
alias: {
$css: resolve(__dirname, "src/css"),
},
// 配置省略文件路径的后缀名
extensions: [".js", ".json", ".jsx", ".css"],
// 告诉 webpack 解析模块是去找哪个目录
modules: [resolve(__dirname, "../../node_modules"), "node_modules"],
},
// devServer
devServer: {
// contentBase: resolve(__dirname, 'dist'),
// 开启HMR功能
// 当修改了webpack配置,新配置要想生效,必须重新webpack服务
hot: true,
compress: false,
// 端口号
port: 3001,
// 域名
host: "localhost",
open: true,
// 服务器代理 --> 解决开发环境跨域问题
proxy: {
// 一旦devServer(5000)服务器接受到 /api/xxx 的请求,就会把请求转发到另外一个服务器(3000)
"/api": {
target: "http://localhost:3000",
// 发送请求时,请求路径重写:将 /api/xxx --> /xxx (去掉/api)
pathRewrite: {
"^/api": "",
},
},
},
},
performance: {
// 入口起点的最大体积,这个参数代表入口加载时候最大体积,将其改为了1M,
maxEntrypointSize: 1000000,
// 此选项根据单个资源体积,控制 webpack 何时生成性能提示,自己将其改成了1M
maxAssetSize: 1000000,
// 属性允许 webpack 控制用于计算性能提示的文件,通过覆盖原有属性,将其改成只对js文件进行性能测试。
assetFilter: function (assetFilename) {
return assetFilename.endsWith(".js");
},
},
devtool: "eval-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:外部
错误代码准确信息 和 源代码的错误位置
module会将loader的source map加入
内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
开发环境:速度快,调试更友好
速度快(eval>inline>cheap>...)
eval-cheap-souce-map
eval-source-map
调试更友好
souce-map
cheap-module-souce-map
cheap-souce-map
--> eval-source-map / eval-cheap-module-souce-map
生产环境:源代码要不要隐藏? 调试要不要更友好
内联会让代码体积变大,所以在生产环境不用内联
nosources-source-map 全部隐藏
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
--> source-map / cheap-module-souce-map
*/
// webpack.dll.js
/*
使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
当你运行 webpack 时,默认查找 webpack.config.js 配置文件
需求:需要运行 webpack.dll.js 文件
--> webpack --config webpack.dll.js
*/
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最终打包生成的[name] --> jquery
// ['jquery'] --> 要打包的库是jquery
jquery: ['jquery'],
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]' // 打包的库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个 manifest.json --> 提供和jquery映射
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射库的暴露的内容名称
path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径
})
],
mode: 'production'
};
// postcss.config.js
module.exports = {
plugins: [
//使用postcss插件
require("postcss-preset-env"),
],
};