前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Babel:下一代Javascript语法编译器

Babel:下一代Javascript语法编译器

作者头像
江涛学编程
发布2020-07-21 15:14:31
8150
发布2020-07-21 15:14:31
举报
文章被收录于专栏:江涛的博客江涛的博客

定义

Babel是一个Javascript的编译器,通过它你可以将一些新版本的ECMAScript语法转换成低版本的语法。以便能够在低版本的浏览器或者其它环境平稳运行。

截至目前笔者写这篇文章的时候,babel的版本是7.10.0

实践

第一步:创建项目

mkdir babel-study && cd babel-study

第二步:初始化项目,并安装相关依赖包

npm init -y

npm i @babel/cli @babel/core @babel/preset-env --save-dev

相关依赖包说明:

@babel/cli: hello,你好,我是脚手架工具,我可以通过一些命令将源文件编译成目标代码。

@babel/core: hello,你好,我是一个代码分析选手,我负责将代码分析称ast,方便其他插件进行相关处理。

@babel/preset-env: hello,你好,我是一个语法转义器,我负责的内容是将JS的相关语法进行编译,关于转义新增的API和全局对象这个我不负责的。

第三步:配置.babelrc

楼下这几位就是常用的babel配置参数了,这里做简要介绍

presets(预设)

早期的版本其实是引入类似babel-preset-x,这种形式的包,现在官方推荐统一用@babel/preset-env,这个包来做语法转义器这部分的工作。

plugins(插件)

弥补babel本身上的功能不足,比如转义新增的API和全局对象可能就需要用到一些新的插件来做这部分工作,我们称之为补丁转义器。

ignore(忽略)

把不需要babel编译的文件写配置到这个参数里面,是一个数组的形式。

minified(压缩)

Boolean类型的,将其设置为true后,编译后的文件会被压缩。

comments(注释)

Boolean类型的,将其设置为true后,编译后的文件会有注释(你项目开发中写的注释)。

env(环境变量)

babel运行的环境变量,如果设置了BABEL_ENV则使用它,如果没有设置,它会去找有没有NODE_ENV,如果还是没有,那就是走默认development

这里附上一份我调研后的配置文件

代码语言:javascript
复制
{
  "presets": [[
    "@babel/preset-env", {
      // "modules": false,
      "corejs": "3",
      "useBuiltIns": "usage",
      "targets": {
        "node": "4"
        // "browsers": ["last 2 versions"]
      }
    }
  ]],
  "plugins": ["@babel/plugin-transform-runtime"],
  "env": {
    "test": {
      "presets": [[
        "@babel/preset-env", {
          "modules": false,
          "targets": {
            "node": "current",
            // "chrome": "83",
            // "edge": "17",
            // "firefox": "68",
            // "ie": "11",
            // "ios": "11.3",
            // "safari": "5.1",
            // "samsung": "9.2",
            "browsers": ["last 2 versions"]
          }
        }
      ]],
      "minified": true,  
      "comments": true,
      "ignore": ["./src/test.js"]
    },
    "development": {
      "presets": [[
        "@babel/preset-env", {
          "targets": {
            "browsers": ["last 2 versions", "safari 7"]
          }
        }
      ]]
    },
    "production": {
      "presets": [[
        "@babel/preset-env", {
          "targets": {
            "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
          }
        }
      ]],
      "plugins": ["@babel/runtime"],
      "minified": true,  
      "comments": true
    }
  }
}

这里简要说明下,modules默认为true的,在node的环境下(支持COMMONJS),如果使用ES Module的语法(import、export),然后将其设置为false,你会发现入口文件没有被编译,所有这里把它去掉了。然后targets下面你可以单独设置相关环境的支持版本,browsers的优先级高于其他的。babel7.4.0以后,废弃了polyfill,需要单独安装core-js

第四步:编写相关测试代码

这里我们测试下ES Module写法,然后一些新的API的转义情况,比如数组的include,箭头函数、模板字符串、Promise等,这里我们不考虑相关的写法是不是冗余,单纯地就是为了测试下编译效果。

animal.js

代码语言:javascript
复制
class Animal {
  constructor(name) {
    this.name = name;
  }

  eat() {
    console.log(`${this.name} is eating!`);
  }
}

export default Animal;

person.js

代码语言:javascript
复制
import Animal from './animal';

class Person extends Animal {
  constructor(name, sex) {
    super(name);
    this.name = name;
    this.sex = sex;
    this.sexMap = new Map([[1, '男'], [0, '女']]);
  }

  sing() {
    console.log(`${this.name} is singing!`);
  }

  getSex() {
    if (![0, 1].includes(this.sex)) {
      return false;
    } else {
      return this.sexMap.get(this.sex);
    }
  }

  testArr(arr) {
    return arr.map(item => item * 2);
  }

  testPromise() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(2020);
      }, 2000);
    });
  }
}

export default Person;

index.js

代码语言:javascript
复制
import Person from './person';
// 我就是试试
let ataola = new Person('ataola', 1);
ataola.eat();
ataola.sing();
const sex = ataola.getSex();
console.log(sex);
let testArr = ataola.testArr([0, 1, 2]);
console.log(testArr);
ataola.testPromise().then(res => {
  console.log(res);
});

第五步:babel-cli的使用

编译项目文件
代码语言:javascript
复制
# 单纯执行, 它会在控制台打出编译后的信息
babel index.js

# 完整写法
babel index.js --out-file bundle.js
# 简写形式
babel index.js -o bundle.js
编译项目文件夹
代码语言:javascript
复制
# 完整写法
babel src -out-dir dist
# 简写形式
babel src -d dist
# 生成sourc map文件
babel src -d dist -s
babel-node

babel-cli天然自带了一个babel-node的命令,拆分一下也就是babel + node,提供了一个支持ES6的REPL环境,你可以这么玩。

代码语言:javascript
复制
# 直接进到这个环境
babel-node

# 直接执行这个文件的代码
babel-node index.js

最后附上我的测试脚本

代码语言:javascript
复制
 ...
 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build:dir": "babel src -d dist",
    "build:dir:prod": "cross-env BABEL_ENV=production babel src -d dist",
    "build:dir:dev": "cross-env BABEL_ENV=development babel src -d dist",
    "build:dir:test": "cross-env BABEL_ENV=test babel src -d dist",
    "build:dir:s": "babel src -d dist -s",
    "build:file": "babel ./test/babel_core.test.js -o bundle.js"
  },
  ...

项目地址: https://github.com/ataola/JavaScript-Tsukuki/tree/master/code/babel-study

问题思考

在项目中使用Babel,它的作用是什么?或者这么说它的意义何在?

将高版本的JS语法转换成低版本的JS语法,可兼容不同版本的浏览器或者运行环境,划重点,解决了代码在不同版本的浏览器的兼容性问题。人的脑容量都是有限的,兼容的事情就愉快地交给它吧。

使用Babel后,把源代码编译成更复杂更难懂一坨坨的东西,我为什么要去用它?

首先,这绝对不是为了装逼,也不是为了混淆代码。我们先思考下使用高版本的语法它有什么用?有一些其实是低版本的语法糖,使用了这些我们可以减少代码量,然后减轻维护成本。但是ECMAScript它是一个语法标准,不同的JS引擎以及浏览器对它的实现和支持又不大一样,所有我们不能够保证使用高版本的语法它能够完美在各平台运行,这也就是babel的作用体现。

ES的语法有那么多版本,Babel的配置有那么多个版本,我该怎么去选择呢?

早期的预设有babel-preset-es2015、babel-preset-stage-x之类的啥的,现在官方推荐统一@babel/preset-env,脚手架统一@babel/cli,对,不成文地规定就是@babel打头基本是对的,polyfill除外。

@babel/xxx和 babel-xxx的,为什么会有两种,该用哪个?

先说结论,用前者@babel/xxx, @xxx就相当于注册了一个命名空间,特指这个是xxx下的某包,它是一个范围,是一种组织的体现形式,例如@ataola/zjt,

.babelrc文件我不写行不行,能运行吗?

如果只是创建一个.babelrc里面什么都不写,会报错,因为babel会读取里面的格式,加个{},这个是可以运行的,里面什么都不写。这里思考下babel的默认行为是什么?只是转换了Javascript的语法,而不对新的API进行转换,新的还是要用插件的。

什么是语法转义器,什么是补丁转义器?

在presets里的形如@babel/preset-env就是语法转义器,在plugins下的插件包就是补丁转义器,它们的分工不同,前者是将相关语法进行编译,后者弥补了前者的一些不足,故称之为补丁。

targets里设置browsers的优先级高,还是直接设置浏览器的优先级高?

设置browsers的优先级高于直接设置浏览器的,会覆盖后者。

为什么将modules设置成false,是否还有其他设置方案?

说明其默认为true,默认都是支持commonjs规范的。还可以设置成amd、umd之类的。

transform-runtime解决了一个什么问题?

解决了es6语法中全局对象或者全局对象方法编译不足的情况。

既然transform-runtime只是解决es6,那我要是用es7、es8、es9甚至更高怎么办呢?

babel-polyfill , core-js、regenerator-runtime

为什么不推荐全局安装脚手架?

版本更新迭代太快了,安装在项目本地易升级。

BABEL_ENV或者NODE_ENV的设置方式

代码语言:javascript
复制
# osx|linux
export NODE_ENV=production

#window
SET NODE_ENV=production

Babel的默认行为是什么?

转换了形如let、箭头函数之类的语法, 如果要完全的ES6语法支持需要安装plugin-transform-runtime插件,如果需要更高版本的话,那就需要安装polyfill插件。

参考文献

babel官网:https://babeljs.io/

@babel/preset-env文档:https://babeljs.io/docs/en/babel-preset-env/

@babel/plugin-transform-runtime:https://babeljs.io/docs/en/next/babel-plugin-transform-runtime.html

@babel/cli文档:https://babeljs.io/docs/en/babel-cli

babel配置文件:https://babeljs.io/docs/en/config-files#file-relative-configuration

babel环境变量配置:https://babeljs.io/docs/en/options#envname

@xxx npm包的解释 About Scope: https://docs.npmjs.com/about-scopes

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江涛学编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 实践
    • 第一步:创建项目
      • 第二步:初始化项目,并安装相关依赖包
        • 第三步:配置.babelrc
          • presets(预设)
          • plugins(插件)
          • ignore(忽略)
          • minified(压缩)
          • comments(注释)
          • env(环境变量)
        • 第四步:编写相关测试代码
          • 第五步:babel-cli的使用
            • 编译项目文件
            • 编译项目文件夹
            • babel-node
        • 问题思考
          • 在项目中使用Babel,它的作用是什么?或者这么说它的意义何在?
            • 使用Babel后,把源代码编译成更复杂更难懂一坨坨的东西,我为什么要去用它?
              • ES的语法有那么多版本,Babel的配置有那么多个版本,我该怎么去选择呢?
                • @babel/xxx和 babel-xxx的,为什么会有两种,该用哪个?
                  • .babelrc文件我不写行不行,能运行吗?
                    • 什么是语法转义器,什么是补丁转义器?
                      • targets里设置browsers的优先级高,还是直接设置浏览器的优先级高?
                        • 为什么将modules设置成false,是否还有其他设置方案?
                          • transform-runtime解决了一个什么问题?
                            • 既然transform-runtime只是解决es6,那我要是用es7、es8、es9甚至更高怎么办呢?
                              • 为什么不推荐全局安装脚手架?
                                • BABEL_ENV或者NODE_ENV的设置方式
                                  • Babel的默认行为是什么?
                                  • 参考文献
                                  相关产品与服务
                                  腾讯云代码分析
                                  腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
                                  领券
                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档