# webpack-study **Repository Path**: nicefree/webpack-study ## Basic Information - **Project Name**: webpack-study - **Description**: 2022年了,再不会webpack5敲得代码就不香了,持续更新中...... - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: https://gitee.com/nicefree/webpack-study - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 2 - **Created**: 2021-11-30 - **Last Updated**: 2023-05-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: webpack5, webpack, JavaScript ## README  > 参考: - https://juejin.cn/post/6844904031240863758#heading-1 - https://cloud.tencent.com/developer/article/1847715、 - https://jelly.jd.com/article/61179aa26bea510187770aa3 - https://juejin.cn/post/6990869970385109005#heading-3 > 注意:当前 node 版本要尽量用最新版本,目前 16.13.0 是没有问题的 ### 初始化 创建项目文件夹 webpack-study npm init -y npm i -D webpack webpack-cli - npm i -D 为 npm install --save-dev 的缩写 - npm i -S 为 npm install --save 的缩写 新建一个文件夹 src ,然后新建一个文件 main.js,写一点代码测试一下 `console.log('Hello World')` 配置 package.json 命令 ```javascript "scripts": { "build": "webpack src/main.js" } ``` 执行 npm run build 此时如果生成了一个 dist 文件夹,并且内部含有 main.js 说明已经打包成功了 ### 自定义配置 上面一个简单的例子只是 webpack 自己默认的配置,下面我们要实现更加丰富的自定义配置 新建一个 build 文件夹,里面新建一个 webpack.config.js ```javascript // webpack.config.js const path = require("path"); module.exports = { mode: "development", // 开发模式 entry: path.resolve(__dirname, "../src/main.js"), // 入口文件 output: { filename: "output.js", // 打包后的文件名称 path: path.resolve(__dirname, "../dist"), // 打包后的目录 }, }; ``` 更改我们的打包命令 ```javascript "scripts": { "build": "webpack --config build/webpack.config.js" } ``` 执行 npm run build 会发现生成了以下目录 其中 dist 文件夹中的 main.js 就是我们需要在浏览器中实际运行的文件 当然实际运用中不会仅仅如此,下面让我们通过实际案例带你快速入手 webpack ### 配置 html 模板 js 文件打包好了,但是我们不可能每次在 html 文件中手动引入打包好的 js > 这里可能有的朋友会认为我们打包 js 文件名称不是一直是固定的嘛(output.js)?这样每次就不用改动引入文件名称了呀?实际上我们日常开发中往往会这样配置: ```javascript module.exports = { // 省略其他配置 output: { filename: "[name].[hash:8].js", // 打包后的文件名称, hash已被启用,改fullhash, path: path.resolve(__dirname, "../dist"), // 打包后的目录 }, }; ``` 这时候生成的 dist 目录文件如下 main.8626b326.js 为了缓存,你会发现打包好的 js 文件的名称每次都不一样。webpack 打包出来的 js 文件我们需要引入到 html 中,但是每次我们都手动修改 js 文件名显得很麻烦,因此我们需要一个插件来帮我们完成这件事情 npm i -D html-webpack-plugin 新建一个 build 同级的文件夹 public,里面新建一个 index.html 具体配置文件如下 ```javascript // webpack.config.js const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { mode: "development", // 开发模式 entry: path.resolve(__dirname, "../src/main.js"), // 入口文件 output: { filename: "[name].[fullhash:8].js", // 打包后的文件名称 path: path.resolve(__dirname, "../dist"), // 打包后的目录 }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "../public/index.html"), }), ], }; ``` 可以发现打包生成的 js 文件已经被自动引入 html 文件中 思考?为什么多了个 defer,查看博客文章https://blog.csdn.net/qq_43238599/article/details/115273893 查看官方插件配置选项https://github.com/jantimon/html-webpack-plugin#options 重新调整插件配置,再打包 ```javascript plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "../public/index.html"), scriptLoading: "blocking", }), ]; ``` 打包结果的 html 内容:
js 打包进入到了 body,如果不配置 scriptLoading 却在 head,配置了却在 body,再加个配置项 ```javascript plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "../public/index.html"), inject: "head", scriptLoading: "blocking", }), ]; ``` 再打包就 ok #### 多入口文件如何开发 > 生成多个 html-webpack-plugin 实例来解决这个问题 public 目录下新建 header.html,新建 webpack.config.multi.js ```javascript // webpack.config.multi.js const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { mode: "development", // 开发模式 entry: { main: path.resolve(__dirname, "../src/main.js"), header: path.resolve(__dirname, "../src/header.js"), }, output: { filename: "[name].[fullhash:8].js", // 打包后的文件名称 path: path.resolve(__dirname, "../dist"), // 打包后的目录 }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "../public/index.html"), filename: "index.html", inject: "head", scriptLoading: "blocking", chunks: ["main"], // 与入口文件对应的模块名 }), new HtmlWebpackPlugin({ template: path.resolve(__dirname, "../public/header.html"), filename: "header.html", inject: "head", scriptLoading: "blocking", chunks: ["header"], // 与入口文件对应的模块名 }), ], }; ``` package.json 调整 ```javascript "scripts": { "build": "webpack --config build/webpack.config.js", "buildmul": "webpack --config build/webpack.config.multi.js" }, ``` 执行 npm run buildmul #### clean-webpack-plugin > 每次执行 npm run build 会发现 dist 文件夹里会残留上次打包的文件,这里我们推荐一个 plugin 来帮我们在打包输出前清空文件夹 clean-webpack-plugin npm i -D clean-webpack-plugin ```javascript const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = { // ...省略其他配置 plugins: [new CleanWebpackPlugin()], }; ``` ### 引用 CSS #### loader loader 用于对模块的源代码进行转换 loader 都在 module 下的 rules 中配置 loader 配置项包括: - test 正则校验(必须) - loader 调用 loader 的名称 / use 链式调用 loader (二选一) - include/exclude 手动添加必修处理的文件/文件夹或屏蔽不需要处理的文件/文件夹(可选) - options 为 loaders 提供额外的设置选项(可选) tip:use 链式调用,都是从右向左解析,需注意调用 loader 的顺序。loader 要记住,面试经常被问到有哪些 loader 以及其作用 我们的入口文件是 js,所以我们在入口 js 中引入我们的 css 文件 ```css /* index.css */ * { margin: 0; padding: 0; } ``` ```css /* index.less */ .red { color: red; } ``` ```css /* index.scss */ .green { color: green; } ``` ```javascript import "./assets/index.css"; import "./assets/index.less"; import "./assets/index.scss"; console.log("Hello World"); ``` 同时我们也需要一些 loader 来解析我们的 css 文件 > npm i -D style-loader css-loader 如果我们使用 less 来构建样式,则需要多安装两个 > npm i -D less less-loader 如果我们使用 scss 来构建样式,则需要安装 > npm i -D sass-loader 配置文件如下 ```javascript // webpack.config.js module.exports = { // ...省略其他配置 module: { rules: [ { test: /\.css$/, use: ["style-loader", "css-loader"], // 从右向左解析原则 }, { test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"], // 从右向左解析原则 }, { test: /\.scss$/, use: ["style-loader", "css-loader", "sass-loader"], // 从右向左解析原则 }, ], }, }; ``` 执行编译的时候会报 scss 相关错误,还需安装 node-sass,但没有看到相关使用 node-sass 的字眼!!! npm i -D node-sass sass-loader 全局安装 live-server, npm i -g live-server cmd cd dist cmd live-server 打开浏览器,观察 html 内容 为了直观可以修改 public/index.html 的内容 ```html
```
rules 的配置
```javascript
rules: [
{
test: /\.html$/,
loader: "html-loader",
},
];
```
npm run build 查看 html 的内容,其中一张是转成了 base64 一张是文件路径形式
#### 处理媒体文件
免费视频素材网站
- https://www.videezy.com
- http://www.wedistill.io/
- https://mazwai.com/
- https://footagecrate.com/
- https://www.monzoom.com
下载个视频放到 media 目录下 video.mp4
index.html 内容调整
```html
```
```javascript
// webpack.config.js
rules: [
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, // 媒体文件
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
generator: {
filename: "media/[name].[hash:6][ext]",
publicPath: "./",
},
},
];
```
cmd npm run build
查看 html 引入的视频路径和 dist/media 下的视频
#### 处理字体文件
添加字体 src/assets/fonts/Poppins-Regular.woff
```css
// index.css追加如下
.font {
font-family: "Poppins-Regular";
}
@font-face {
font-family: "Poppins-Regular";
src: url("./fonts/Poppins-Regular.woff") format("woff");
}
```
```javascript
// webpack.config.js
rules: [
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, // 字体
type: "asset/inline", // inline 的时候不需要指定文件名
},
];
```
inde.html 调整添加 font
```html
```
注意:~@
在 webpack.common.js 中添加配置选项
resolve 和 entry 同级
```javascript
resolve: {
alias: { // 配置别名
"@": path.resolve(__dirname, "../src"),
},
},
```
npm run dev 编译通过,并且浏览器正常访问,如果把配置去掉,编译不通过会报错!
### 代码依赖分析
> npm i webpack-bundle-analyzer -D
只有打包才会分析所以在 webpack.prod.js 添加如下配置:
```javascript
const BundleAnalyzerPlugin =
require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
// ... 其他配置
plugins: [
new BundleAnalyzerPlugin({
// 可以是`server`,`static`或`disabled`。
// 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
// 在“静态”模式下,会生成带有报告的单个HTML文件。
// 在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
analyzerMode: "static",
// 将在“服务器”模式下使用的主机启动HTTP服务器。
analyzerHost: "127.0.0.1",
// 将在“服务器”模式下使用的端口启动HTTP服务器。
analyzerPort: 8888,
// 路径捆绑,将在`static`模式下生成的报告文件。
// 相对于捆绑输出目录。
reportFilename: "report.html",
// 模块大小默认显示在报告中。
// 应该是`stat`,`parsed`或者`gzip`中的一个。
// 有关更多信息,请参见“定义”一节。
defaultSizes: "parsed",
// 在默认浏览器中自动打开报告
openAnalyzer: false,
// 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
generateStatsFile: false,
// 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
// 相对于捆绑输出目录。
statsFilename: "stats.json",
// stats.toJson()方法的选项。
// 例如,您可以使用`source:false`选项排除统计文件中模块的来源。
// 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
statsOptions: null,
logLevel: "info", // 日志级别。可以是'信息','警告','错误'或'沉默'。
}),
];
```
npm run prod
### splitChunks(分离 chunks)
webpack.prod.js
也只有打包才需要分离
```javascript
//webpack.prod.js
//与plugins同级
optimization: {
splitChunks: {
chunks: "all",
name: "vendor",
cacheGroups: {
"echarts.vendor": {
name: "echarts.vendor",
priority: 40,
test: /[\\/]node_modules[\\/](echarts|zrender)[\\/]/,
chunks: "all",
},
lodash: {
name: "lodash",
chunks: "async",
test: /[\\/]node_modules[\\/]lodash[\\/]/,
priority: 40,
},
"async-common": {
chunks: "async",
minChunks: 2,
name: "async-commons",
priority: 30,
},
commons: {
name: "commons",
chunks: "all",
minChunks: 2,
priority: 20,
},
},
},
},
```
安装 echarts
> npm i echarts -S
新建 src/echart.js
```javascript
import * as echarts from "echarts";
var myChart = echarts.init(document.getElementById("main"));
var option = {
title: {
text: "ECharts 入门示例",
},
tooltip: {},
legend: {
data: ["销量"],
},
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"],
},
yAxis: {},
series: [
{
name: "销量",
type: "bar",
data: [5, 20, 36, 10, 10, 20],
},
],
};
myChart.setOption(option);
```
在 main.js 中引入
> import './echart'
修改 public/index.html
```html
```
这个时候还需调整 HtmlWebpackPlugin 配置的 nject: 'body',思考为什么?
运行 npm run prod,在 dist 下会发现新增了 echarts.vendor.xxxx.js 这就是通过 splitChunks 分离出来 echarts 包
### 动态导入(按需加载 chunks)
按需下载资源,如路由懒加载。可以提升首屏加载速度
> npm i lodash -S
通过 import()语法实现动态导入
```javascript
//在main.js添加
function getComponent() {
// Lodash, now imported by this script
return import("lodash")
.then(({ default: _ }) => {
const element = document.createElement("div");
element.innerHTML = _.join(["Hello", "webpack"], " ");
return element;
})
.catch((error) => "An error occurred while loading the component");
}
const button = document.createElement("button");
button.innerHTML = "Click me ";
button.onclick = () => {
getComponent().then((component) => {
document.body.appendChild(component);
});
};
document.body.appendChild(button);
```
在 webpack.prod.js 中 cacheGroups 下添加(在上面 splitChunks 中已经加过了)
```javascript
lodash: {
name: "lodash",
chunks: "async",
test: /[\\/]node_modules[\\/]lodash[\\/]/,
priority: 40,
},
```
npm run prod 可以看到有生成 lodash.xxx.js
cd dist
cmd live-server 启动服务,点击底部的 Click me 按钮,可以看到动态加载的 js
### 定义编译时全局变量
> npm i cross-env -D
package.json 添加两个命令
```javascript
"scripts": {
"cdev": "cross-env NODE_ENV=development webpack serve --config build/webpack.dev.js",
"cbuild": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js",
}
```
在 webpack.common.js 添加输出
console.log('process.env.NODE_ENV',process.env.NODE_ENV)
cmd npm run cdev 或者 npm run cbuild 可以看到輸出的变量
### 定义编译后全局变量
通过 DefinePlugin 实现
根目录下新建 config/dev.env.js
```javascript
module.exports = {
NODE_ENV: '"development"',
APP_API: '"wwww.testapi.com"',
};
```
```webpack.dev.js
// webpck.dev.js
const env = require("../config/dev.env")
const webpack =require("webpack")
module.exports = merge(common,{
plugins: [
new webpack.DefinePlugin({
"process.env": env,
}),
],
})
```
// main.js
try {
console.log(process.env)
} catch (error) {
}
### externals
防止将外部资源包打包到自己的 bundle 中
示例:从 cdn 引入 jQuery,而不是把它打包
1. index.html 中添加
必须是 body>前,如果放 body>后就不行,思考?
2. main.js 添加
```javascript
import $ from "jquery";
console.log($("#main"));
```
3. npm i jquery -S 这里主要满足 dev 环境使用, html 引入了 jq,main.js 中又引入,会出现引入两次的情况,后面再考虑如何 dev 只引入一次
4. webpack.prod.js 添加配置
```javascript
externals: {
jquery: 'jQuery',
,
```
npm run dev 和 npm run prod 查看结果
### 打包入口是 CSS
思考后续是否可以打包组件相关的样式,只打包样式文件
新建 src\assets\main.css
```css
* {
margin: 0;
padding: 0;
}
.red {
color: red;
}
.green {
color: green;
}
```
新建 webpack.config.css.js
```javascript
const path = require('path')
module.exports = {
mode: 'development', // 模式
entry: path.resolve(**dirname, '../src/assets/main.css'), // 打包入口地址
output: {
filename: 'bundle.css', // 输出文件名
path: path.join(**dirname, '../dist') // 输出文件目录
}
}
```
package.json 添加命令
> "buildcss": "webpack --config build/webpack.config.css.js"
npm run buildcss 编译错误
处理 css 文件需要使用 css-loader
调整配置
```javascript
// webpack.config.css.js
const path = require("path");
module.exports = {
mode: "development", // 模式
entry: path.resolve(__dirname, "../src/assets/main.css"), // 打包入口地址
output: {
filename: "bundle.css", // 输出文件名
path: path.join(__dirname, "../dist"), // 输出文件目录
},
module: {
rules: [
// 转换规则
{
test: /\.css$/, //匹配所有的 css 文件
use: "css-loader", // use: 对应的 Loader 名称
},
],
},
};
```
npm run buildcss
### 常用 loader
常用的 loader:
- style-loader、css-loader、postcss-loader、less-loader,
- 编译 sass 须使用 sass-loader node-sass 或 dart-sass
- style-loader 和 MiniCssExtractPlugin.loader 不能共用
- file-loader:解决资源引入问题,并将资源 copy 到指定目录,默认为 dist
- url-loader:解依赖 file-loader,当图片小于 limit 值的时候,会将图片转为 base64 编码,大于 limit 值的时候依然是使用 file-loader 进行拷贝
- img-loader:压缩图片
- html-loader: 处理 html 文件资源
- webpack5 新增资源模块(asset module),允许使用资源文件(字体,图标等)而无需配置额外的 loader。
- asset/resource 将资源分割为单独的文件,并导出 url,类似之前的 file-loader 的功能.
- asset/inline 将资源导出为 dataUrl 的形式,类似之前的 url-loader 的小于 limit 参数时功能.
- asset/source 将资源导出为源码(source code). 类似的 raw-loader 功能.
- asset 会根据文件大小来选择使用哪种类型,当文件小于 8 KB(默认) 的时候会使用 asset/inline,否则会使用 asset/resource
### 缩小文件的搜索范围(配置 include exclude alias noParse extensions)
- alias: 当我们代码中出现 import 'vue'时, webpack 会采用向上递归搜索的方式去 node_modules 目录下找。为了减少搜索范围我们可以直接告诉 webpack 去哪个路径下查找。也就是别名(alias)的配置。
- include exclude 同样配置 include exclude 也可以减少 webpack loader 的搜索转换时间。
- noParse 当我们代码中使用到 import jq from 'jquery'时,webpack 会去解析 jq 这个库是否有依赖其他的包。但是我们对类似 jquery 这类依赖库,一般会认为不会引用其他的包(特殊除外,自行判断)。增加 noParse 属性,告诉 webpack 不必解析,以此增加打包速度。
- extensions webpack 会根据 extensions 定义的后缀查找文件(频率较高的文件类型优先写在前面)
```javascript
module.exports = {
module: {
noParse: /jquery/,
rules: [
{
test: /\.vue$/,
loader: "vue-loader",
include: [path.resolve(__dirname, "src")],
exclude: /node_modules/,
},
{
test: '/\.(jep?g|png|gif)$/,
use: {
loader: 'url-loader',
include: [path.resolve(__dirname, 'src/assets/icons)],
exclude: /node_modules/
}
}
],
},
resolve: {
alias: {
'vue$', 'vue/dist/vue.runtime.esm.js',
'@': path.resolve(__dirname, '../src'),
'assets': resolve('src/assets'),
'components': resolve('src/components')
},
extensions: ['*', '.js', '.json', '.vue']
}
}
```
### parallelUglifyPlugin 多进程压缩 js
适用生产环境
> npm i webpack-parallel-uglify-plugin -D
```javascript
// webpack.prod.js
const ParallelUglifyPlugin = require("webpack-parallel-uglify-plugin");
plugins: [
new ParallelUglifyPlugin({
// 压缩js的一些配置
uglifyJS: {
output: {
beautify: false, // 不需要格式化,以最紧凑的方式输出
comments: false, // 删除注释
},
warnings: false, // 删除未使用一些代码时引起的警告
compress: {
drop_console: true, // 删除所有console.log
// 是否内嵌虽定义,但只使用了一次的变量
// 比如var x = 2, y = 10, z = x + y 变成 z = 12
collapse_vars: true,
// 提出多次出现但没定义的变量,将其变成静态值;
// 比如x = 'xx', y = 'xx' 变成 var a = 'xx', x = a, y = a
reduce_vars: true,
},
},
}),
];
```
npm run prod 后查看打包出来的 js 已经没有相关 console.log 等
### happyPack 多进程打包
因为 js 是单线程的,如果引用的模块很多,且模块间引用的层级很深,那么 webpack 在递归解析依赖时,速度就会很慢。而使用 happyPack 可以开启多进程打包,会提高构建速度
它在开发或者生产环境都可以使用,不过对于小项目,使用这个优化空间不大,且开启进程可能消耗性能会更多;在大项目时,才会有较多的优化空间
> npm i happypack -D
```javascript
// wepback.common.js 或webpack.prod.js
const HappyPack = require('happypack')
// 将原来babel的配置改下,改为使用happypack多进程打包
module: {
rules: [
{
test: /\.js$/,
// use: ['babel-loader?cacheDirectory'],
// 改为使用 happypack打包
use: ['happypack/loader?id=babel'], // 这个id是自定义命名的,要跟插件中id对应
// 排除 node_modules 目录下的文件
exclude: /node_modules/
}
]
},
plugins: [
new HappyPack({
id: 'babel', // 唯一标识符
// 使用的loader配置改写到happypack的配置项中
use: ['babel-loader']
})
]
```
npm run prod
HappyPack 添加多个 loader,如下参考, 未实验:
```javascript
// ...
// 引入 happypack
const HappyPack = require("happypack");
// 创建 happypack 共享进程池,其中包含 6 个子进程
const happyThreadPool = HappyPack.ThreadPool({ size: 6 });
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
// use: ['babel-loader?cacheDirectory'] 之前是使用这种方式直接使用 loader
// 现在用下面的方式替换成 happypack/loader,并使用 id 指定创建的 HappyPack 插件
use: ["happypack/loader?id=babel"],
include: path.resolve(__dirname, "src"),
},
{
test: /\.(css|less)$/,
// 之前是使用这种方式直接使用 loader
// use: ['style-loader',
// {
// loader: 'css-loader',
// options: {
// sourceMap: true
// }
// },
// {
// loader: 'postcss-loader',
// options: {
// plugins: () => [autoprefixer()]
// }
// },
// {
// loader: 'less-loader',
// options: {
// javascriptEnabled: true,
// }
// }]
// 现在用下面的方式替换成 happypack/loader,并使用 id 指定创建的 HappyPack 插件
use: ["happypack/loader?id=styles"],
include: path.resolve(__dirname, "src"),
},
],
},
plugins: [
// ...
new HappyPack({
/*
* 必须配置项
*/
// id 标识符,要和 rules 中指定的 id 对应起来
id: "babel",
// 需要使用的 loader,用法和 rules 中 Loader 配置一样
// 可以直接是字符串,也可以是对象形式
loaders: ["babel-loader?cacheDirectory"],
// 使用共享进程池中的进程处理任务
threadPool: happyThreadPool,
}),
new HappyPack({
/*
* 必须配置
*/
// id 标识符,要和 rules 中指定的 id 对应起来
id: "styles",
// 需要使用的 loader,用法和 rules 中 Loader 配置一样
// 可以直接是字符串,也可以是对象形式
loaders: [
"style-loader",
{
loader: "css-loader",
options: {
sourceMap: true,
},
},
{
loader: "postcss-loader",
options: {
plugins: () => [autoprefixer()],
},
},
{
loader: "less-loader",
options: {
javascriptEnabled: true,
},
},
],
// 使用共享进程池中的进程处理任务
threadPool: happyThreadPool,
}),
],
};
```
### css 压缩 css-minimizer-webpack-plugin
CSS 压缩之前会使用 optimize-css-assets-webpack-plugin 这个插件,在 webpack v5 之后推荐使用 css-minimizer-webpack-plugin 这个插件。
> npm i css-minimizer-webpack-plugin -D
> 修改 webpack.config.minicss.js
```javascript
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
optimization: {
minimizer: [new CssMinimizerPlugin()],
},
};
```
忘了 mode: 'development', // 开发模式 改为 productions,相关 hash 改为 fullhash
npm run buildminicss 观察添加配置前后的 css 变化
### 拷贝静态资源 copy-webpack-plugin
> npm i -D copy-webpack-plugin
webpack.common.js 添加配置选项
```javascript
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: "./",
globOptions: {
ignore: ["**/*.html"],
},
},
],
}),
],
};
```
public 下面必须需要有可拷贝的资源(除了 html),这里放了个 logo,否则会有警告信息
npm run dev / npm run prod