muwoo/blogs

在webpack中使用babel来编译你的es6和es7

muwoo opened this issue · 0 comments

muwoo commented

你需要了解的babel

babel 是一个javaScript 编译工具,babel 已经支持最新的 javascript 版本,下面我们来介绍 babel 常用的几个工具

babel-preset-env

安装:

npm install babel-preset-env --save-dev

不需要任何配置,babel-preset-env表现的同babel-preset-latest一样(或者可以说同babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017结合到一起,表现的一致)
你也可以通过配置polyfills和transforms来支持你所需要支持的浏览器,仅配置需要支持的语法来使你的打包文件更轻量级。

{
  "presets": ["env"]
}

有了上面这些调研,我们来看一下vue-cli 脚手架里有这样一段话:

{"presets": [["env", {
      "targets": {
          "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
       }
    }]]
}

通过上面的这些研究,我们知道了:

  • ">1% " 兼容全球使用率大于1%的流览器
  • last 2 versions 兼容每个游览器的最近两个版本
  • not ie <= 8 不兼容ie8及以下

说到这里,我们开始我们第一个demo,我们来编译我们的ES6 项目:

// src/test.js
export default 'hello ES6'
//  src/index.js
import test from './test'

console.log(test)
// webpack.config.js
const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: '[name].bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
       options: {
          presets: [["env", {
            "targets": {
              "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
            }
          }]]
        }
      }
    ]
  }
}

但是随着项目的复杂度增加,我们在options里面的配置会越来越多,所以我们可以利用babel 提供的.babelrc 来提供相同的用法:

// .babelrc
 presets: [["env", {
     "targets": {
          "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
}]]

babel-polyfill

babel 本身只提供预发的转换,当我们使用一些箭头函数这样的新的语法,其实在babel看来,更像是一种语法糖。但是babel不能转义一些ES6、ES7...的新的全局属性,例如 Promise 、新的原生方法如 String.padStart (left-pad) 等。这个时候我们就需要使用babel-polyfill.

npm install --save babel-polyfill

更详细的介绍可以参考:https://babeljs.cn/docs/usage/polyfill

这里主要体积一下:
Babel 转译后的代码要实现源代码同样的功能需要借助一些帮助函数,例如,{ [name]: 'JavaScript' } 转译后的代码如下所示:

'use strict';
function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }
  return obj;
}
var obj = _defineProperty({}, 'name', 'JavaScript');

类似上面的帮助函数 _defineProperty 可能会重复出现在一些模块里,导致编译后的代码体积变大。Babel 为了解决这个问题,提供了单独的包 babel-runtime 供编译模块复用工具函数。

启用插件 babel-plugin-transform-runtime 后,Babel 就会使用 babel-runtime 下的工具函数,转译代码如下:

'use strict';
// 之前的 _defineProperty 函数已经作为公共模块 `babel-runtime/helpers/defineProperty` 使用
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var obj = (0, _defineProperty3.default)({}, 'name', 'JavaScript');

只不过那些需要修改内置api才能达成的功能,譬如:扩展String.prototype,给上面增加includes方法,就属于修改内置API的范畴。这类操作就由polyfill提供,所以项目中可以视情况选择不同的类型库