webpack
解决的问题
- 编译浏览器无法理解的东西
ES6、ts、.vue
- 代替一些人工操作
文件合并与拆分、图片压缩、资源处理、代码转换等
- 帮助开发
提供本地服务器、热更新、代理
配置项
- entry 入口(必须项)
- output 出口(必须项)
- module loader编写的地方
- plugins 插件
- mode 模式(必须项)
- development 开发模式下,Webpack 会自动优化打包速度,添加一些调试过程中的辅助;
- production 生产模式下,Webpack 会自动优化打包结果;(例如:代码的压缩混淆等)
- none Webpack 就是运行最原始的打包,不做任何额外处理;
- optimization 优化
- devServer 开发模式配置
- resolve 解析提供一些简化功能
文件后缀别名等
- cache 缓存
缓存生成的 webpack 模块和 chunk,来改善构建速度
- devtool
是否生成,以及如何生成 source map。
处理JS
- es6 转换
babel-loader
安装:@babel/preset-env
用来转换es6语法到这个版本,需要配置(可以卸载babel配置文件中),不然不会进行转换
npm install --save-dev babel-loader @babel/core @babel/preset-env
配置:
{
test: '/\.js$/',
use: {
loader: "babel-loader",
options: { // babel 配置
presets:[
[
'@babel/preset-env',
{
targets:{
browsers: [
">1%", // 占有率大于1%
"last 2 versions",// 支持浏览器最后两个版本
"not ie<=8"// 不支持ie8及之前的浏览器
]
}
}
]
]
}
}
}
- 代码规范
eslint-loader(webpack5 废弃),使用
eslint-webpack-plugin
安装:eslint-webpack-plugin
npm install --save-dev eslint-webpack-plugin eslint
配置:
// webpack.config.js
const ESLintPlugin = require('eslint-webpack-plugin');
new eslintPlugin()
规范:
定义不同规则,可在开源规则中继承
//.eslintrc.ts
module.exports = {
env: {
browsers: true, //环境 浏览器环境,
es2021: true //版本
},
// 继承 如
// eslint-config-standard
// eslint-config-airbnb
exports:[
"standard", //eslint-config-standard
"plugin:vue/strongly-recommended", //eslint-config-airbnb
],
// eslint-plugin-vue
plugins:[// 插件 提供一些特殊语法 如Vue书写规则
"vue"
],
parserOptions: {
ecmaVersion: 6, //版本
sourceType:'module', //模块
ecmaFeatures: {
jsx: true //是否使用jsx
}
},
rules: {
}
}
处理TS
- 安装
npm install --save-dev typescript ts-loader
- 配置
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
处理css
css-loader 解析css文件,将css文件变成js模块
之后有两种方式:
style-loader 将css作为 style 插入到html中
mini-css-extract-plugin 提取css到单独的文件中
- 安装
npm install --save-dev style-loader css-loader mini-css-extract-plugin
- 配置
const miniCssExtractPlugin = require("mini-css-extract-plugin")
// module.rules
{
test: /\.css$/,
use: ['miniCssExtractPlugin.loader', 'css-loader']
}
// plugins
new miniCssExtractPlugin({ // css 处理
filename: "[name].bundle.css"
})
css预编译处理:
先将sass/scss/less 编译成css文件,然后再进行css处理
- sass-loader
安装:
npm install --save-dev sass sass-loader
配置:{ test: /\.scss$/, use: ['style-loader', 'css-loader','sass-loader'] }
- less-loader
安装:
npm install --save-dev less less-loader
配置:{ test: /\.less$/, use: ['style-loader', 'css-loader','less-loader'] }
css压缩:
- css-minimizer-webpack-plugin
安装:
npm install --save-dev css-minimizer-webpack-plugin
配置:
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
"default",
{
discardComments: { removeAll: true },
},
],
},
})
资源文件处理
webpack5 自带了资源文件处理,不需要再配置。
- 图片
file-loader 处理图片文件,将图片文件变成base64的字符串,然后将字符串插入到js中
url-loader 处理图片文件,将图片文件变成base64的字符串,然后将字符串插入到js中,但是如果图片大小超过了limit,则会将图片文件变成base64的字符串,然后将字符串插入到js中
- 优化操作
图片操作:
使用webpack自带的,只用配置type即可
type:
asset: 根据配置决定
asset/inline: 全部转换为base64的字符串
asset/resource: 使用图片地址
// 资源文件 webpack自带
{
test: '/\.(jpg|jpeg|png|gif|svg)$/',
type: "asset" ,// asset/inline asset/resource
parser: {
dataUrlCondition: {
maxSize: 5000 // 大小零界配置
}
},
generator: {
filename: "[name].[hash][etx]" // 本名 + hash + 后缀
}
}
html处理
使用插件 html-webpack-plugin
- 提供一个html模板,复用固定内容
- 打包生成一个html
- 打包出来的html自动引入js
安装
npm install --save-dev html-webpack-plugin
配置
// plugins
// html
new HtmlWebpackPlugin({
template: "./public/index.html", //用来做模板的html的文件路径(从项目根目录开始)
filename: "index.html", //生成的html的名字
title:'vue3+webpack5',// 标题名称
inject: "body" // 打包出来的那个js文件,放置在生成的body标签内
})
vue 处理
- 安装
npm install --save-dev vue-loader @vue/compiler-sfc
- 配置
// module.rules
{
test: /\.vue$/,
use: 'vue-loader'
}
// plugins
new VueLoaderPlugin()
loader 本质
loader 本质就是一个函数,接受源文件作为参数,返回转换后的结果
代码分割
用来将代码分割成多个文件,然后再进行打包,然后再进行代码分割,这样可以减少首屏加载时间
- 异步加载
import("./home").then(({default:home})=>{
console.log(home)
})
- 动态导入
import(/* webpackChunkName: "home" */ "./home")
- 路由懒加载
const Home = () => import(/* webpackChunkName: "home" */ "./home")
- 代码分割
runtime + vendor + 核心代码 + 异步代码
// optimization
splitChunks: { // 项目代码
chunks: "all", // 所有的chunk
minSize: 20000, // 最小的chunk大小
minChunks: 1, // 最少的chunk数量
maxAsyncRequests: 5, // 最多的异步请求数量
maxInitialRequests: 3, // 最多的初始请求数量
automaticNameDelimiter: "~", // 分割符
cacheGroups: { // 缓存组
defaultVendors: { // 第三方库
test: /[\\/]node_modules[\\/]/,
priority: -10, // 优先级
name: "vendors"
},
default: { // 公共库
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
},
runtimeChunk: { //webpack运行时代码
name: 'runtime'
}
技巧性配置
文件hash : 解决缓存问题,在浏览器中缓存文件,下次访问时,直接从缓存中获取,不用重新请求服务器,导致重复从缓存中获取。
使用 [chunkhash] 控制只有当前文件改变时,才会更改文件hash
resolve 配置
- alias 别名
alias:{
"@": "/src"
},
- extensions 后缀名
extensions: ['.tsx', '.ts', '.js']
批量引入指定文件下的所有文件
require.context(<路径>, <是否递归>, <匹配的文件>)
const r = request.context("./model", false, /.js/)
const keys = r.keys()
const value = r(keys[0])
将打包结果放入某个文件下
在 filename 配置中前面添加路径
filename: "./css/[name].bundle.css"
CDN引入加前缀
// output
publicPath: 'URL_ADDRESS'
开发模式
- devServer
devServer: {
hot: true, // 热更新
open: true, // 启动服务打开浏览器
port: 8080, // 端口
host: "localhost", // 地址
proxy: { // 代理
"/": {
target: "http://localhost:3000/", // 代理地址
pathRewrite: { //路径重写
"^/num": "/api/getNum"
},
headers:{ //请求头
}
}
}
},
- devtool
devtool: "eval-cheap-source-map",
区分环境
- 生产模式
代码压缩、tree shaking、代码混淆
- 开发模式
热更新、source map
区分环境:
- 根据不同环境不同打包 process.env.NODE_ENV
- JS获取环境 webpack 提供的插件
将开发环境和生产环境的配置分离,再将公共配置导入,形成不同的配置文件,
最后在不同的环境中使用不同的配置文件。
webpack提供了合并工具 merge
// 开发环境
// webpack.dev.config.js
const merge = require("webpack-merge")
const baseConfig = require("./webpack.base.config.js")
module.exports = merge(baseConfig, {
mode: "production",
})
// 生产环境
// webpack.prod.config.js
const merge = require("webpack-merge")
const baseConfig = require("./webpack.base.config.js")
module.exports = merge(baseConfig, {
mode: "production",
devtool: "source-map",
devServer: {
hot: true,
open: true,
port: 8080,
host: "localhost",
proxy: {
"/": {
target: "URL_ADDRESS",
pathRewrite: {
"^/num": "/api/getNum"
}
}
}
}
})
配置环境变量
- 安装:
npm install --save-dev cross-env dotenv
dotenv: 读取.env文件环境变量
cross-env:指令跨平台库
NODE_ENV 可以通过process.env.NODE_ENV获取环境变量
// package.json
"scripts": {
"dev": "cross-env NODE_ENV=dev webpack-dev-server --config webpack.dev.config.js",
"build": "cross-env NODE_ENV=prod webpack --config webpack.prod.config.js"
}
if (process.env.NODE_ENV === "dev") {
console.log("dev")
}
打包优化
打包分析
- 安装:
npm install --save-dev webpack-bundle-analyzer
- 配置:
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
// plugins
new BundleAnalyzerPlugin()
dll优化
dll:动态链接库
先将第三方库打包成一个dll文件,然后再将dll文件引入到项目中,这样就可以减少打包时间。
dll-plugin webpack已经提供了dll插件
- 配置:
// webpack.dll.config.js
const webpack = require("webpack");
// plugins
new webpack.DllPlugin({
name: "dll", // 生成的dll文件的名字
path: path.resolve(__dirname, "dll", "manifest.json") // 生成的dll文件的路径
context: __dirname // 上下文
})
// package.json
"scripts": {
"dll": "webpack --config webpack.dll.config.js"
}
// 生产环境引用
// webpack.prod.config.js
const path = require("path");
const webpack = require("webpack");
//plugins
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "dll", "manifest.json")
})
dll打包的东西需要手动在index.html中引入
<!-- index.html -->
<script src="./dll/vendors.dll.js"></script>
代码压缩混淆
- 安装:
npm install --save-dev terser-webpack-plugin
,webpack5自带了
const TerserPlugin = require('terser-webpack-plugin');
// optimization
optimization: {
minimize:true,// 压缩代码
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // 删除console
drop_debugger: true, // 删除debugger
pure_funcs: ["console.log"] // 压缩console.log
}
}
})
]
}
tree shaking
// optimization
usedExports: true, // 只导出使用的模块