write once,run everywhere--Babel 7.x

417 阅读6分钟

我这一生都在等待着,只是不知道到底在等谁  --- 幸福终点站

作为程序猿,对象从来都是 new 啊! 😂😂😂

const GF = new Object();
GF.happy(console.log("see a film with you On this Chinese Valentine's Day"));

前言

曾几何时,compile once,run everywhere 的 java 魅力无穷,吸引着很多的有志之士投入到其麾下。那时,javascript 还在为规范到底遵循谁打的热火朝天,ie 浏览器从引领 javascript 发展,到后来被嫌弃的不要不要的,写个代码还要考虑是否需要考虑兼容 ie (当然不止 ie ,这里只是为了嫌弃 ie)确实会让人奔溃。随着 Neo (Node) 的出现,自此 javascript 的发展迅速,竟有与 java 一争世界最好语言之实力。许多有志之士夜以继日苦思冥想 write once,run everywhere,终得解决之法---Babel。前端工程师喜大普奔,奔走相告,越来越多的前端工程师与产品经理握手言和。自此 javascript 一扫当初疲态,在高级语言的争霸中显露峥嵘,竟有称王之势。

随意杜撰的,😉😉😉,想想三个月之前下定决心全栈,一路走来,已被 javascript 的魅力所折服,竟有想放弃 java 的念头(俺只是担心以后光头啊,只有光(熬)头(夜)才能变强)

package.json

第一次接触 javascript 的时候,心里是很抵触的,一想我心爱的 java 有 maven 作为依赖管理,我还在 html 中引入 javascript 文件,引入之前还要去依赖库下载对应版本的类库,嫌弃之情溢于言表。后来了解到了 package.json,Neo(Node) 救世主之名绝非浪得虚名啊。

{
   "name": "fly-babel",
   "version": "1.0.0",
   "main": "index.js",
   "license": "MIT",
   "private": true,
   "scripts": {
       "babel": "./node_modules/.bin/babel src --out-dir lib"
   },
   "dependencies": {
       "@babel/runtime": "^7.5.5",
       "core-js": "3"
   },
   "devDependencies": {
       "@babel/cli": "^7.5.5",
       "@babel/core": "^7.5.5",
       "@babel/plugin-transform-runtime": "^7.5.5",
       "@babel/preset-env": "^7.5.5"
   }
}

运行 yarn babel 将 src 下面的代码编译输出到 lib

scripts 主要是用于运行脚本的。比如 yarn babel 或 yarn run babel 或 npm run babel

dependencies 主要是写的代码所需依赖库,比如你引用的工具类库 lodash ,项目打包的时候,这些依赖会打包进项目中

devDependencies 是开发环境依赖,最终打包不会打到项目中

yarn

yarn 中文文档

一款比 Npm 更智能强大的依赖包管理器,用的人都说好,谁用谁知道

yarn 初始化项目

yarn init

全局安装 yarn

# Mac 真是开发利器啊
brew install yarn

# 使用 npm 安装
npm install -g yarn

验证 yarn 是否安装成功

yarn --version

配置淘宝镜像

yarn config set registry http://registry.npm.taobao.org/

安装项目依赖

yarn install

添加项目依赖

# 添加最新版本 lodash 到生产依赖
yarn add [package]
# 添加指定版本
yarn add [package]@[version]
yarn add lodash

添加开发环境依赖

yarn add --dev [package]
# 添加 lodash 到开发依赖
yarn add --dev lodash

升级项目依赖

# 图形化界面
yarn upgrade-interactive --latest

yarn upgrade [package]

# 升级到指定版本
yarn upgrade [package]@[version]

移除依赖

yarn remove [package]

# 移除 lodash
yarn remove lodash

运行 package.json 中的自定义命令

yarn run 
yarn run babel
yarn babel

Babel

记得使用是 Babel 7.x

Bablel 中文官方网站

Babel 在线转换

答应我,官方网站资料一定要看哦,毕竟是一手资料。可以先在在线转换上体验下,class 到底编译成了什么,推荐看下 Babel 7使用总结,官方文档加这篇资料差不多就明白了 Babel 了。

安装依赖

# 安装开发依赖
yarn add --dev @babel/core @babel/cli @babel/preset-env @babel/runtime @babel/plugin-transform-runtime

# 安装项目依赖
yarn add core-js @babel/runtime

配置文件选择---babel.config.js

js 文件可以使用 javascript ,可扩展性较高,可以使用 node 的 api。

.babelrc 是 json 格式,连注释都加不了,难搞哦。不过项目中的子项目还是可以用.babelrc,babel.config.js 作为整个项目全局配置。

// babel.config.js 配置文件
/**
 * @author: 张攀钦
 * @description: babel 全局配置
 * 1、plugins优先于presets进行编译;
 * 2、plugins按照数组的index增序(从数组第一个到最后一个)进行编译;
 * 3、presets按照数组的index倒序(从数组最后一个到第一个)进行编译,
 */
module.exports = function (api) {
    api.cache(true);
    const babelrcRoots = [
        // Keep the root as a root
        ".",

        // Also consider monorepo packages "root" and load their .babelrc files.
        "./packages/*"
    ]
    const presets = [
        [
            "@babel/preset-env",
            {
                // 配置需要兼容的环境
                // chrome, edge, firefox, safari, ie, ios, node,android
                targets: {
                    ie: "8",
                    chrome: "67",
                    "browsers": ["> 1%", "last 2 versions", " ie>8", "android >= 4.0", "ios >= 7"]
                },
                // 是否输出启用的plugins列表
                debug: true,
                loose: true,
                // 模块使用 es modules ,配置为 "auto" 使用 commonJS 规范,
                modules: false,
                // 垫片使用 core.js
                corejs: 3,
                // 按需加载运用 polyfill
                useBuiltIns: "usage",
            },
        ],
    ];
    const plugins = [["@babel/plugin-transform-runtime", {
        corejs: 3,
        absoluteRuntime: false,
        helpers: true,
        regenerator: true,
        // 使用 es modules helpers
        useESModules: true
    }]];
    // 测试取 Node 相关变量
    if (process.env.NODE_ENV === "development") {
        console.log('开发环境', process.env);
    }
    return {
        presets,
        plugins, babelrcRoots
    };
}

这是我目前使用的配置,以后添加新的东东了,再来补充

presets 引入一些常用插件集合,@babel/preset-env 这个包含 es 中常用的语法转换(@babel/preset-env则默认情况下将转换所有ECMAScript 2015+代码。),而不用一个个添加到 plugins

plugins 引入特殊的插件进行垫片

小试牛刀

  • 源码文件
[1, 2, 3].map((n) => n + 1);
class FlyYou {
    fly () {
        console.log('m fly you');
    }

    static sleep () {
        console.log('m sleep');
    }
}
console.log(Object.assign({}, { age: 1 }));
const arr = [1, 2, 3];
console.log('arr 是否包含 1:', arr.includes(1));
Promise.resolve('demo-1.js-Promise.resolve').then(data => console.log(data));
  • Babel 转义之后的代码
import "core-js/modules/es.object.to-string";
import "core-js/modules/es.promise";
import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign";
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";

var _context;

_mapInstanceProperty(_context = [1, 2, 3]).call(_context, function (n) {
  return n + 1;
});

var FlyYou =
/*#__PURE__*/
function () {
  function FlyYou() {}

  var _proto = FlyYou.prototype;

  _proto.fly = function fly() {
    console.log('m fly you');
  };

  FlyYou.sleep = function sleep() {
    console.log('m sleep');
  };

  return FlyYou;
}();

console.log(_Object$assign({}, {
  age: 1
}));
var arr = [1, 2, 3];
console.log('arr 是否包含 1:', _includesInstanceProperty(arr).call(arr, 1));

_Promise.resolve('demo-1.js-Promise.resolve').then(function (data) {
  return console.log(data);
});
  • 转义分析
import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
_Promise.resolve('demo-1.js-Promise.resolve').then(function (data) {
  return console.log(data);
});

这个代码是没有办法单独在浏览器运行的,需要结合 webpack 将依赖打包运行。我们可以看到 Promise 被 _Promise 替换,这个就是垫片(polyfill),意思就是引入新的依赖,来检查运行环境是否有 Promise 实现,有的话用原生的 Promise ,没有的话用依赖库(@babel/runtime-corejs3/core-js-stable/promise)实现的 Promise 。

@babel/polyfill 与 @babel/runtime 区别

二者都会提供垫片,但是 @babel/polyfill 会检查运行环境是否实现了 api,没有的话会直接修改原型或添加对象到 window。@babel/runtime 不会污染全局变量,Babel 7.X 二者选其一即可。推荐用 @babel/runtime。

举个例子,比如 ie 没有实现 Promise,你使用 @babel/polyfill编译之后的代码,是可以直接在浏览器控制台访问 Promise ,而 @babel/runtime 不会污染全局变量,控制台访问不到 Promise。