编译 ES6 基础语法
npm i @babel/core @babel/preset-env babel-loader -D
@babel/preset-env是一系列插件的集合,包含了我们在babel6中常用的es2015,es2016, es2017等最新的语法转化插件,允许我们使用最新的js语法,比如 let,const,箭头函数等等,但不包括stage-x阶段的插件。
module.exports = {
...,
module: {
rules: [
{
test: /\.js$/,
// loader: 'babel-loader '
// bower_components 是以前的一种包管理器 bootstrap
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
...
]
},
...
}
编译Class类语法
npm i @babel/plugin-proposal-class-properties -D
module.exports = {
...,
module: {
rules: [
{
test: /\.js$/,
// loader: 'babel-loader '
// bower_components 是以前的一种包管理器 bootstrap
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-class-properties']
}
}
},
...
]
},
...
}
编译 async await语法
npm i @babel/plugin-transform-runtime @babel/runtime -D / yarn add @babel/plugin-transform-runtime @babel/runtime -D
module.exports = {
...,
module: {
rules: [
{
test: /\.js$/,
// loader: 'babel-loader '
// bower_components 是以前的一种包管理器 bootstrap
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-transform-runtime'
]
}
}
},
...
]
},
...
}
编译装饰器语法
npm i @babel/plugin-proposal-decorators -D / yarn add @babel/plugin-proposal-decorators -D
module.exports = {
...,
module: {
rules: [
{
test: /\.js$/,
// loader: 'babel-loader '
// bower_components 是以前的一种包管理器 bootstrap
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-transform-runtime', // 处理async await
[
'@babel/plugin-proposal-decorators',
{
legacy: true
}
],
[
'@babel/plugin-proposal-class-properties', // 处理类的属性
{
loose: true
}
]
]
}
}
},
...
]
},
...
}
垫片
npm i @babel/polyfill -D / yarn add @babel/polyfill -D
如果JS中含有浏览器解析不了的语句,可以使用垫片,但垫片直接引入会导致编译出得包大出很多,如下面的方式一和方式二。通过方式三引入添加配置选项则会降低编译结果的体积。
方式一:入口文件顶级添加如下语句
import "@babel/polyfill";
方式二:配置文件入口处
module.exports = {
entry: {
app: ["@babel/polyfill", path.resolve(__dirname, '../src/app.js')]
}
}
方式三:添加@babel/preset-env时添加配置选项
module.exports = {
...,
module: {
rules: [
{
test: /\.js$/,
// loader: 'babel-loader '
// bower_components 是以前的一种包管理器 bootstrap
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage'
}
]
],
plugins: [
'@babel/plugin-transform-runtime', // 处理async await
[
'@babel/plugin-proposal-decorators',
{
legacy: true
}
],
[
'@babel/plugin-proposal-class-properties', // 处理类的属性
{
loose: true
}
]
]
}
}
},
...
]
},
...
}
此时运行查看会有提示信息安装core-js模块
npm i core-js@3 -D / yarn add core-js@3 -D
添加配置
module.exports = {
...,
module: {
rules: [
{
test: /\.js$/,
// loader: 'babel-loader '
// bower_components 是以前的一种包管理器 bootstrap
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs:3
}
]
],
plugins: [
'@babel/plugin-transform-runtime', // 处理async await
[
'@babel/plugin-proposal-decorators',
{
legacy: true
}
],
[
'@babel/plugin-proposal-class-properties', // 处理类的属性
{
loose: true
}
]
]
}
}
},
...
]
},
...
}
为什么要使用垫片
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。举个栗子,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。
举例Object.assign
const addProps = (target) => {
console.log(0)
console.log(target) // 装饰的类,为es5的函数
target.prototype.$nextTick = () => {
setTimeout(() => {
console.log('nextTick')
}, 1000)
}
}
@addProps
class MyTest {
state = {
list: ['a', 'b']
}
constructor () {
this.message = 'sz-gp-2004'
}
show () {
console.log(this.message)
console.log(this.state.list)
const obj = Object.assign({}, { a: 1 }, { b:2 })
console.log(obj)
}
}
const myTest = new MyTest()
// const myFn = (props) => {
// console.log(props)
// }
const myFn = (props) => {
return new Promise(resolve => {
setTimeout(() => {
resolve('hello111')
}, 2000);
})
}
export {
myTest,
myFn as default
}
// export default new MyTest()
添加垫片和不添加之后对比,发现添加垫片之后打包的app.js体积增大,说明实现相关函数
@babel/polyfill 和 @babel/preset-env 的关系
@babel/preset-env 中与 @babel/polyfill 的相关参数有 targets 和 useBuiltIns 两个
targets: 支持的目标浏览器的列表
"targets": {
"chrome": "58",
"ie": "11"
}
useBuiltIns: 参数有 “entry”、”usage”、false 三个值
默认值是false,此参数决定了babel打包时如何处理@babel/polyfilll 语句。
“entry”: 会将文件中 import @babel/polyfilll
语句 结合 targets ,转换为一系列引入语句,去掉目标浏览器已支持的 polyfilll 模块,不管代码里有没有用到,只要目标浏览器不支持都会引入对应的 polyfilll 模块。
“usage”: 不需要手动在代码里写 import @babel/polyfilll
,打包时会自动根据实际代码的使用情况,结合 targets 引入代码里实际用到部分 polyfilll 模块
false: 对 import‘@babel/polyfilll’不作任何处理,也不会自动引入 polyfilll 模块。
需要注意的是在 webpack 打包文件配置的 entry 中引入的 @babel/polyfill 不会根据 useBuiltIns 配置任何转换处理。
总结:
在业务项目中需要用到polyfill时, 可以使用和 @babel/preset-env 的 targets 和 useBuiltIns: usage 来根据目标浏览器的支持情况,按需引入用到的 polyfill 文件。
不建议使用 import @babel/polyfilll
一次性引入所有的 polyfill 文件。