主题
webpack基础配置
配置前准备
我们将webpack配置分为3部分
webpack.base.js --> 开发、生产都有的配置
webpack.dev.js --> 仅开发有的配置
webpack.prod.js --> 仅生成有的配置
webpack打包需要有一个参数mode
,值有development
和production
mode=development时,打包结果会被
eval()
函数包裹的,不利于开发,用于开发模式mode=production时,打包结果会被默认压缩混淆
当前我们正处于配置调试阶段,为了方便查看打包结果,我们需要将mode设置为 production, 且配置一下不让webpack自动压缩代码
js
/**
* @type {import('webpack').Configuration}
* @description webpack基础配置
*/
module.exports = {
mode: "production",
optimization: {
minimize: false, // 是否压缩代码,为了调试方便,配置完后删除
},
};
1. 配置入口和出口
因为
js
build/webpack.base.js
const path = require('path');
/**
* @type {import('webpack').Configuration}
*/
module.exports = {
entry: path.resolve(__dirname, '../src/main.ts'), // 入口文件
output: {
path: path.resolve(__dirname, '../dist'), // 打包后输出目录
filename: 'js/[name].[contenthash:6].js',
clean: true, // 清空上一次打包的输出目录, webpack5内置
publicPath: '/', // 打包后的资源路径前缀
}
}
2. HtmlWebpackPlugin
将publicnei d html文件创建到dist
将打包好的资源文件注入到html模板
bash
> pnpm add -D html-webpack-plugin
在build/webpack.base.js
中加入plugin
js
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
....
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"), // 模板文件
filename: "index.html", // 打包后的文件名
title: "webpack5-vue3-ts", // 页面标题
inject: true, // 是否自动注入js和css文件
}),
]
}
在public/index.html
中更改title,取值从html-webpack-plugin 插件给html中注入的title中取值
html
<title><%= htmlWebpackPlugin.options.title %></title>
3. 配置别名和解析规则 alias
js
module.exports = {
....
resolve: {
alias: {
"@": path.resolve(__dirname, "../src"), // @指向src目录
vue$: "vue/dist/vue.runtime.esm-bundler.js", // vue的运行时模块别名
},
extensions: [".ts", ".js", ".vue", ".json"], // 解析文件后缀名
modules: [path.resolve(__dirname, '../src'), 'node_modules'], // 告诉 webpack 解析模块时应该搜索的目录。
},
}
4. 配置vue解析
1)vue-loader 解析 vue
注意版本与vue的版本关系
bash
> pnpm add -D vue-loader
- 配置
vue-loader
和plugin
js
module.exports = {
...
plugins: [
...
new VueLoaderPlugin() // vue-loader插件
],
module:{
rules:[
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
}
}
2)ts-loader 编译ts为js
bash
> pnpm add ts-loader @babel/preset-typescript -D
@babel/preset-typescript
的文档 传送门一般使用了ts,都会用这个插件,更方便的处理ts
- 配置
js
module.exports = {
...
module: {
rules: [
...
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: "ts-loader",
options: {
transpileOnly: true, // 只进行类型检查,不进行编译
appendTsSuffixTo: [/\.vue$/], // 给.vue文件添加ts后缀
},
},
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-typescript",
{
allExtensions: true, // 允许所有扩展名的文件
}
]
]
}
}
]
}
...
]
}
};
3. 简单配置 js
bash
> pnpm add -D babel-loader @babel/core @babel/preset-env
- 配置
js
module.exports = {
module: {
rules: [
{
test: /\.m?jsx?$/,
exclude: /node_modules/,
loader: "babel-loader",
},
],
},
};
5. babel相关配置
到这里, 可以运行命令npx webpack -c build/webpack.base.js
命令来查看打包结果了,可以看到打包结果内的高级语法未被转译未低级语法,例如:const
这些高级语法会带来兼容性问题,需要用babel来进行语法降级
1)babel 基本配置(基本语法)
上面已经配置了babel-loader,因此我们只需要创建一个babel.config.js
文件,在里面进行配置
js
// babel.config.js
module.exports = {
presets: [
"@babel/preset-env", // 转换ES6+语法
],
};
在进行打包 npx webpack -c build/webpack.base.js
查看打包后的结果,可以看到const已经降级为 var了
2)babel处理js语言API的语法兼容(业务)
polyfill --> 从 Babel 7.4.0 版本开始,这个软件包已经不建议使用了,建议直接包含
core-js/stable
(用于模拟 ECMAScript 的功能)
babel预设只能处理一些语言层面的一些语法降级,处理不了一些API的语法降级,例如数组的map方法,reduce方法等,这些高级语法需单独用 polyfill 来处理兼容性,否则在低版本浏览器中会因为浏览器不认识这些的API导致报错甚至白屏
bash
> pnpm add core-js regenerator-runtime
注意:这里的
core-js
和regenerator-runtime
两个插件需要安装在生产依赖中,因为polyfill需要在项目源码之前运行
安装完后,在babel.config.js
中配置
js
module.exports = {
presets: [
"@babel/preset-env", // 转换ES6+语法
{
useBuiltIns: "usage", // 按需加载polyfill
corejs: 3, // 使用core-js@3
}
],
};
💡小提示
关于
useBuil
选项,共有三个值可选:
false:(默认)当使用useBuil=false时,需要在运行项目源码之前(入口文件最顶部)手动加载所有的 polyfill,体积会很大
usage:(建议)自动按需引入polyfill,不需要我们处理;
entry:需要在程序的入口最开始处手动引入需要用到的polyfill,引入的体积也会比较大,例如:
jsimport "core-js/stable"; import "regenerator-runtime/runtime";
3)polyfill 的影响
core-js + regenerator-runtime polyfill 原理 :会在某个对象的原型(例如Array.prototype)上重写一些高级语法,例如 map、reduce、filter、some、every等
影响: 在写一些库的时候,可能会对全局进行污染,但是一般写业务开发的项目不影响;
4)解决库的语法降级(库)
若是在写一个第三方库,或者npm包,上述的polyfill会对全局造成污染,那么可以用另一个插件来替代上述的polyfill
bash
pnpm add -D @babel/plugin-transform-runtime
pnpm add @babel/runtime-corejs3
注意:@babel/runtime为生产依赖 @babel/plugin-transform-runtime为开发依赖
- 配置
js
// babel.config.js
module.exports = {
presets: [
"@babel/preset-env", // 转换ES6+语法
],
plugins: [
[
"@babel/plugin-transform-runtime", // 减少代码重复,避免多次引入同一模块
{
corejs: 3, // 指定core-js版本
},
],
],
};
原理:不是重写原型上的方法,而是针对高级语法用其他途径重写方法替代,不会更改原型上的方法,避免全局的污染
5)将ts-bebal的预设也迁移到babel.config.js
由于我们现在有统一的babel配置文件,所以可以将前面的ts-loader里面的babel预设统一放到babel.config.js中,简化了webpack配置文件,也方便babel配置维护更方便
js
// webpack.base.js
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: "ts-loader",
options: {
transpileOnly: true, // 只进行类型检查,不进行编译
appendTsSuffixTo: [/\.vue$/], // 给.vue文件添加ts后缀
},
},
"babel-loader"
/* presets已经迁移到babel.config.js中了 */
// {
// loader: "babel-loader",
// options: {
// presets: [
// [
// "@babel/preset-typescript",
// {
// allExtensions: true, // 允许所有扩展名的文件
// },
// ],
// ],
// },
// },
],
},
]
}
};
js
// babel.config.js
module.exports = {
presets: [
["@babel/preset-env"], // 转换ES6+语法
[
"@babel/preset-typescript", // 转换TypeScript语法
{
allExtensions: true, // 允许所有扩展名的文件
},
],
],
plugins: [
[
"@babel/plugin-transform-runtime", // 减少代码重复,避免多次引入同一模块
{
corejs: 3, // 指定core-js版本
},
],
],
};
6. 指定浏览器兼容目标
无论是js,还是css, 在做兼容性处理的时候,babel,post-css都会有很多的polyfill代码,会影响整体的打包体积,也可能他们的默认处理并非我们想要的,所以我们需要明确告诉他们该处理兼容性到什么程度,通过.browserslistrc
文件
浏览器列表传送门
.browserslistrc
文件主要被一下工具使用
Autoprefixer
Babel
post-preset-env
eslint-plugin-compat
stylelint-unsupported-browser-features
postcss-normalize
bash
// .browserslistrc
> 1%
last 3 versions
not ie <= 11