Node.js 12中的ES模块[每日前端夜话0x9E]

Stella981
• 阅读 1008

每日前端夜话****0x9E

每日前端夜话,陪你聊前端。

每天晚上18:00准时推送。

正文共:2552 字

预计阅读时间:10 分钟

作者:Brian De Sousa

翻译:疯狂的技术宅

来源:logrocket

Node.js 12中的ES模块[每日前端夜话0x9E]

ES Modules In Node.js 12

多年来,在 JavaScript 生态中出现了不同形式的模块化方案。开发人员使用了明确定义的规范(如 AMD 或 CommonJS)以及简单的编码模式(如通过揭示模块模式(revealing module pattern))来得到模块化解决方案的好处。

模块可以在浏览器的客户端使用,也可以在 Node.js 的服务器端使用。有时也使用像 Babel 这样的工具将代码从一种模块格式转换为另一种格式。所有这些都使得混乱的 JavaScript 模块状态变得更加混乱。

提示:本文重点介绍 Node.js 中的 ES 模块。你可以通过查看“CommonJS vs AMD vs RequireJS vs ES6 Modules”来更好的比较模块系统。【https://medium.com/computed-comparisons/commonjs-vs-amd-vs-requirejs-vs-es6-modules-2e814b114a0b】

一段简短的历史

先让我们来看看 ES 模块支持的关键里程碑:

  • 2015年6月:ES 模块在 ECMAScript 的 ES2015 规范中定义【http://www.ecma-international.org/ecma-262/6.0/index.html】。

  • 2015年6月 -  2017年9月:主要浏览器为隐藏在开发者标志后面的 ES 模块添加实验性支持。用 ES 模块开发 JavaScript 的主要方法是通过像 Babel 这样的工具来转换代码。

  • 2017年9月:Node.js v8.5包含 ES 模块的实验性支持。

  • 2017年9月 -  2018年5月:主要浏览器开始支持 ES 模块规范,没有开发者标志,包括:

    2018年10月:创建了一个新的模块实施计划。该计划包括几个阶段,从一开始就遵循三个指导原则,用新的实施方案取代当前的实验性实施方案:

  1. 遵守 ES 规范

  2. Node 应尽可能的以和浏览器相同的方式执行操作

  3. 不破坏现有的 CommonJS 模块

  4. Chrome 61,2017年9月5日

  5. Safari 11,2017年9月18日

  6. Firefox 60,2018年5月8日

提示:Node.js 模块团队为新实现提供了更详细的指导原则。【https://github.com/nodejs/modules/#features】

  • 2019年10月(暂定):预计 Node 12 将会获得长期支持。根据官方计划,其目标是在此时发布对 ES 模块的完全支持。

为什么完整的 ES 模块支持里程碑对 Node.js 如此重要?

有几个原因。首先所有主流浏览器都支持 ES 模块 —— 你可以自己到这里去查看【https://caniuse.com/#feat=es6-module】。在Node.js 中支持服务器端的 ES 模块开箱即用,将能够允许全栈开发人员非常自然地为客户端和服务器编写模块化、可重用的 JavaScript 代码。

另外,Node.js 中的实验性功能在未来版本中会受到非向后兼容的修改或删除。话虽如此,实验性的 ES 模块支持已经在 Node 中使用了好几年,并且预计在 2019 年 10 月之前不会发生显着变化。

Node.js 模块的当前状态

CommonJS 模块

目前(撰写本文时的 2019 年 7 月)Node.js 中模块的事实标准是 CommonJS。CommonJS  模块在普通的 .js 文件中用 module.exports 进行定义,然后可以用 require() 函数在其他 .js 文件中使用。例如:

1// foo.js2module.exports = function() { 3  return 'Hello foo!';4}56// index.js7var foo = require('./foo');8console.log(foo()); // Hello foo!

可以使用 node index.js 命令运行此示例。

ES模块

从 Node v8.5 开始,开发人员已经能够使用 --experimental-modules 标志运行对 ES 模块规范的各种支持了。从 Node v12.4 开始,模块可以在 .mjs 文件中定义(或在某些情况下【https://nodejs.org/api/esm.html】在.js文件中)。例如:

1// foo.mjs2export function foo() { 3  return 'Hello foo!'; 4}56// index.mjs7import { foo } from './foo.mjs';8console.log(foo()); // Hello foo!

node --experimental-modules index.mjs 命令运行此示例。

在同一个应用中同时使用 CommonJS 和 ES 模块

在某些方面,在浏览器中支持 ES 模块可能比在 Node 中更简单,因为 Node 已经有了一个定义良好的 CommonJS 模块系统。幸运的是,开发人员可以同时使用这两种模块,甚至从一种模块导入到另一种模块。社区在在这方面做得非常出色。

假设我们有两个模块。第一个是 CommonJS 模块,第二个是ES模块(注意不同的文件扩展名):

 1// cjs-module-a.js 2module.exports = function() { 3  return 'I am CJS module A'; 4}; 5 6// esm-module-a.mjs 7export function esmModuleA() { 8  return 'I am ESM Module A'; 9};10export default esmModuleA;

在 ES 模块脚本中使用 CommonJS 模块(请注意 .mjs 扩展名和使用 import 关键字):

1// index.mjs2import esmModuleA from './esm-module-a.mjs';3import cjsModuleA from './cjs-module-a.js';4console.log(`esmModuleA loaded from an ES Module: ${esmModuleA()}`);5console.log(`cjsModuleA loaded from an ES Module: ${cjsModuleA()}`);

node --experimental-modules index.mjs 命令运行此示例。

在标准的 CommonJS 脚本中使用 ES 模块(注意 .js 扩展名和使用require()函数):

 1// index.js 2// synchronously load CommonJS module 3const cjsModuleA = require('./cjs-module-a'); 4console.log(`cjsModuleA loaded synchronously from an CJS Module: ${cjsModuleA()}`); 5 6// asynchronously load ES module using CommonJS 7async function main() { 8  const {esmModuleA} = await import('./esm-module-a.mjs'); 9  console.log(`esmModuleA loaded asynchronously from a CJS module: ${esmModuleA()}`);10}11main();

这些例子提供了如何在同一个程序中同时使用 CommonJS 和 ES 模块的基本演示。你可以查看 Gil Tayar 在 “NodeJS 中的原生 ES 模块:状态和未来方向,第一部分“中深入探讨的 CommonJS 和 ES 模块的互操作性【https://medium.com/@giltayar/native-es-modules-in-nodejs-status-and-future-directions-part-i-ee5ea3001f71】。

Node.js 模块的未来状态

在撰写本文时,新模块的实施计划正处于第三和最后阶段。计划在 Node 12 LTS 发布的同时完成阶段 3,并且在没有 -experimental-modules 标志的情况下可以使用 ES 模块支持。

第 3 阶段可能会带来一些重大改进,以完善 ES 模块的实现。

加载方案

开发人员希望模块加载系统具有灵活性和全功能。以下是 Node.js 模块加载器解决方案中的一些关键功能:

  • 代码覆盖/检测:使开发人员工具能够检索有关 CJS 和 ESM 模块使用情况的数据。

  • 可插入加载器:允许开发人员在他们的包中包含加载程序插件,这些插件可以定义从特定文件扩展名或mimetypes 加载模块的新行为,甚至是没有扩展名的文件。

  • 运行时加载器:允许在运行时转换 import 语句中引用的文件。

  • 模块的任意来源:允许从文件系统以外的源加载模块(例如,从 URL 加载模块)。

  • 模拟模块:允许在测试时用模拟模块替换。

你可以查看这里的完整列表【https://github.com/nodejs/modules/#features】。

package.json 中的 exports 象

虽然命名和语法不是最终的方案,但这里的想法是在 package.json 文件中的某个地方有一个对象,它允许为包中的不同组件提供“漂亮”的入口点。这个 package.json 是可能的一个实现:

 1{ 2    "name": "@myorg/mypackage", 3    "version": "1.0.0", 4    "type": "module", 5    "main": "./dist/index.js", 6    "exports": { 7        ".": "./src/mypackage.mjs", 8        "./data": "./data/somedir/someotherdir/index.mjs" 9    }10}

开发人员可以像这样导入 @myorg/mypackage 的数据组件:

1import { MyModule } from '@myorg/mypackage/data2

用包的名称引用包的根

模块引用当同一个包中的另一个模块时,可能会出现大量的回溯,如下所示:

1import coolcomponent from '../../../coolcomponent/module.js2

如果实现了这种方案,那么就可以用在 package.json 中定义的包名的引用来替换回溯。新代码如下所示:

1import coolcomponent from 'mypackage/coolcomponent/module.js2

支持双 ESM/CommonJS 包

允许 npm 包同时包含 CJS 和 ES 模块对于确保从 CommonJS 迁移到 ES 模块后能够保持向后兼容,对开发人员友好的路径非常重要。这通常被称为“双模式”支持。

双模式支持的现状方法是将 package.json 中的现有 main 入口点指向 CommonJS 的入口点。如果 npm 包中包含 ES 模块并且开发人员想要使用它们,则需要使用深度导入来访问这些模块(例如 import'pkg/module.mjs')。这是双模式解决方案,可能与 Node.js 12 LTS 一起提供。

还有其他一些双模式支持提案。这个广泛争议的提案中包含一些选项【https://github.com/nodejs/modules/issues/273】,使开发人员可以更轻松地发送包含两个单独实现(ESM 和 CJS)的包,但此提议未能达成共识。

一个更新的 ESM 的 require 提案提出了一种不同的方法【https://github.com/nodejs/modules/issues/299】,允许开发人员使用 require() 来解析 ES 模块。该提案仍然是开放的,但是已经沉默了,不太可能包含在 Node 12 LTS 中。

ES 模块你好,CommonJS 再见?

虽然目标是 ES 模块最终取代 Node.js 中的 CommonJS 模块,但没人知道未来究竟会怎样 —— 也不知道CommonJS 模块支持消失的时间。但有一件事是肯定的:Node 开发人员花费了大量的时间和精力确保在没有 CommonJS 的情况下无缝过渡到未来。

他们在确保两种模块类型彼此互操作之间取得平衡,同时尽量不引入太多新的双模式 API,因为一旦迁移之后就会变得无用,并且需要时间来消除 Node 对 CommonJS 的支持。

那什么时候才会从 Node.js 中删除 CommonJS 呢?让我们做一个大胆而且毫无根据的预测:Node 18 会带有 --experimental-no-commonjs-modules,并且 Node 20 会彻底抛弃 CommonJS。

能够跨浏览器、服务器和其他 JavaScript 运行环境的模块化 JavaScript 的未来是令人兴奋的!

原文:https://blog.logrocket.com/es-modules-in-node-js-12-from-experimental-to-release/

Node.js 12中的ES模块[每日前端夜话0x9E]

下面夹杂一些私货:也许你和高薪之间只差这一张图

2019年京程一灯课程体系上新,这是我们第一次将全部课程列表对外开放。

愿你有个好前程,愿你月薪30K。我们是认真的 !

Node.js 12中的ES模块[每日前端夜话0x9E]

在公众号内回复“体系”查看高清大图

长按二维码,加大鹏老师微信好友

拉你加入前端技术交流群

唠一唠怎样才能拿高薪

Node.js 12中的ES模块[每日前端夜话0x9E]

Node.js 12中的ES模块[每日前端夜话0x9E]

往期精选

小手一抖,资料全有。长按二维码关注前端先锋,阅读更多技术文章和业界动态。

Node.js 12中的ES模块[每日前端夜话0x9E]

本文分享自微信公众号 - 前端先锋(jingchengyideng)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
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
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Java修道之路,问鼎巅峰,我辈代码修仙法力齐天
<center<fontcolor00FF7Fsize5face"黑体"代码尽头谁为峰,一见秃头道成空。</font<center<fontcolor00FF00size5face"黑体"编程修真路破折,一步一劫渡飞升。</font众所周知,编程修真有八大境界:1.Javase练气筑基2.数据库结丹3.web前端元婴4.Jav
Stella981 Stella981
3年前
AssemblyScript 入门指南[每日前端夜话0xEB]
每日前端夜话0xEB每日前端夜话,陪你聊前端。每天晚上18:00准时推送。正文共:2459 字预计阅读时间:10分钟作者:DannyGuo翻译:疯狂的技术宅来源:logrocket!(https://oscimg.oschina.net/oscnet/b880277c594152a503
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这