webpackbabael7转译ES6

58次阅读

共计 3257 个字符,预计需要花费 9 分钟才能阅读完成。

现在 JavaScript 代码主要采用 ES6 编写,但并不是所有浏览器都支持 ES6 语法,因此,在其中需要某种转化机制,也就是将 ES6+ 语法转化为 ES5 语法,babel7可以帮助我们做到这件事。

1、babel 介绍

babel-loader是一个 webpack 的加载器,用于将 ES6+ 转译成 ES5,要开始使用babel-loader,我们需要安装一些依赖项,以babel7 为例,有这么一些依赖:

  • @babel/core
  • @babel/preset-env
  • @babel/plugin-transform-runtime
  • @babel/polyfill

下面细说以下这些依赖具有是干什么的:
@babel/core
这是 babel 编译库的核心包
@babel/preset-env
这个包是指编译时会自动按照最新的转译规则去编译,除了这个包外还有一些规则包,比如 babel-preset-es2015(将es6javascript代码转化浏览器兼容 javascript 代码), babel-preset-es2016(将 es7javascript代码转化浏览器兼容 javascript 代码), babel-preset-es2017(将 es8javascript代码转化浏览器兼容 javascript 代码)等。
@babel/polyfill
接下来我们继续说 babel/polyfill 是个什么东东。babel官网上写了很明确一句话,babel只负责对语法进行编译。当我们写尖头函数,babel会帮你把它编译成普通函数,这没有任何问题,但是,比如说我们代码里使用了 promisebabel 打包出来的代码其实还是 promise,在低版本浏览器里,promise 并不支持,但是 babel 并不会帮你处理,因为这不是语法编译层面需要做的事情。不转换新的 API 包括,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象。
于是,如果我们要让打包出来的代码能兼容低版本浏览器,还要考虑到 promise,Set 这样的新语法低版本浏览器不兼容的问题,这时候 babel/polyfill 就出场了。你只需要全局安装一下babel/polyfill

npm install --save-dev @babel/polyfill

然后在项目中使用一下它,你的代码就不存在刚才提到的兼容性问题了。

import '@babel/polyfill'

但是,直接用 babel-polyfill 会有一些坑,第一个坑是污染全局环境,比如说低版本浏览器没有 Set,但是babel-polyfill 会在全局变量里加一个 Set。再一个问题是,会造成代码冗余,举个例子,多个模块用到Promise,每个模块里都有可能独立存在一个对Promise 做兼容性的代码。所以,使用 babel-polyfill 可以解决兼容性问题,但并不是最佳方案,于是,出现了 babel-plugin-transform-runtime,使用这个插件,就可以解决上面的问题了。
@babel/plugin-transform-runtime
为了不污染全局对象和内置的对象原型,但是又想体验使用新鲜语法的快感。就可以配合使用 babel-runtimebabel-plugin-transform-runtime。比如当前运行环境不支持 promise,可以通过引入babel-runtime/core-js/promise 来获取 promise,或者通过babel-plugin-transform-runtime 自动重写你的 promise。也许有人会奇怪,为什么会有两个runtime 插件,其实是有历史原因的:刚开始开始只有 babel-runtime 插件,但是用起来很不方便,在代码中直接引入 helper 函数,意味着不能共享,造成最终打包出来的文件里有很多重复的helper 代码。所以,Babel又开发了 babel-plugin-transform-runtime,这个模块会将我们的代码重写,如将Promise 重写成 _Promise(只是打比方),然后引入_Promise helper 函数。这样就避免了重复打包代码和手动引入模块的痛苦。

在使用 @babel/plugin-transform-runtime 之前需要安装@babel/runtime,因为前者依赖后者。

2、webpack 中配置 babel

① 安装依赖

npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime @babel/polyfill @babel/runtime--save-dev

② 在项目的根目录中创建名为 .babelrc 的新文件来配置 Babel:

{"presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-transform-runtime"]
}

③ webpack 配置 loader(加载器)

module: {
  rules: [
    {
      test: /\.js$/, // 使用正则来匹配 js 文件
      exclude: /node_modules/, // 排除依赖包文件夹
      use: {loader: 'babel-loader' // 使用 babel-loader}
    }
  ]
}

webpack.config.js 最终配置:

const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
  entry: './babel7 转义 ES6.js',
  output: {path: path.resolve(__dirname, 'build'),
    filename: 'bundle.js',
    publicPath: __dirname + '/build/'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {loader: 'babel-loader'}
      }
    ]
  },
  plugins: [new CleanWebpackPlugin() // 会删除上次构建的文件,然后重新构建
  ]
}

④ 在 app.js 全局引入 @babel/polyfill 并写入 ES6 语法,并执行 npm run build 打包

// 测试 ES6 语法是否通过 babel 转译

import '@babel/polyfill'
const array = [1, 2, 3]
const isES6 = () => console.log(...array)

isES6()

const arr = [new Promise(() => {}), new Promise(() => {})]

arr.map(item => {console.log(item)
})


全局引入 @babel/polyfill 的这种方式可能会导入代码中不需要的 polyfill,从而使打包体积更大
更改 .babelrc,只转译我们使用到的

/**
* babel 配置文件
*/
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",// 按需引入
        "corejs": "3.3.2"
      }
    ]
  ],
  "plugins": ["@babel/plugin-transform-runtime"]
}

同时,将全局引入这段代码注释掉,再次打包

// 全局引入
// import '@babel/polyfill'


参考文章:
https://zhuanlan.zhihu.com/p/35378233
https://juejin.im/post/5a96859a6fb9a063523e2591
https://www.jianshu.com/p/7bc7b0fadfc2
https://github.com/SunshowerC/blog/issues/4

正文完
 0