这是我参与更文挑战的第6天,活动详情查看: 更文挑战
前言
在前面的文章里,我们已经可以通过 js 进行 import 各种资源。现在还有个问题,就是需要将 es6+ 代码需要转译为 es5 和添加 polyfill,解决浏览器兼容性问题。而 babel 就是专门解决这个问题。
babel
由于 babel 是分为多个包,初学者一般都会被搞混,在这里,先解释各个常用的 babel 包的作用。
- @babel/core: 只会将 es6+ 语法转换为 es5 语法,但是没办法转换新 api,如:promise。
- @babel/preset-env: 智能预设,包含了一组插件,控制如何添加 polyfill(兼容新 api),可以按需添加 polyfill,不会污染全局环境和原型。
- @babel/plugin-transform-runtime: 需要和 @babel/runtime (这玩意我也不清楚是什么东东)配合使用,使辅助代码作为一个独立模块引入,可以减少编译后代码的体积。(这一块,官方文档也没有解释清楚,仅是我个人观点)
- @babel/cli: 提供 cli 命令行工具,用来通过命令行编译文件,适合安装到本地项目里(注意:该篇文章没有介绍如何使用该包)。
在一些 babel7.4+ 之前,还有一个重要的插件 @babel/polyfill,该插件已经被弃用了,在这里提醒一下大家,不需要再使用了,以免被一些旧博客误导。
- @babel/polyfill: 包括 core-js 和 regenerator runtime 模块,添加各种 es5 没有的新 api 的 polyfill,由于默认没有按需添加,因此会变得很大,这是源码之前运行的插件,需要 -S 安装。
而这些 babel 包如果需要在 webpack 项目上使用,则需要使用到 babel-loader。
使用 babel
安装 babel-loader、@babel/core、@babel/preset-env,用来将 es6+ 语法转换为 es5,并按需添加 polyfill
npm i -D babel-loader @babel/core @babel/preset-env
在 webpack 里配置以下代码,注意需要添加 exclude,防止转换 node_modules 和 bower_components 的代码,包管理下载下来的代码是不需要转换的。
webapck.config.js
module.exports = {
...
module: {
rules: [
...
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
}
如果需要添加插件,比如:@babel/plugin-proposal-object-rest-spread,可以在 options 里添加 plugins 属性引入相应的插件。
备注:该插件已经被 @babel/preset-env 包含,不需要额外安装,该插件用于对 es6 的 reset 参数和 spread 扩展运算符做处理
webpack.config.js
module.exports = {
...
module: {
rules: [
...
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-object-rest-spread']
}
}
}
]
}
}
提升 babel 转译速度
在 options 里配置 cacheDirectory 为 true,开启缓存 babel-loader 执行的结果,之后的 webpack 每次构建,都会尝试读取缓存。缓存的目录默认为项目的 node_modules/.cache/babel-loader,如果 node_modules 没有找到,则缓存到系统默认的临时文件夹(不清楚怎么更换缓存目录)。
webpack.config.js
module.exports = {
...
module: {
rules: [
...
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-object-rest-spread'],
cacheDirectory: true,
}
}
}
]
}
}
执行 npm run build,node_modules 里面生成了一些 babel 转译相关的缓存文件
减少 babel 编译后的代码体积
babel 对一些公共方法使用了一些辅助代码(如:_extend),它会默认添加到每一个需要辅助代码的文件中。需要安装 @babel/plugin-transform-runtime 和 @babel/runtime 让辅助代码作为一个独立模块引入。
npm i -D @babel/plugin-transform-runtime @babel/runtime
在 plugins 里添加 @babel/plugin-transform-runtime
webpack.config.js
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-transform-runtime'],
cacheDirectory: true,
}
}
}
完整代码
目录
webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
console.log('环境变量:', process.env.NODE_ENV)
module.exports = {
// entry: path.resolve(__dirname, '../src/js/index.js'),
entry: {
main: path.resolve(__dirname, '../src/js/index.js'),
header: path.resolve(__dirname, '../src/js/header.js'),
footer: path.resolve(__dirname, '../src/js/footer.js'),
},
output: {
// filename: 'main.js',
filename: 'js/[name].[fullhash].js',
path: path.resolve(__dirname, '../dist'),
// assetModuleFilename: 'img/[hash][ext][query]' // 全局指定资源文件输出位置和文件名
},
// devServer: {
// port: 3000,
// hot: true,
// contentBase: '../dist'
// },
plugins: [
// new HtmlWebpackPlugin({
// title: '首页'
// }),
// 配置多个 HtmlWebpackPlugin,有多少个页面就配置多少个
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/html/index.html'),
filename: 'index.html',
chunks: ['main'] // 与入口文件对应的模块名(entry 配置),这里可以理解为引入 main.js
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/html/header.html'),
filename: 'header.html',
chunks: ['header']
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/html/footer.html'),
filename: 'footer.html',
chunks: ['footer']
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].[fullhash].css'
})
],
module: {
rules: [
{
test: /\.css$/i,
use: [
//'style-loader', 'css-loader'
MiniCssExtractPlugin.loader, 'css-loader'
]
},
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'
]
},
// {
// test: /\.(jpe?g|png|svg|gif)/i,
// type: 'asset/resource',
// generator: {
// filename: 'img/[hash][ext][query]' // 局部指定输出位置
// }
// },
// {
// test: /\.(jpe?g|png|svg|gif)/i,
// type: 'asset/inline',
// },
{
test: /\.(jpe?g|png|svg|gif)/i,
type: 'asset',
generator: {
filename: 'img/[hash][ext][query]' // 局部指定输出位置
},
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 限制于 8kb
}
}
},
{
test: /\.txt/,
type: 'asset/source'
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-transform-runtime'],
cacheDirectory: true,
}
}
}
]
},
resolve: {
alias: {
'@': path.resolve(__dirname, '../src'),
// 下面可以继续新增别名
}
}
}
系列文章
webpack5 的使用(零):概念
webpack5 的使用(一):起步
webpack5 的使用(二):多个环境配置
webpack5 的使用(三):加载 css
webpack5 的使用(四):加载资源文件
webpack5 的使用(五):babel 转译 js 代码
webpack5 的使用(六):优化