在npm script中使用babal编译你的代码

在前端开发领域,浏览器兼容性问题来来去去,未曾消失过。除了 CSS,咱们还要面对 JavaScript 的兼容性问题:你用了 JavaScript 的 A 特性,可以在 B 浏览器上正常运行,却在 C 浏览器的 D 版本上报错。前端

@babel/cli是 babel 提供的命令行工具,用于命令行下编译源代码。node

这里假定咱们已经过 npm init 初始化项目。 首先,在项目中安装@babel/cli:git

npm install --save-dev @babel/core @babel/cli
复制代码

若是你用过 babel 6,可能要问,怎么不是 npm install --save-dev babel-cli?@ 符号又是什么?这是 babel 7 的一大调整,原来的 babel-xx 包统一迁移到babel 域下 - 域由 @ 符号来标识,一来便于区别官方与非官方的包,二来避免可能的包命名冲突。npm

如今假定咱们的项目下有一个 script.js 文件,内容是:json

let fun = () => console.log('hello babel.js')
复制代码

咱们试试运行 npx babel script.js:api

$ npx babel script.js
let fun = () => console.log('hello babel.js');
复制代码

这个调整则是在 babel 6 里发生的。Babel 6 作了大量模块化的工做,将原来集成一体的各类编译功能分离出去,独立成插件。这意味着,默认状况下,当下版本的 babel 不会编译代码。浏览器

现有以下伪代码:bash

class classApi{
  //格式化时间 
  static formdatatime = (time)=>{
    let date = new Date(time * 1000)
    const getDoubleDigit = curr => curr < 10 ? `0${curr}` : curr;
    return `${date.getFullYear()}-${getDoubleDigit(date.getMonth() + 1)}-${getDoubleDigit(date.getDate())} ${getDoubleDigit(date.getHours())}:${getDoubleDigit(date.getMinutes())}:${getDoubleDigit(date.getSeconds())}`
  } 
  // 构造函数
  constructor(localItem){
      this.initData(localItem);
      this.initParams();
  }
  // 获取参数的具体规则
  generateParams(params){
   
  }
  // 获取参数的代理方法
  ProxyParams(key){
    
  }
  //主函数 用于生成具体的api
  main(key){
    
  }
  // 初始化数据
  initData(localItem){
    
  }
  //初始化参数 apiObject对象是须要维护的对象
  initParams(){
    
  }
  // 生成api的工厂
  generateApi(){
    
  }
}

const classApiObject = new classApi("roomData");
classApiObject.generateApi();
复制代码

使用以下命令编译babel

npx babel --no-babelrc dist/classApi.js --out-dir dist --presets=@babel/preset-env --plugins=@babel/plugin-proposal-class-properties
复制代码

--no-babelrc : 表示不使用babelrc --out-dir : 指定编译输出目录 --presets : 指定babel的预设 --plugins: 指定babel 插件app

则生层以下代码

"use strict";

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

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 classApi =
/*#__PURE__*/
function () {
  //格式化时间 
  // 构造函数
  function classApi(localItem) {
    _classCallCheck(this, classApi);

    this.initData(localItem);
    this.initParams();
  } // 获取参数的具体规则


  _createClass(classApi, [{
    key: "generateParams",
    value: function generateParams(params) {
 
    } // 获取参数的代理方法

  }, {
    key: "ProxyParams",
    value: function ProxyParams(key) {
      
    } //主函数 用于生成具体的api

  }, {
    key: "main",
    value: function main(key) {
     
    } // 初始化数据

  }, {
    key: "initData",
    value: function initData(localItem) {
     
    } //初始化参数 apiObject对象是须要维护的对象

  }, {
    key: "initParams",
    value: function initParams() {
      
    } // 生成api的工厂

  }, {
    key: "generateApi",
    value: function generateApi() {
      
    }
  }]);

  return classApi;
}();

_defineProperty(classApi, "formdatatime", function (time) {
  var date = new Date(time * 1000);

  var getDoubleDigit = function getDoubleDigit(curr) {
    return curr < 10 ? "0".concat(curr) : curr;
  };

  return "".concat(date.getFullYear(), "-").concat(getDoubleDigit(date.getMonth() + 1), "-").concat(getDoubleDigit(date.getDate()), " ").concat(getDoubleDigit(date.getHours()), ":").concat(getDoubleDigit(date.getMinutes()), ":").concat(getDoubleDigit(date.getSeconds()));
});

var classApiObject = new classApi("roomData");
classApiObject.generateApi();
复制代码

babel-polyfill

babel-polyfill 其实包含regenerator runtime、core-js,若是你的代码只须要其中一部分 polyfill,那么你能够考虑直接引入 core-js 下的特定 polyfill,没必要使用 babel-polyfill 这样的庞然大物。

另外一种办法,是配合 @babel/preset-env 的 useBuiltIns 配置 固然你还能够引入cdn上的包

babel-runtime

@babel/runtime 是 babel 生态里最让人困惑的一个包。而在 babel 7 下,咱们还多了一个 @babel/runtime-corejs2。 咱们先来看看 @babel/runtime 的 package.json 里的 description 怎么写:

babel's modular runtime helpers

有点不知所谓。

不过从 package.json 里没有 main 字段咱们能够看出,它的用法确定不是 require('babel-runtime') 这样。

那么,babel-runtime 与 babel-polyfill 的区别到底是什么?

咱们知道,IE 11 不支持 Object.assign,此时,咱们有俩种候选方案:

  1. 引入 babel-polyfill,补丁一打,Object.assign 就被创造出来
  2. 配置 @babel/plugin-transform-object-assign

第二种方案中,babel 会将全部的 Object.assign 替换成 _extends 这样一个辅助函数。以下所示:

Object.assign({}, {})
复制代码

编译成:

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

_extends({}, {});
复制代码

问题是,若是你的项目里有 100 个文件,其中有 50 个文件里写了 Object.assign,那么,坏消息来了,_extends 辅助函数会出现 50 次。

怎么办?咱们天然而然会想到把 _extends 分离出去,而后在每一个文件中引入 - 这正是 @babel/runtime 的做用: 很是漂亮。可没人想要手动转换这些代码。

因而 babel 提供了 @babel/plugin-transform-runtime 来替咱们作这些转换。

这样,咱们不须要 babel-polyfill 也同样能够在程序中使用 Object.assign,编译后的代码最终可以正常运行在 IE 11 下。

提问:在通过 @babel/plugin-transform-runtime 的处理后,IE 11 下如今有 Object.assign 吗?

答案是,仍然没有。

这正是 babel-polyfill 与 babel-runtime 的一大区别,前者改造目标浏览器,让你的浏览器拥有原本不支持的特性;后者改造你的代码,让你的代码能在全部目标浏览器上运行,但不改造浏览器。

若是你仍是困惑,我推荐一个很是简单的区分方法 - 打开浏览器开发者工具,在 console 里执行代码:

引入 babel-polyfill 后的 IE 11,你能够在 console 下执行 Object.assign({}, {})
而引入 babel-runtime 后的 IE 11,仍然提示你:Object doesn't support property or method 'assign'
复制代码

babel-register

通过 babel 的编译后,咱们的源代码与运行在生产下的代码是不同的。

babel-register 则提供了动态编译。换句话说,咱们的源代码可以真正运行在生产环境下,不须要 babel 编译这一环节。

咱们先在项目下安装 babel-register:

$ npm install --save-dev @babel/register
复制代码

而后在入口文件中 require

require('@babel/register')
require('./app')
复制代码

在入口文件头部引入 @babel/register 后,咱们的 app 文件中便可使用任意 es2015 的特性。 固然,坏处是动态编译,致使程序在速度、性能上有所损耗

babel-node

咱们上面说,babel-register 提供动态编译,可以让咱们的源代码真正运行在生产环境下 - 但其实否则,咱们仍须要作部分调整,好比新增一个入口文件,并在该文件中 require('@babel/register')。而 babel-node 能真正作到一行源代码都不须要调整:

$ npm install --save-dev @babel/core @babel/node
$ npx babel-node app.js
复制代码

只是,请不要在生产环境中使用 babel-node,由于它是动态编译源代码,应用启动速度很是慢。

写在最后 欢迎加我wx wangchen20180818 交流,学习

相关文章
相关标签/搜索