Node.js v13.2.0 开始支持ES modules了

来源:http://www.chinese-glasses.com 作者:Web前端 人气:126 发布时间:2020-03-14
摘要:时间: 2019-11-25阅读: 149标签: node写在前面 commonJS、AMD、es6模块化 区别(表格比较): Node.js 前不久发布了v13.2.0,宣布开始支持ESmodules。在此之前,想要在node中使用ESmodules,需要添加-

时间: 2019-11-25阅读: 149标签: node写在前面

commonJS、AMD、es6模块化 区别(表格比较):

Node.js 前不久发布了v13.2.0,宣布开始支持ES modules。在此之前,想要在node中使用ES modules,需要添加--experimental-module。v13.2.0版本后,可以直接使用ES modules了。

区别项 es模块化 commonJS AMD
可用于服务端还是浏览器 服务端和浏览器 服务端 浏览器
模块依赖关系何时确定(即:何时加载模块) 编译时 运行时 运行时
设计思想 尽量的静态化
模块是不是对象 不是
是否整体加载模块(即加载的所有方法)
是否是动态更新(即通过接口,可以取到模块内部实时的值) 是。es module输出的是值的引用 不是。commonJS模块输出的是值的拷贝,不存在动态更新
模块变量是否是只读的 是。原因:ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。

在node中使用ES modules

  • commonJS模块就是对象,整体加载模块(即加载的所有方法)

  • ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。

  • export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。

    // 报错
    export 1;
    // 报错
    var m = 1;
    export m;
    

    上面两种写法都会报错,因为没有提供对外的接口。第一种写法直接输出1,第二种写法通过变量m,还是直接输出1。1只是一个值,不是接口。正确的写法是下面这样。

    // 写法一
    export var m = 1;
    // 写法二
    var m = 1;
    export {m};
    // 写法三
    var n = 1;
    export {n as m};
    

    同样的,function和class的输出,也必须遵守这样的写法。

    // 报错
    function f() {}
    export f;
    // 正确
    export function f() {};
    // 正确
    function f() {}
    export {f};
    
  • export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。

    export var foo = 'bar';
    setTimeout(() => foo = 'baz', 500);
    

    上面代码输出变量foo,值为bar,500毫秒之后变成baz。
    这一点与 CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新。

  • export命令和import命令可以出现在模块的任何位置,只要处于模块顶层就可以。
    如果处于块级作用域内,就会报错,这是因为处于条件代码块之中,就没法做静态优化了,违背了ES6模块的设计初衷。

  • import命令具有提升效果,会提升到整个模块的头部,首先执行。

    foo();=
    import { foo } from 'my_module';
    

    上面的代码不会报错,因为import的执行早于foo的调用。这种行为的本质是,import命令是编译阶段执行的,在代码运行之前。

  • 目前阶段,通过 Babel 转码,CommonJS 模块的require命令和 ES6 模块的import命令,可以写在同一个模块里面,但是最好不要这样做。因为import在静态解析阶段执行,所以它是一个模块之中最早执行的。下面的代码可能不会得到预期结果。

    require('core-js/modules/es6.symbol');
    require('core-js/modules/es6.promise');
    import React from 'React';
    
  • import语句会执行所加载的模块,因此可以有下面的写法。

    import 'lodash';
    

    上面代码仅仅执行lodash模块,但是不输入任何值。

  • 如果模块名不含路径,那么import命令会去node_modules目录寻找这个模块。

    import 'baz';
    import 'abc/123';
    

    如果模块名包含路径,那么import命令会按照路径去寻找这个名字的脚本文件。

    import 'file:///etc/config/app.json';
    import './foo';
    import './foo?search';
    import '../bar';
    import '/baz';
    
  • 如果脚本文件省略了后缀名,比如import './foo',Node 会依次尝试四个后缀名:./foo.mjs、./foo.js、./foo.json、./foo.node。
    如果这些脚本文件都不存在,Node 就会去加载./foo/package.json的main字段指定的脚本。
    如果./foo/package.json不存在或者没有main字段,那么就会依次加载./foo/index.mjs、./foo/index.js、./foo/index.json、./foo/index.node。
    如果以上四个文件还是都不存在,就会抛出错误。

想要在项目中使用ES modules,有以下两种方法:

1、文件后缀名使用.mjs

举个例子,假设项目目录如下:

.|____component| |____a.mjs|____index.mjs

文件内容如下:

// component/a.mjslet a = 'This is component a';export default a;// index.mjsimport a from './component/a.mjs';console.log(a);

执行node index.mjs,代码可以正确执行,输出如下:

(node:77465) ExperimentalWarning: The ESM module loader is experimental.This is component a

2、文件依然使用.js的后缀名,在项目的package.json中设置:type:module

项目目录如下:

.|____component| |____a.js|____package.json|____index.js

各个文件内容如下:

// component/a.jslet a = 'This is component a';export default a;// index.jsimport a from './component/a.mjs';console.log(a);// package.json{ ... "type": "module", // 必须要有这一行 ...}

执行node index.js,代码可以正确执行,输出如下:

(node:78977) ExperimentalWarning: The ESM module loader is experimental.This is component a

如果在命令行使用ES module,需要加上--input-type=module。举个例子:

node --input-type=module--eval"import { sep } from 'path'; console.log(sep);"

需要注意的是,目前,ES module的实现还是实验性质的,后续有随时调整的可能。Import

import引入ES module时,支持以下几种方式:

10bet,相对路径 (./file.mjs)绝对路径 (file:///opt/app/file.mjs)模块名 (es-module-package’)模块内路径 (es-module-package/lib/file.mjs)

本文由10bet发布于Web前端,转载请注明出处:Node.js v13.2.0 开始支持ES modules了

关键词:

频道精选

最火资讯