目录
一、CSS 兼容(处理.css文件、.less文件)
二、打包图片
三、webpack插件使用
https://www.webpackjs.com/concepts/configuration/webpack5 配置官方网站:https://www.webpackjs.com/concepts/configuration/?
webpack5 插件官方网站:https://webpack.docschina.org/loaders/?
一、CSS 兼容(处理.css文件、.less文件)
1、需要下载的的依赖
- postcss、postcss-cli、postcss-loader:是一个用 JavaScript 工具和插件转换 CSS 代码的工具,postcss-loader 使用?PostCSS?处理 CSS 的 loader
- 配置?postcss.config.js
-
module.exports = {
plugins: [
[
'postcss-preset-env',
{
// 其他选项
},
],
],
};
- autoprefixer:自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮你自动为 CSS 规则添加前缀
-
postcss-preset-env:帮你将最新的 CSS 语法转换成大多数浏览器都能理解的语法,并根据你的目标浏览器或运行时环境来确定你需要的 polyfills,此功能基于?cssdb?实现 -
css-loader:css-loader会对@import 和 url 进行处理 -
less、less-loader:将 Less 编译为 CSS 的 loader -
style-loader:把 CSS 插入到 DOM 中 -
配置 webpack.config.js -
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
// 启用/禁用或者设置在 css-loader 前应用的 loader 数量
importLoaders: 1
// 0 => no loaders (默认);
// 1 => postcss-loader;
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
}
]
}
} - 配置 .browserslistrc
-
> 0.01%
last 2 version
not dead
?二、打包图片
?1、img src 三种写法:
2、?background url 写法
- img.js
- ?设置webpac.config.js 中 css-loader的options的 esModule: false
-
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
// use: [
// {
// loader: 'file-loader',
// options: {
// esModule: false // 不转为 esModule
// }
// }
// ]
use: ['file-loader']
}
]
}
}
3、设置打包图片的输出名称和路径名,配置如下:
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: 'file-loader',
options: {
/**
* [ext]: 扩展名
* [name]: 文件名
* [hash]: 文件内容
* [contentHash]:
* [hash:<length>]
* [path]:
*/
name: 'img/[name].[hash:8].[ext]',
// outputPath: 'img' // 或者在 name 直接添加 img/
}
}
]
}
]
}
}
4、url-loader?
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: 'img/[name].[hash:6].[ext]',
limit: 25 * 1024
}
}
]
}
]
}
}
5、type:assset (webpack5 内置模块)处理图片替换 filse-loader 和 url-loader 使用
- asset/resource? 相当于 fille-loader 作用
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset/resource',
// 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
generator: {
filename: "img/[name].[hash:4][ext]"
}
}
]
}
}
- asset/inline? 相当于 url-loader 作用
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset/inline'
}
]
}
}
- asset/source 相当于 row-loader 作用很少用
- asset:通过限制图片大小的尺寸,进行拷贝图片或者将图片转为 base64
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset',
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
}
]
}
}
?
6、asset 处理字体图标
设置 type 类型为 asset/resource
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
}
]
}
}
三、webpack插件使用
1、clean-webpack-plugin 清空上一次的打包结果
// webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset',
// 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
}
]
},
plugins: [
new CleanWebpackPlugin()
]
}
2、html-webapck-plugin?:内置 html模板,设置自定义属性?title 、template
// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset',
// 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'html-webpack-plugin',
template: './public/index.html'
})
]
}
3、DefinePlugin(webpack 内置模块):用于定义全局变量(?link 引用的 BASE_url)
// html 模板
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
// webpack.config.js
const path = require('path')
const { DefinePlugin } = require('webpack')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset',
// 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
}
]
},
plugins: [
new DefinePlugin({
BASE_URL: '"./"'
})
]
}
4、copy-webpack-plugin:拷贝静态资源到打包目录
// webpack.config.js
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset',
// 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html'] // 忽略 index.html
}
}
]
})
]
}
5、babel (解决 JSX、ES6、TS的语法转换)
需要安装的依赖:
- @babel/cli:使用 babel命令
- @babel/core:转换语法核心插件
- @babel/preset-env:预设的 babel 插件集合
- babel-loader
// webpack.config.js
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset',
// 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
},
{
test: /\.js$/,
use: ['babel-loader']
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html'] // 忽略 index.html
}
}
]
})
]
}
// 单独配置babel的转换机制
// babel.config.js
module.exports = {
presets: [
'@babel/preset-env',
// { targets: 'chrome 91' } // 兼容谷歌的版本
]
}
6、polyfill :转换 Promise语法新特性,打一些补丁和做一些填充
- @babel/polyfill 不建议安装,包太大,可以安装核心插件:core-js、regenerator-runtime?
- 在 index.js 引入?core-js、regenerator-runtime?
// index.js
import "core-js/stable";
import "regenerator-runtime/runtime";
const title = '拉钩教育'
const foo = () => {
console.log(title)
}
const p1 = new Promise((resolve, reject) => {
console.log(111)
})
console.log(p1)
foo()
// babel.config.js
module.exports = {
"presets": [
["@babel/preset-env", {
// false: 不对当前的JS处理做 polyfill 的填充
// usage: 依据用户源代码当中所使用到的新语法进行填充
// entry: 依据我们当前筛选出来的浏览器决定填充什么
"useBuiltIns": "entry",
"corejs": 3
}]
]
}
// webpack.config.js
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
mode: 'development',
devtool: false,
entry: './src/index.js',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
// assetModuleFilename: "img/[name].[hash:4][ext]"
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
type: 'asset',
// 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html'] // 忽略 index.html
}
}
]
})
]
}
7、webpack-dev-server 热更新
- 添加 watch 监听,live serve 热启动
(1)方式一:在build 添加 --watch
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config lg.webpack.js --watch"
},
?? (2)方式二:在 webpack.json.js 添加 watch 属性为 true?
// webpack.config.js
module.exports = {
watch: true,
mode: 'development',
devtool: false,
entry: './src/index.js',
......
}
- 安装依赖?webpack-dev-server,添加 serve 属性
// webpack.config.js
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config lg.webpack.js",
"serve": "webpack serve --config lg.webpack.js"
},
?(3)二者监听的对比
????????watch 监听不足:
- 所有源代码都会被重新编译
- 每次编译成功之后需要进行文件读写
- 不能实现局部刷新
????????webpack-dev-server
- 可以实现局部刷新
- 编译后的文件在内存中,读取速度快
- 开启一个服务端
8、?webpack-dev-middleware :如果相对打包监听使用自由度高,可使用这个依赖
- yarn add express?webpack-dev-middleware -D
- 在根目录新建 Serve.js文件
-
// Server.js
const express = require('express')
const webpackDevMiddle = require('webpack-dev-middleware')
const webpack = require('webpack')
const app = express()
// 获取配置文件
const config = require('./webpack.config.js')
const compiler = webpack(config)
app.use(webpackDevMiddle(compiler))
// 开启端口上的服务
app.listen(3000, () => {
console.log('服务运行在 3000 端口上');
}) - node .\Server.js?
9、HMR :开启模块热更新(已安装 webpack-dev-server 情况下使用)
- 配置 webpack.config.js,添加 devServe 属性
// webpack.config.js
module.exports = {
mode: 'development',
devtool: false,
devServer: {
hot: true
},
......
}
- 在 index.js 中对想要热更新的文件进行? module.js 判断
// index.js
import './title'
if (module.hot) {
module.hot.accept(['./title.js'], () => {
console.log('title.js模块更新');
})
}
10、react 使用热更新
- yarn add @pmmmwh/react-refresh-webpack-plugin react-refresh -D
- 配置 .babel.config.js
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env'],
['@babel/preset-react'],
],
plugins: [
['react-refresh/babel']
]
}
- 配置 webpack.config.js?,引入插件?@pmmmwh/react-refresh-webpack-plugin
// webpack.config.js
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { DefinePlugin } = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
module.exports = {
mode: 'development',
devtool: false,
entry: './src/index.js',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
},
target: 'web',
devServer: {
hot: true
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|gif|jpe?g)$/,
type: 'asset',
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
},
{
test: /\.jsx?$/,
use: ['babel-loader']
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
}),
new DefinePlugin({
BASE_URL: '"./"'
}),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
new ReactRefreshWebpackPlugin()
]
}
11、vue? 使用 HRM
- yarn add?vue-loader?vue-template-compiler?-D // vue2建议安装 vue-loader@14 以下版本,vue3安装?ue-loader@15 以上版本,15版本之前的不需要处理 .vue 文件,15之后需要手动处理安装插件vue-loader/lib/plugin
- 配置 webpack.config.js,引入插件?vue-loader/lib/plugin
// webpack.config.js
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { DefinePlugin } = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
mode: 'development',
devtool: false,
entry: './src/index.js',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
},
target: 'web',
devServer: {
hot: true
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|gif|jpe?g)$/,
type: 'asset',
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
},
{
test: /\.jsx?$/,
use: ['babel-loader']
},
{
test: /\.vue$/,
use: ['vue-loader']
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
}),
new DefinePlugin({
BASE_URL: '"./"'
}),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
new VueLoaderPlugin()
]
}
12、output 中的 path?
// webpack.config.js
module.exports = {
mode: 'development',
devtool: false,
devServer: {
hot: true
},
entry: './src/index.js',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist'),
// assetModuleFilename: "img/[name].[hash:4][ext]"
publicPath: './'
},
......
}
13、?devserver 中的 path?
- publicPath:指定本地服务所在的目录
- contentBase:我们打包后的资源如果依赖其他资源?,词是告知去哪里去找
- watchContentBase:监听引入资源变化的内容
// webpack.config.js
module.exports = {
mode: 'development',
devtool: false,
entry: './src/index.js',
devServer: {
hot: true,
publicPath: '/lg',
contentBase: path.resolve(__dirname, 'public'),
watchContentBase: true
},
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/lg'
},
......
}
14、devServer 常用配置
- hot: true 开启热更新
- hotOnly: true 只对更新的加载
- port: 4000 设置端口号
- open: true 服务启动,自动开启浏览器
- compress: true 压缩 js
- historyApiFallback: true 设置回退历史纪录
- proxy:解决跨域问题
-
module.exports = {
mode: 'development',
devtool: false,
entry: './src/index.js',
devServer: {
hot: true,
publicPath: '/lg',
contentBase: path.resolve(__dirname, 'public'),
watchContentBase: true,
proxy: {
'/api': {
target: 'https://api.github.com',
pathRewrite: { "^/api": "" },
changeOrigin: true
}
}
},
......
}
15、resolve: 模块路径解析规则,对于引入的文件进行后缀名补全设置
// webpack.config.js
module.exports = {
mode: 'development',
devtool: false,
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': path.resolve(__dirname, 'src')
}
},
......
}
16、source-map:方便定位源代码位置
- 设置 mode:“development” //? 默认是 none,production是开发模式
- 设置 devtool:"source-map" // eval |?cheap-eval-source-map ...
17、ts-loader 和 babel-loader 对 .ts文件进行转换编译?
?ts-loader:打包时不能对 ES6 新语法进行填充,不建议使用
- yarn add ts-loader -D
- 配置 webpack.config.js 规则?
// webpack.config.js
module.exports = {
mode: 'development',
entry: './src/index.ts',
devtool: 'nosources-source-map',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
},
target: 'web',
devServer: {
hot: true,
port: 4000
},
module: {
rules: [
{
test: /\.jsx?$/,
use: ['babel-loader']
},
{
test: /\.ts$/,
use: ['ts-loader']
}
]
},
......
}
?babel-loader:打包时能够补充 ES6 新语法
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
corejs: 3
}],
['@babel/preset-typescript']
]
}
// webpack.config.js
module.exports = {
mode: 'development',
entry: './src/index.ts',
devtool: 'nosources-source-map',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
},
target: 'web',
devServer: {
hot: true,
port: 4000
},
module: {
rules: [
{
test: /\.jsx?$/,
use: ['babel-loader']
},
{
test: /\.ts$/,
use: ['babel-loader']
}
]
},
......
}
// package.json.js
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npm run ck && webpack",
"serve": "webpack serve",
"ck": "tsc --noEmit"
},
18、加载 vue 文件
- yarn add vue vue-loader??vue-template-compiler -D
- 配置 postcss.config.js
// postcss.config.js
module.exports = {
plugins: [
require('postcss-preset-env')
]
}
// webpack.config.js
const path = require('path')
const { DefinePlugin } = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
devtool: false,
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, 'dist')
},
target: 'web',
devServer: {
hot: true,
port: 4000
},
module: {
rules: [
{
test: /\.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'postcss-loader',
'less-loader'
]
},
{
test: /\.jsx?$/,
use: ['babel-loader']
},
{
test: /\.ts$/,
use: ['babel-loader']
},
{
test: /\.vue$/,
use: ['vue-loader']
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
}),
new DefinePlugin({
BASE_URL: '"./"'
}),
new VueLoaderPlugin()
]
}
19、合并生产环境配置?
- ?新建 config目录,新建文件 path.js、webpack.common.js、webpack.dev.js、webpack.prod.js
- path.js
// path.js
const path = require('path')
const appDir = process.cwd()
const resolveApp = (relativePath) => {
return path.resolve(appDir, relativePath)
}
module.exports = resolveApp
// webpack.common.js
const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { merge } = require('webpack-merge')
// 导入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')
// 定义对象保存 base 配置信息
const commonConfig = {
entry: './src/index.js', // 反而没有报错( 相对路径 )
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': resolveApp('./src')
}
},
output: {
filename: 'js/main.js',
path: resolveApp('./dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|gif|jpe?g)$/,
type: 'asset',
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
},
{
test: /\.jsx?$/,
use: ['babel-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
})
]
}
module.exports = (env) => {
const isProduction = env.production
// 依据当前的打包模式来合并配置
const config = isProduction ? prodConfig : devConfig
const mergeConfig = merge(commonConfig, config)
return mergeConfig
}
// webpack.dev.js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
module.exports = {
mode: 'development',
devtool: 'cheap-module-source-map',
target: 'web',
devServer: {
hot: true,
hotOnly: true,
port: 4000,
open: false,
compress: true,
historyApiFallback: true,
proxy: {
'/api': {
target: 'https://api.github.com',
pathRewrite: { "^/api": "" },
changeOrigin: true
}
}
},
plugins: [
new ReactRefreshWebpackPlugin()
]
}
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
mode: 'production',
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
})
]
}
// babel.config.js
const presets = [
['@babel/preset-env'],
['@babel/preset-react'],
]
const plugins = []
console.log(process.env.NODE_ENV, '<------')
// 依据当前的打包模式来决定plugins 的值
const isProduction = process.env.NODE_ENV === 'production'
if (!isProduction) {
plugins.push(['react-refresh/babel'])
}
module.exports = {
presets,
plugins
}
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"serve": "webpack serve",
"build2": "webpack --config ./config/webpack.common.js --env production",
"serve2": "webpack serve --config ./config/webpack.common.js --env development"
},
- yarn run build2
- yarn run serve2
20、?代码拆分方式
// webpack.common.js
const commonConfig = {
entry: {
main1: './src/main1.js',
main2: './src/main2.js'
},
output: {
filename: 'js/[name].build.js',
path: resolveApp('./dist')
},
......
}
- 通过 import 方式打包,如果入口文件引入依赖 lodash 和 jquery ,写法如下
// main1.js
import _ from 'lodash'
import $ from 'jquery'
console.log($)
console.log('main1.js文件')
console.log(_.join(['前端', '开发']))
// main2.js
import _ from 'lodash'
import $ from 'jquery'
console.log($)
console.log('main2.js文件')
console.log(_.join(['111', '2---']))
// webpack.common.js
// 定义对象保存 base 配置信息
const commonConfig = {
entry: {
// 如果 入口文件中引入单个依赖(lodash、jquery)写法
main1: { import: './src/main1.js', dependOn: 'lodash' },
main2: { import: './src/main2.js', dependOn: 'lodash' },
lodash: 'lodash'
// 如果 入口文件中引入多个依赖(lodash、jquery)写法
// main1: { import: './src/main1.js', dependOn: 'shared' },
// main2: { import: './src/main2.js', dependOn: 'shared' },
// shared: ['lodash', 'jquery']
},
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': resolveApp('./src')
}
},
output: {
filename: 'js/[name].build.js',
path: resolveApp('./dist')
},
optimization: {
minimizer: [
new TerserPlugin({
extractComments: false,
}),
]
}
// index.js
import 'jquery'
console.log('index.js代码')
// webpack.common.js
// 定义对象保存 base 配置信息
const commonConfig = {
entry: {
index: './src/index.js'
},
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': resolveApp('./src')
}
},
output: {
filename: 'js/[name].build.js',
path: resolveApp('./dist')
},
optimization: {
minimizer: [
new TerserPlugin({
extractComments: false,
}),
],
splitChunks: {
chunks: 'all', // 默认是 async(处理异步) | initial(处理同步) | all(同步异步都处理)
miniSize:2000, // 默认是 2000,如果拆包的体积达不到 2000,就不进行拆包
maxSize: 2000, // 默认是 0,一般写和miniSize一样,避免出现警告
minChunks: 1, // 拆分的包至少被引用1次,如果是2 ,不建议和 miniSize、maxSize一起用
cacheGroups: { // 将引入的第三方依赖包进行合并打包
syVendors: {
test: /[\\/]node_modules[\\/]/,
filename: 'js/[id]_vendors.js',
priority: -10 // 优先级哪个数值大,用哪个
},
default: {
minChunks: 2,
filename: 'js/syy_[id]_vendors.js',
priority: -20
}
}
}
}
21、import 动态导入配置
// webpack.common.js
// 定义对象保存 base 配置信息
const commonConfig = {
entry: {
index: './src/index.js'
},
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': resolveApp('./src')
}
},
output: {
filename: 'js/[name].build.js',
path: resolveApp('./dist'),
chunkFilename: 'js/chunk_[name]:[contenthash:8].js' // 定义打包名
},
optimization: {
// nature:当前文件的名称按照自然数进行编号排序,如果某个文件当前次不被依赖导入,那么重新打包的次数会变,会影响浏览器的缓存,不建议使用
// named:一般开发环境下使用,用文件名命名
// deterministic:生产模式下使用,用文件名产生的 hash 来命名
chunkIds: 'nature',
runtimeChunk: true, // 针对改变的文件进行打包,打包名不边
minimizer: [
new TerserPlugin({
extractComments: false,
}),
]
}
}
用魔法注释可以让打包名包括原文件名:
// index.js
import(/*webpackChunkName: "title"*/'./title')
console.log('index.js代码')
22、代码懒加载、prefetch(预获取) 与 preload(预加载)
// index.js
const oBtn = document.createElement('button')
oBtn.innerHTML = '点击加载元素'
document.body.appendChild(oBtn)
// 按需加载
oBtn.addEventListener('click', () => {
import(
/*webpackChunkName:'utils' */
// 在浏览器空闲的时候预获取,一般这个用的比较多
/*webpackPreLoad:true */
// 与 chunk 并行下载
/*webpackPreLoad:true */
'./utils').then(({ default: element }) => {
console.log(element)
document.body.appendChild(element)
})
})
// utils.js
const oEle = document.createElement('div')
oEle.innerHTML = '前端开发'
module.exports = oEle
23、?第三方扩展设置 CDN?
- 有 CDN服务器情况下,设置?publicPath
// webpack.config.js
module.exports ={
output: {
filename: 'js/[name].[contenthash:8].bundle.js',
path: resolveApp('./dist'),
publicPath: 'https//abc/cdn'
},
......
}
- 通过在 index.html 引入第三方依赖包 cdn地址来提高访问速度
// index.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
</body>
</html>
// webpack.config.js
const commonConfig = {
// 不打包 lodash
externals: {
lodash: '_'
},
......
}
24、打包 Dll 动态库(将不经常变动的库单独进行打包,这样编译时不再进行打包,提高开发效率)?
// pageage.json
{
"name": "46_webpack_pack_dll",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dll": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"webpack": "^5.50.0",
"webpack-cli": "^4.7.2"
}
}
// webpackage.config.js
const path = require('path')
const webpack = require('webpack')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
mode: "production",
entry: {
react: ['react', 'react-dom']
},
output: {
path: path.resolve(__dirname, 'dll'),
filename: 'dll_[name].js',
library: 'dll_[name]'
},
optimization: {
minimizer: [
new TerserPlugin({
extractComments: false
}),
],
},
plugins: [
new webpack.DllPlugin({
name: 'dll_[name]',
path: path.resolve(__dirname, './dll/[name].manifest.json')
})
]
}
25、使用 Dll 库:将不常用的依赖包单独打包
- ?配置 webpack.config.js,添加依赖包?add-asset-html-webpack-plugin
// webpack.config.js
const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { merge } = require('webpack-merge')
const TerserPlugin = require('terser-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
// 导入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')
// 定义对象保存 base 配置信息
const commonConfig = {
entry: {
index: './src/index.js'
},
resolve: {
extensions: ['.js', '.json', '.wasm', '.jsx', '.ts', '.vue']
},
optimization: {
minimizer: [
new TerserPlugin({
extractComments: false
})
],
runtimeChunk: false,
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 20000,
minChunks: 1,
cacheGroups: {
reactVendors: {
test: /[\\/]node_modules[\\/]/,
filename: 'js/[name].vendor.js'
}
}
}
},
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': resolveApp('./src')
}
},
output: {
filename: 'js/[name].[contenthash:8]._bundle.js',
path: resolveApp('./dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|gif|jpe?g)$/,
type: 'asset',
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
},
{
test: /\.jsx?$/,
use: ['babel-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
}),
new webpack.DllReferencePlugin({
context: resolveApp('./'),
manifest: resolveApp('./dll/react.manifest.json')
}),
new AddAssetHtmlPlugin({
outputPath: 'js',
filepath: resolveApp('./dll/dll_react.js')
})
]
}
module.exports = (env) => {
const isProduction = env.production
process.env.NODE_ENV = isProduction ? 'production' : 'development'
// 依据当前的打包模式来合并配置
const config = isProduction ? prodConfig : devConfig
const mergeConfig = merge(commonConfig, config)
return mergeConfig
}
26、CSS 抽离(mini-css-extract-plugin)和 压缩(css-minimizer-webpack-plugin)
- yarn add?mini-css-extract-plugin?css-minimizer-webpack-plugin -D
// paths.js
const path = require('path')
const appDir = process.cwd()
const resolveApp = (relativePath) => {
return path.resolve(appDir, relativePath)
}
module.exports = resolveApp
// webpack.common.js
const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { merge } = require('webpack-merge')
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
// 导入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')
// 定义对象保存 base 配置信息
const commonConfig = (isProduction) => {
return {
entry: {
index: './src/index.js'
},
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': resolveApp('./src')
}
},
output: {
filename: 'js/[name].[contenthash:8].bundle.js',
path: resolveApp('./dist'),
},
optimization: {
runtimeChunk: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
]
},
module: {
rules: [
{
test: /\.css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|gif|jpe?g)$/,
type: 'asset',
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:3][ext]'
}
},
{
test: /\.jsx?$/,
use: ['babel-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
})
]
}
}
module.exports = (env) => {
const isProduction = env.production
process.env.NODE_ENV = isProduction ? 'production' : 'development'
// 依据当前的打包模式来合并配置
const config = isProduction ? prodConfig : devConfig
const mergeConfig = merge(commonConfig(isProduction), config)
return mergeConfig
}
// webpack.dev.js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
module.exports = {
mode: 'development',
devtool: 'cheap-module-source-map',
target: 'web',
devServer: {
hot: true,
hotOnly: true,
port: 4000,
open: false,
compress: true,
historyApiFallback: true,
proxy: {
'/api': {
target: 'https://api.github.com',
pathRewrite: { "^/api": "" },
changeOrigin: true
}
}
},
plugins: [
new ReactRefreshWebpackPlugin()
]
}
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
module.exports = {
mode: 'production',
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
},
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:8].css'
})
]
}
27、TerserPlugin 压缩 JS:在生产模式下使用 (terser-webpack-plugin)
webpack v5 开箱即带有最新版本的?terser-webpack-plugin 。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装?terser-webpack-plugin 。如果使用 webpack v4,则必须安装?terser-webpack-plugin ?v4 的版本。?
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const TerserPlugin = require("terser-webpack-plugin")
module.exports = {
mode: 'production',
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin({
extractComments: false
})
]
},
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:8].css'
})
]
}
28、?scope hoisting:作用域提升,打包构建后可以提升访问速度(是webpack内置功能)
?ModuleConcatenationPlugin插件
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')
module.exports = {
mode: 'production',
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
new webpack.optimize.ModuleConcatenationPlugin()
]
}
29、TreeShaking:打包删除没有用到的函数
- ?usedExports 配置,配合minimizer、minimize使用?
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
mode: 'development',
devtool: false,
optimization: {
usedExports: true, // 标记不使用的函数
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
]
},
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
// new webpack.optimize.ModuleConcatenationPlugin()
]
}
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
mode: 'development',
devtool: false,
optimization: {
usedExports: true,
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
]
},
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
// new webpack.optimize.ModuleConcatenationPlugin()
]
}
?针对 js 文件写法:
// package.json
{
"sideEffects": [
"./src/title.js" // 删除未引用的代码不包含 title.js
]
}
针对 css 文件写法:
// webpack.config.js
// 定义对象保存 base 配置信息
const commonConfig = {
entry: {
index: './src/index.js'
},
resolve: {
extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
alias: {
'@': resolveApp('./src')
}
},
output: {
filename: 'js/[name].[contenthash:8].bundle.js',
path: resolveApp('./dist'),
},
optimization: {
runtimeChunk: true
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false
}
},
'postcss-loader'
],
sideEffects: true,
}
......
]
}
30、Css-TreeShaking:对 CSS 没用到的样式内容进行删除
- yarn add?purgecss-webpack-plugin?glob -D
- webpack.prod.js 配置
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const resolveApp = require('./paths')
const glob = require('glob')
module.exports = {
mode: 'development',
devtool: false,
optimization: {
usedExports: true, // 标记不被使用的函数
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
new CssMinimizerPlugin()
]
},
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
new MiniCssExtractPlugin({
filename: 'css/[name].css'
}),
new PurgeCSSPlugin({
paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),
safelist: function () {
return {
standard: ['body', 'html', 'ef']
}
}
})
]
}
31、?资源压缩?(yarn add compression-webpack-plugin -D)
// webpack.prod.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const CompressionPlugin = require("compression-webpack-plugin")
const resolveApp = require('./paths')
const glob = require('glob')
module.exports = {
mode: 'production',
optimization: {
usedExports: true, // 标记不被使用的函数
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
new CssMinimizerPlugin()
]
},
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
new MiniCssExtractPlugin({
filename: 'css/[name].css'
}),
new PurgeCSSPlugin({
paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),
safelist: function () {
return {
standard: ['body', 'html', 'ef']
}
}
}),
new CompressionPlugin({
test: /\.(css|js)$/, // 对 css 和 js 文件进行压缩
minRatio: 0.8, //压缩前体积/压缩后体积
threshold: 0,
algorithm: 'gzip' // 压缩格式
})
]
}
32、inlineChunkHtmlPlugin 使用:适用于打包的 js文件不大情况下使用,将打包的文件注入到 html????????
// webpack.prod.js
const InlineChunkHtmlPlugin = require('inline-chunk-html-plugin')
module.exports = {
mode: 'production',
optimization: {
usedExports: true, // 标记不被使用的函数
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
new CssMinimizerPlugin()
]
},
plugins: [
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime.*\.js/])
]
}
33、webpack 打包 Library?
// webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
devtool: false,
entry: './src/index.js',
output: {
filename: 'sy_utils.js', // 打包文件输出名
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd', // 对 ESModule 、 AMD、CMD 进行暴露
library: 'syUtil', // 输出一个库,为你的入口做导出
globalObject: 'this' // 将打包的文件 self 改成 this
}
}
34、打包时间和内容分析
- 打包时间插件:speed-measure-webpack-plugin
// webpack.common.js
// 时间分析
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()
// 定义对象保存 base 配置信息
const commonConfig = (isProduction) => {
return {
entry: {
index: './src/index.js'
},
......
}
}
module.exports = (env) => {
const isProduction = env.production
process.env.NODE_ENV = isProduction ? 'production' : 'development'
// 依据当前的打包模式来合并配置
const config = isProduction ? prodConfig : devConfig
const mergeConfig = merge(commonConfig(isProduction), config)
return smp.wrap(mergeConfig)
}
- 打包内容分析插件:webpack-bundle-analyzer
// webpack.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
mode: 'production',
......
plugins: [
new BundleAnalyzerPlugin()
]
}
|