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-airbnbexports:["standard", //eslint-config-standard"plugin:vue/strongly-recommended", //eslint-config-airbnb],// eslint-plugin-vueplugins:[// 插件 提供一些特殊语法 如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/resourceparser: {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", // 所有的chunkminSize: 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, // 删除consoledrop_debugger: true, // 删除debuggerpure_funcs: ["console.log"] // 压缩console.log}}})]
}
tree shaking
// optimizationusedExports: true, // 只导出使用的模块