一个Webpack配置文件的构成
- mode 输出模式
- entry 入口文件
- output 输出位置配置
- module.rules 不同源码模块的加载规则配置(即使用不同loader加载不同模块)
- plugins loader以外的工作配置
- devServer 配置开发服务器(代理+热更新)
- optimization 优化配置
- optimization.minify 文件压缩
- optimization.splitChunks 分包配置
一个完整的webpack.config.js配置案例
具体细节可查阅: Webpack官方文档
/* 引入各种功能插件 */
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
/* 打包模式(生产模式下会自动开启Tree-Shaking) */
// mode: "development",
mode: "production",
/* 入口JS文件 每个入口文件对应着一棵依赖树 */
entry: {
index: "../src/js/index.js",
other: "../src/js/other.js",
},
/* bundle输出位置 */
/* dev */
output: {
// 根据js文件内容不同 生成不同的哈希 用于判断是否应该重新下载该文件
filename: "[name].[hash8].js",
// bundle输出文件夹
path: "D:/phpStudy/WWW/jdzb_client_js",
},
/* prod */
// output: {
// filename: "[name].[contenthash:8].js", // 打包代码时,加上 hash 戳
// path: wwwPath,
// // 如果有CDN
// // publicPath: 'http://cdn.abc.com'
// // 异步chunk输出位置 以流水号命名
// chunkFilename: "async/[id].js",
// },
/* 使用不同【loader+具体配置】去编译加载不同【源码模块】 */
module: {
rules: [
/* common */
/* 编译加载JS模块 */
{
// 找到所有的js文件
test: /\.js$/, // 使用babel-loader做ES高级语法向ES5的转换
use: ["babel-loader"] /* 以下两个只需要写一个 */,
// 查找范围仅限于src目录
include: "../src",
// 不查找node_modules目录
exclude: /node_modules/,
},
/* dev */
/* 编译加载图片模块 */
// {
// test: /\.(png|jpg|jpeg|gif)$/,
// use: [
// {
// loader: "file-loader",
// options: {},
// },
// ],
// },
// 开发环境下CSS的配置
/* 编译加载CSS模块 */
// {
// test: /\.css$/,
// // loader 的执行顺序是:从后往前
// /*
// postcss.config.js中的配置
// module.exports = {
// plugins: [require("autoprefixer")],
// };
// */
// use: ["style-loader", "css-loader", "postcss-loader"],
// },
// scss开发环境
/* 编译加载SCSS模块 */
// {
// test: /\.scss$/, // 增加 'less-loader' ,注意顺序
// use: [
// "style-loader",
// "css-loader",
// "sass-loader",
// "postcss-loader",
// ],
// },
/* prod */
/* 编译加载图片模块 */
// 考虑 base64 编码的情况
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: "url-loader",
options: {
// 小于 5kb 的图片用 base64 格式产出
// 否则,依然延用 file-loader 的形式,产出 url 格式
limit: 1 * 1024,
// 输出到bundle根目录下的img文件夹
outputPath: "img/",
// 不一定以ESM模块形式去引入
// 不要看到源代码中未以ESM模块形式去引入a.png 就给哥tree-shaking掉(html中可能以src形式引用)
esModule: false,
},
},
},
/* 编译加载CSS模块 */
// 抽离css
{
test: /\.css$/,
use: [
// 将样式统一提取到独立的CSS文件
MiniCssExtractPlugin.loader,
// 加载CSS文件
"css-loader",
// 先对C3的样式定义加必要的浏览器兼容前缀
"postcss-loader",
],
},
/* 编译加载SCSS模块 */
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
// 将SCSS编译为CSS
"sass-loader",
"postcss-loader",
],
},
],
},
plugins: [
/* common */
/* 为html文件注入自动识别hash后缀的能力 */
new HtmlWebpackPlugin({
// 令html识别原始的<img src="xxx"/>
template: `html-withimg-loader!${path.join(srcPath, "index.html")}`,
filename: "index.html",
// 压缩选项
minify: {
collapseWhitespace: true,
keepClosingSlash: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
},
// 需要依赖的具体chunk
chunks: ["index", "common"],
}),
new HtmlWebpackPlugin({
template: `html-withimg-loader!${path.join(srcPath, "views", "other.html")}`,
filename: "other.html",
minify: {
collapseWhitespace: true,
keepClosingSlash: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
},
chunks: ["other", "common", "vendor"],
}),
/* dev */
/* 定义全局变量 */
// new webpack.DefinePlugin({
// // 相当于定义全局变量const ENV = 'production'
// ENV: JSON.stringify("development"),
// }),
// 会默认清空 output.path 文件夹
new CleanWebpackPlugin(),
/* prod */
// 抽离css文件到css目录下
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:8].css",
}),
new webpack.DefinePlugin({
ENV: JSON.stringify("production"),
}),
],
/* dev */
/*
开发服务器(生产环境下使用Nginx)
1. 跨域代理
2. 模块热更新(hot modudle replacement)
*/
devServer: {
hot: true, // 热更新
port: 8000, // 测试服务器端口
open: true, // 自动打开浏览器
compress: true, // 启动 gzip 压缩
/* 跨域代理 */
proxy: {
"/api": {
target: "http://localhost:9000/api",
changeOrigin: true,
// webpack-dev-server通过websocket协议与浏览器的内核服务器保持长连接
ws: true,
// 覆盖/api为卵都没有
pathRewrite: {
"^/api": "",
},
},
},
},
/* prod */
/* 性能优化选项 */
optimization: {
/* 压缩JS与CSS */
minimizer: [
new TerserPlugin(),
new OptimizeCssAssetsPlugin({})
],
/* 分包配置 */
splitChunks: {
// 同步异步都使用分包
// initial 只考虑同步引入 import xxx from "path"
// async 只考虑异步引入 const About = import(path)
// all 同步异步都考虑
chunks: "all",
/* 拆包配置 */
cacheGroups: {
// 第三方模块统一拆到vender.js中
vendor: {
name: "vendor", // chunk 名称
priority: 1, // 权限更高的优先抽离,重要!!!
test: /node_modules/,
minSize: 0, // 大小限制
minChunks: 1, // 最少复用过几次
},
// utils下的轮子统一拆到common.js中
common: {
name: "common", // chunk 名称
priority: 0, // 优先级
test: /src\/utils/,
minSize: 0, // 公共模块的大小限制
minChunks: 1, // 公共模块最少复用过几次
},
},
},
},
};
以下是一个能跑起来的Webpack4工程配置
git clone https://gitee.com/steveouyang/learn_webpack.git
cd learn_js_pro
git checkout feat1-wp4
npm i
npm run mock
npm run dev
npm run build
配套的Nginx配置
server {
listen 8002;
server_name localhost;
root "D:/phpStudy/WWW/jdzb_client_js";
location / {
index index.html;
autoindex on;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location /api {
proxy_pass http://10.3.134.65:9000/api;
}
}
下一篇我们来讲讲Webpack5与4的几个主要不同