Node.js 如何处理 ES6 模块

Alex799
• 阅读 2240

Node.js 如何处理 ES6 模块

作者: 阮一峰

日期: 2020年8月20日

学习 JavaScript 语言,你会发现它有两种格式的模块。

一种是 ES6 模块,简称 ESM;另一种是 Node.js 专用的 CommonJS 模块,简称 CJS。这两种模块不兼容。

很多人使用 Node.js,只会用require()加载模块,遇到 ES6 模块就不知道该怎么办。本文就来谈谈,ES6 模块在 Node.js 里面怎么使用。

Node.js 如何处理 ES6 模块

一、两种模块的差异

ES6 模块和 CommonJS 模块有很大的差异。

语法上面,CommonJS 模块使用require()加载和module.exports输出,ES6 模块使用importexport

用法上面,require()是同步加载,后面的代码必须等待这个命令执行完,才会执行。import命令则是异步加载,或者更准确地说,ES6 模块有一个独立的静态解析阶段,依赖关系的分析是在那个阶段完成的,最底层的模块第一个执行。

二、Node.js 的区分

Node.js 要求 ES6 模块采用.mjs后缀文件名。也就是说,只要脚本文件里面使用import或者export命令,那么就必须采用.mjs后缀名。Node.js 遇到.mjs文件,就认为它是 ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定"use strict"

如果不希望将后缀名改成.mjs,可以在项目的package.json文件中,指定type字段为module

 {
   "type": "module"
} 

一旦设置了以后,该目录里面的 JS 脚本,就被解释用 ES6 模块。

 # 解释成 ES6 模块
$ node my-app.js 

如果这时还要使用 CommonJS 模块,那么需要将 CommonJS 脚本的后缀名都改成.cjs。如果没有type字段,或者type字段为commonjs,则.js脚本会被解释成 CommonJS 模块。

总结为一句话:.mjs文件总是以 ES6 模块加载,.cjs文件总是以 CommonJS 模块加载,.js文件的加载取决于package.json里面type字段的设置。

注意,ES6 模块与 CommonJS 模块尽量不要混用。require命令不能加载.mjs文件,会报错,只有import命令才可以加载.mjs文件。反过来,.mjs文件里面也不能使用require命令,必须使用import

三、CommonJS 模块加载 ES6 模块

CommonJS 的require()命令不能加载 ES6 模块,会报错,只能使用import()这个方法加载。

 (async () => {
  await import('./my-app.mjs');
})(); 

上面代码可以在 CommonJS 模块中运行。

require()不支持 ES6 模块的一个原因是,它是同步加载,而 ES6 模块内部可以使用顶层await命令,导致无法被同步加载。

四、ES6 模块加载 CommonJS 模块

ES6 模块的import命令可以加载 CommonJS 模块,但是只能整体加载,不能只加载单一的输出项。

 // 正确
import packageMain from 'commonjs-package';

// 报错
import { method } from 'commonjs-package'; 

这是因为 ES6 模块需要支持静态代码分析,而 CommonJS 模块的输出接口是module.exports,是一个对象,无法被静态分析,所以只能整体加载。

加载单一的输出项,可以写成下面这样。

 import packageMain from 'commonjs-package';
const { method } = packageMain; 

五、同时支持两种格式的模块

一个模块同时要支持 CommonJS 和 ES6 两种格式,也很容易。

如果原始模块是 ES6 格式,那么需要给出一个整体输出接口,比如export default obj,使得 CommonJS 可以用import()进行加载。

如果原始模块是 CommonJS 格式,那么可以加一个包装层。

 import cjsModule from '../index.js';
export const foo = cjsModule.foo; 

上面代码先整体输入 CommonJS 模块,然后再根据需要输出具名接口。

你可以把这个文件的后缀名改为.mjs,或者将它放在一个子目录,再在这个子目录里面放一个单独的package.json文件,指明{ type: "module" }

另一种做法是在package.json文件的exports字段,指明两种格式模块各自的加载入口。

 "exports":{ 
    "require": "./index.js",
    "import": "./esm/wrapper.js" 
} 

上面代码指定require()import,加载该模块会自动切换到不一样的入口文件。

(完)

文档信息

  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证
  • 发表日期: 2020年8月20日

本文转自 http://www.ruanyifeng.com/blog/2020/08/how-nodejs-use-es6-module.html,如有侵权,请联系删除。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
小嫌 小嫌
3年前
解决node环境下SyntaxError: Cannot use import statement outside a module的问题
问题:vscode中无法利用import进行模块引入解决方式:终端执行npminity生成package.json文件,在json文件中设置"type":"module"最后执行,问题解决问题原因:node早先只支持CommonJS的模块化方案,所以ES6的模块化特性用不了。但是在NodeV13.2.0之后开始实验性的支持ESM模块化,不过需要
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
CommonJS,ES2015,AMD,CMD区别
本文你将学到:1.Rollup是什么2.CommonJS、AMD、CMD、UMD、ES6分别的介绍3.ES6模块与CommonJS模块的区别4.模块演进的产物——TreeShaking5.TreeShaking应该注意什么本文所有例子都存放于https://github.com/hua1995116
Stella981 Stella981
3年前
ES6 模块化(Module)export和import详解
ES6模块化(Module)export和import详解ES6在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Stella981 Stella981
3年前
ES6学习笔记(二十)Module 的加载实现
上一章介绍了模块的语法,本章介绍如何在浏览器和Node之中加载ES6模块,以及实际开发中经常遇到的一些问题(比如循环加载)。1.浏览器加载传统方法 HTML网页中,浏览器通过<script标签加载JavaScript脚本。<!页面内嵌的脚本<scripttype
Stella981 Stella981
3年前
Node.js 中使用 ECDSA 签名遇到的坑
文/Fenying最近有个朋友问我关于Node.js下使用ECDSA的问题,主要是使用Node.js的Crypto模块无法校验网络传输过来的签名结果。在踩坑无数后,终于搞清楚了原因。坑0x00:签名输出格式在排除了证书、消息不一致的可能之后,我开始对比使用Node.js签名的结果与网络传输过来的签