在Node.js 中使用原生的ES 模塊

blank

在Node.js 中使用原生的ES 模塊

本文譯自: Using ES modules natively in Node.js ,原作者是Dr. Axel Rauschmayer ,圈內稱之為"德國阮一峰"。首發https://qianduan.group

Node.js 從8.5.0 開始原生支持ES 模塊,不過還需要通過命令行參數控制。這還得感謝Bradley Farias對這個新特性的貢獻。

本文就給大家詳細講講這個特性。

舉個栗子

文件結構:

esm-demo/ lib.mjs main.mjs

lib.mjs:

exportfunctionadd(x,y){returnx+y;}

main.mjs:

import{add}from'./lib.mjs';console.log('Result: '+add(2,3));

運行範例:

$ node --experimental-modules main.mjs Result: 5

注意注意!

ES 的模塊名稱:

  • 所有的模塊名稱都是URL —— 這對Node.js 來說引入了新的東西;
  • 文件:最好使用相對的帶.mjs 後綴的路徑來引用ES 模塊,這樣可以保證對瀏覽器的兼容。如果不包含後綴名,則模塊搜索方式與CJS 保持一致。如果同時找到了.mjs 和.js 的文件,則使用.mjs 文件;
    • 例如:../util/tools.mjs
  • 類庫模塊:直接使用模塊名,省略擴展名是最佳方式。這能與現階段類庫模塊發布的方式保持最好的兼容;
    • 例如:lodash
  • 如何讓node_modules 裡的模塊在瀏覽器里工作還有待研究(不使用bundler 工具)。一種可選方案是引入類RequireJS 的配置方式,將裸路徑轉換到真實路徑上。就目前而言,裸路徑的模塊在瀏覽器是中是用不了的;

ES 模塊的特性:

  • 無法動態引入模塊;但是很快就會引入f=" 2ality.com/2017/01/impo ">動態操作符import()來實現;
  • 像__dirname和__filename和這樣的元變量將不再提供,有一個新的提案引入將會給ES模塊提供類似的方式——Domenic Denicola提出import.meta
console.log(import.meta.url);

與CJS 模塊的互操作性

  • ES 模塊可以import CJS 模塊,但是引入的模塊只包含一個default export——即module.exports 的值。已經開始計劃讓CJS 模塊輸出具名export(通過在文件開始加編譯指令的方式),不過可能實現需要花一些時間。如果你想幫忙,看這裡
import fs1 from 'fs' ; console . log ( Object . keys ( fs1 ). length ); // 86 import * as fs2 from 'fs' ; console . log ( Object . keys ( fs2 )); // ['default']
  • 在ES 模塊中不能調用require(),主要是因為:
    • 路徑解析在兩種規範中是很不一樣的:ESM 不支持NODE_PATH 和require.extensions;它的模塊標識符永遠都是URL,這會造成小小的區別;
    • 為了與瀏覽器保持最大的兼容性,ES 模塊總是異步加載的。這種異步加載的方式與CJS 通過require() 同步加載的方式無法很好的在一起工作;
    • 同步模塊的禁用同樣也給在ES 模塊中使用頂級await 開了方便之門(一個目前正在考慮的特性);
  • CJS 無法require() ES 模塊。原因與上一條提到的類似,同步加載異步的模塊各種問題啊。不過也許可以通過import() 來加載ES 模塊。

在老版本的Node.js 上使用ES 模塊

好吧,如果你想在老的Node.js的使用ES模塊,可以看看John-David Dalton的@std/esm

小貼士:只要不使用unlockables特性,就可以保證與原生的ES Module完全兼容。

blank

FAQ

什麼時候可以不借助命令配置就可以使用ES 模塊?

目前的計劃是,在Node.js 10 LTS 版本中可以直接支持ES 模塊;

.mjs 在瀏覽器中可以工作麼?

可以的,只需要提供正確的Media Type(text/javascript 或者application/javascript)即可。 .mjs標準化和周邊工具的升級正在進行中

文件擴展名.mjs 是ES 模塊所必須的麼?

是的,對於Node.js 來說是這樣的。瀏覽器不在乎文件擴展名,只關心Media Type。

為什麼Node.js 需要.mjs?

Node.js 本可以檢查一個文件是CJS 模塊還是ES 模塊。在選擇添加擴展名這個方案之前也討論過多個其他方案。可以閱讀本博的另外一篇了解。每種方案都有其優勢和缺點。在我看來,.mjs 是正確的選擇。

blank

What do you think?

Written by marketer

blank

Chrome 61 裡的新玩意!

blank

實現達到60FPS 的高性能交互動畫