npm 6.14 + Babel 7 使用

Babel官网

Babel github :https://github.com/babel/babel/tree/master/packages

Babel 在线转化:https://www.babeljs.cn/repl

Babel 是干嘛的

用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能为你做的事情:

  • 语法转换
  • 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)
  • 源码转换 (codemods)

npx

在Babel使用之前先介绍一下npx,因为后面用到npx,注意不是npm

npx是啥

npx是一种在npm中安装工具,也可以被单独的下载使用

在npm 5.2.0 的时候发现会买一送一,自动安装了npx。

也就是说 npm5.2之后,会自动安装

npx是解决什么问题的

再也不需全局安装任何工具只需要npx <commang>

为什么使用npx

全局安装劣势:

  • 占用本机空间

    npm会在machine上创建一个目录(mac是/usr/local/lib/node_modules)存放所有global安装的包, 其实node_module占用的空间比较大的

  • 版本问题:

    假如一个项目中的某一个dependency是全局安装的,也就意味着不同的开发人员使用的这个dependency版本完全基于本地的版本,也就会导致不同的开发人员使用不同的版本

使用npx的优势也就凸显出来了:

  • 当在执行

    npx <command>
    

    的时候,npx会做什么事情?

    • 帮你在本地(可以是项目中的也可以是本机的)寻找这个 command
      • 找到了: 就用本地的版本
      • 没找到: 直接下载最新版本,完成命令要求
    • 使用完之后不会在你的本机或者项目留下任何东西

因此优势总结:

  • 不会污染本机
  • 永远使用最新版本的dependency

Babel使用

配置Node项目环境

执行

npm init -y

然后项目目录下就会创建一个package.json,如

image-20201013144435261

下载相应的包的命令

npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill
 
或者简写:
 
npm install -D @babel/core @babel/cli @babel/preset-env
npm install @babel/polyfill

(--save-dev(简写-D)表示该版本只适用于开发环境中,命令会自动帮你写在package.json的devDependencies中

--save(或者不写)则表示该版本适用于生产环境中,命令会自动帮你写在package.json的dependencies中 )

如:

image-20201013144838047

使用Babel前要下载的包的意义和用法

@babel/core

Babel 的核心功能在 @babel/core模块,如果某些代码需要调用Babel的API进行转码,则就需要此模块。

用法如下

var babel = require('@babel/core');
// 字符串转码
babel.transform('code();', options);
// => { code, map, ast }

// 文件转码(异步)
babel.transformFile('filename.js', options, function(err, result) {
  result; // => { code, map, ast }
});

// 文件转码(同步)
babel.transformFileSync('filename.js', options);
// => { code, map, ast }

// Babel AST转码
babel.transformFromAst(ast, code, options);
// => { code, map, ast }

@babel/polyfill

模块包括core-js和自定义regenerator runtime 来模拟完整的 ES2015+ 环境。

Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。

举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片

@babel/preset-env

根据你需要支持的环境(配合targets中的浏览器信息)自动决定适合你的 Babel 插件

@babel/cli

@babel/cli是一个允许你从终端使用 babel 的工具。即用于命令行转码

全局安装命令

npm install -D @babel/cli -g

基本用法如下。

# 转码结果输出到标准输出(字符串形式输出)
$ babel example.js

# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ babel example.js --out-file compiled.js

# 或者
$ babel example.js -o compiled.js

# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ babel src --out-dir lib
# 或者
$ babel src -d lib

# -s 参数生成source map文件
$ babel src -d lib -s

创建配置文件

使用以下内容在项目的根目录中创建名为 babel.config.js 的配置文件:(配置文件很重要)

module.exports = function(api){
    api.cache(true)
    const presets = [
        ["@babel/env", {
          targets: {
            ie:"10",
            edge: "17",
            firefox: "60",
            chrome: "67",
            safari: "11.1"
          },
          useBuiltIns: "usage"
        }]
      ];
      const plugins = [];
      return {
        presets,
        plugins
      }
}

//target表示你想要支持的浏览器的最低型号
// useBuiltIns: "usage" ——由于polyfill包很臃肿,Babel 的此设置将检查你的所有代码,以查找目标环境中缺少的功能,并仅包含所需的 polyfill。

开始使用

创建src文件夹,再在里面创建index.js文件,并输入

(x => x * 2)(1)

在命令行中输入

//表示src整个目录转码到dist目录下
npx babel src -d dist

结果如下

image-20201013153430511

可以看到已经被成功编译

es6相关特性编译问题

class 不支持

上面安装了@babel/polyfill包 编译Promise等全局对对象没问题,但是你会发现class类 这个特性编译不了

image-20201013154717181

这是因为还缺少一个插件@babel/plugin-proposal-class-properties

安装

npm install @babel/plugin-proposal-class-properties -D

在配置文件中加入插件配置

const plugins = [
        '@babel/plugin-proposal-class-properties'
    ];

此时的babel.config.js

module.exports = function(api){
    api.cache(true)
    const presets = [
        ["@babel/env", {
            targets: {
                ie:"10",
                edge: "17",
                firefox: "60",
                chrome: "67",
                safari: "11.1"
            },
            useBuiltIns: "usage"
        }]
    ];
    const plugins = [
        '@babel/plugin-proposal-class-properties'
    ];
    return {
        presets,
        plugins
    }
}

执行编译

npx babel src -d dist

编译结果

image-20201013155825940

class 编译之后出现 require()

如果你的类比较复杂,如

class A {
    constructor() {
        console.log('A构造方法');
    }
}
class B extends A{
    constructor() {
        super();
        console.log('B构造方法')
    }
}

你运行编译命令之后,你会发现,编译完成的文件是这样的

npx babel src -d dist

image-20201013164531970

你会发现居然出现了require(),这不是node的吗,为什么编译之后会出现这个?并且你会发现直接注释掉也可以引入运行,如

image-20201014165708058

image-20201014165727184

找不到require()里面的相关文件

你顺着它引入的文件去模块里面去找,你会发现这些文件你都找不到,这是为什么,怎么解决?

image-20201014114103630

这时候你再用Babel编译一次,你会发现

npx babel src -d dist

编译有个警告

image-20201014114233820

大概意思就是没有指定corejs的版本,就是这个的原因

首先安装corejs

npm install --save core-js@3

然后在配置文件babel.config.js中加入corejs : 3的设置选项

这时候配置文件是这样的

module.exports = function(api){
    api.cache(true)
    const presets = [
        ["@babel/env", {
            targets: {
                ie:"10",
                edge: "17",
                firefox: "60",
                chrome: "60",
                safari: "11.1"
            },
            useBuiltIns: "usage",
            corejs : 3
        }]
    ];
    const plugins = [
        '@babel/plugin-proposal-class-properties',
    ];
    return {
        presets,
        plugins
    }
}

再次执行Babel编译命令

npx babel src -d dist

没有警告了

image-20201014114736338

再次打开,发现可以找到相关文件了

image-20201014114918730

但是require()还是有,浏览器不可能支持require()。babel 是怎么编译es6的模块的,怎么会出现require()?

其实就一句话:

babel 统一将 js 模块化语法转为 commonJS 风格。

从Babel 6.0开始,不再直接提供浏览器版本,需要配合webpack等构建工具使用。如果你的项目相当简单,并不需要使用构建工具,而你又想在Web项目中使用ES6的语法,Babel+Browserify可以满足你的需求。

安装Browserify

官网:http://browserify.org/

github:https://github.com/browserify/browserify

npm install browserify -D

执行Browserify编译

npx browserify ./dist/testClass.js -o test.js

结果如下image-20201014142650790

编译是编译完了,还是有require(),但是好像自己实现了,那html页面引入怎么用呢?

看了下生成的结构

image-20201014181235622

这是自调用的闭包,页面直接引入不可能可以调用的,那怎么在html直接引入调用呢?出现这种情况是为什么呢?这是因为

默认情况下,Browserify不允许从浏览器序列化代码之外访问模块。如果要调用浏览器序列化模块中的代码,则应该将代码与模块一起浏览

参考:https://cloud.tencent.com/developer/ask/109752

npx browserify ./dist/testClass.js --standalone Main -o testClass.js

设置导出到全局的模块

来到我们使用Babel编译后的文件

加入模块导出语句

例:

module.exports = B;

image-20201016160245279

执行编译
其实就是将我们导出的模块挂载到window对象下,使我们页面能够直接访问

#npx browserify [Babel编译后的文件路径] --standalone 导出的模块名 -o 导出的文件位置
npx browserify ./dist/testClass.js --standalone B -o testClass.js

页面引入执行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--<script src="./dist/testClass.js"></script>-->
    <script src="testClass.js"></script>
</head>
<body>

<script>
    console.log(B);
</script>
</body>
</html>

运行结果

image-20201016160740224

posted @ 2020-10-13 16:02  makalo  阅读(1110)  评论(0编辑  收藏  举报