欢迎光临
我们一直在努力

webpack 处理高级JS语法

文章目录

编译 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 文件。

赞(1) 打赏
未经允许不得转载:散人研 » webpack 处理高级JS语法
分享到: 更多 (0)

评论 抢沙发

6 + 6 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏