Node.js 中的 ECMAScript 模块

在过去的几年里,Node.js 一直致力于支持运行 ECMAScript 模块 (ESM)。这是一个非常难以支持的特性,因为 Node.js 生态系统的基础是建立在一个名为 CommonJS (CJS) 的不同模块系统上。

两个模块系统之间的互操作带来了巨大的挑战,需要兼顾许多新功能;然而,Node.js 中对 ESM 的支持现在已经在 Node.js 中实现,尘埃落定。

这就是 TypeScript 带来两个新的 modulemoduleResolution 设置的原因:node16nodenext

{
    "compilerOptions": {
        "module": "nodenext",
    }
}

这些新模式带来了一些高级功能,我们将在这里进行探讨。

package.json 中的 type 和新扩展

Node.js 支持 package.json 中的新设置 称为 type"type" 可以设置为 "module""commonjs"

{
    "name": "my-package",
    "type": "module",

    "//": "...",
    "dependencies": {
    }
}

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

// ./foo.ts
export function helper() {
    // ...
}

// ./bar.ts
import { helper } from "./foo"; // only works in CJS

helper();

+hBoDTP4tQFiJUS8WrfGDyUx8r7dBsurc3RvAG684K8ei9CSt/AJiKrfwxZuNmluSXM6ZpcFtRirOPmGof5rtibiZNLdeq149UV9SB4m53LADpD1Uc0J5UQBM9uSzEGxt0DBAckDkEJyKlSqyQDf61dvO3hkq0OfyJkc2gkSCfWHDGYW52iCM3eh2BUMouBOMAaGY/0WAm/p8n6VVnP/hQTCDF2zcNloVZqO5L1TqDG5ZZtEmdhxI3WcSlaSpT0UwrOOP+1JnosiO3BwT4aCFDBiPLiAZOZHa9fIDIH66kPGoDnaHYBlZTEHsfk2DfS7h7UKbEdSE4nVG7LpAHPnqbGDr9TKitEhaknSStN38FY=

// ./bar.ts
import { helper } from "./foo.js"; // works in ESM & CJS

helper();

QYX3iEAbZLRxyEp7XOrok5nmauoPGp4u7pk6bYfd5hzXK3kyGWLKngXgyU0+PqJvn2NZ4HIAznFKCIyKJunp+XWU3RawNM6pmRjDjkfcTN9BlnJqD2pCLNLBwbsXUSMwqcsNd+YtlCQccnEPnDDLBxZWQ7v7y5W0i+KGT0eu+5aB3Bh5cgRJAflspluh1r7b

/vLnOHI6jZQOSuA3+o1Tppsa+gem6pTQcBNKTsCz+1CyaEWpvDGPhIKsD851Ws9sJmCwSkpmK6i9Fondy6+Drz9wqbK62e72IBk+5UmFG7iBl+/8d8w7Xve7o2SLXaMVt14Fcv+lo2TXJ4e0vC9HY4wg6AIa1TF8zFMLbVhaADmlEIpZNeBwxkbt1u7UDqzLzR7Q8uaj+ZTFWinlHGVhbrjg0Twg/Mhn/kic3y8uATQrR7pU9RWe/xJ18BuRb0gIxcpIwZBqtL7O8VupLwkx8o8NaiMNVVxXHESnDKr2jow=

新文件扩展名

fnAVIANqLMIoZ3uDN46gfqOjzS9iTyNVnyaJepGx0cp+Zq60Qsc0Zyc9lhq3Bo8GpaeXGUWtZ7X1n/VRJ0JZ+u/WNdD6XRYIKsmSskSmz6/YzH3Oh8Ay2wNT5ZnD6pKRio1bm6fB9pB1VLYnYxzOjdyBCriiPdc+4LYsD9VrCdZTUy6FAmTvJ40cATsodHGWhYrKAxgTkqatCh2kD8L9feCnDICx+JibRwr9jK/cqrVMiuJs1WJhdru3ZxQIIT7jzyjowjXgJq1xo0Sph9uuhgUJU0nbekBvGT3w+VgqJVli78xBtkCFREHxAc0sVaLUnJwj/TFrMHIdswt61yuVS9nkPJTH1abT5rbZYcT7NOfePEbVrAkRnsNca0Pq0EFBewMzlP55mGcsKjwnVwqnfQ==

m1TB/A7y8QEn0Ga3clPl0A19Kr2g7cWPTVxRWpt9q9l8uTj1UiW2Snzgno6sx36B5pYwNWUMCqPXLIwjXJatiZHDc5HA+IRyiZk/iQRrzPocLAqzx34AnZGhY9uqQb3RGPXyJC6/8S4C4L1GeidSPKrUQyhkNWDrukmMgmv63xiedNs+bDYc4ItK1hSNsabC0UrCudjJ6SkRbro6eeozPR6B2rbc+vLqFdsvEoq2Y5TeQce8Cr2uODAIvM4DzlDqdvZ4CFKXgu6MekFK2HTb0QC7F5qPPfl/y789hb0gG4s=

eIV8YNap758ItCf/F4EJNbX6XVXhydwZFkc9r9P0FyLupweODnc89EG+B8bkzuVHeuNgC2Ip21wn9rJ2aQccqhigYbdCYX4BXpT+CrcWewDA1rN55WdTx9szjP774wjsdfYXZavpyIet2XyEk5m31GGWFc7WYC/s924POWut1TBl0XqtYs8lcuDf3GX3kiEhwCvI+0WnHoudU6K9nPuqkln2hAFhXRLykqOy81MamytWvhiIlfO5CvGWwF0ljE/nvZVxR5jFIl/qfQ27x3yyMkhPZOHBUZDKzVNzBKmLfgYVX67vQyAykK0xuh3cNDMT

e6Ix//5BVbiDhaV/8mlYp2kTxkwzFhIjIuHkHmpUH4G1dyddYdUA6J/RqAe3WEn7FjtRyeFT6itxLUGpMGm/JHGDdAzwXAThD4biu7j9aELWTvnxZMvjG0THZCHXv+FBavCwHYGIxVkp4EqWAwa8jQYYKVpmYN2xdE6J/gqxbekg5+doLfdb3wtvNgYkCdQuRW96q0FfPPVs2A0fHMxkolf5tFZ2unXFAjXZcs6eVpU6BKUV3cOrUAaFWne71zMYIMFERKBMwi2h6uJHgthX9gHpd0w1C7IhMCoYCRjqDKrJJRpQP7IquZnSxRNIZKGy31P5IlikrCjqIqwwzv5Kfq/j+ZVwiPxNySRbmq7UdTI=

EjzmFtfp38ZlKjcvYYJu4wwJFngST4TkL58y7ZRzk+m5/5Fs1GwjMNMFN7HDQkNN3ywZD4WXS4aCTl3bJib0WrNDQDHNKinkZxynbpQtOsEnArEIAn9eWyKz2qlY+wXf7I921U8dCal3bRTOE16xXOAKjFJRV2XE6x3fHnsZUr1Z0cMT2vDdHpMSN0knHvs/

CommonJS 互操作

o/aKcBFpq5C/0gnQ0abX+R9xLrpD7AhswgPFTvOj4xRgk7qHLBKqqaJB3B3PQ9+017X2LxdyO6uUjllnqqeFazsRglalpgp0N2Jz/Nv60WmP601Y04afFc086EkJPc1xE+iB9YKQGuYRgReUVWLUHw==

// @filename: helper.cts
export function helper() {
    console.log("hello world!");
}

// @filename: index.mts
import foo from "./helper.cjs";

// prints "hello world!"
foo.helper();

BR8Jcz5wYU9ywHHZrF/qOIr40tmEzPD+3WpFxxxdyxaMIJZVuyuqOuKo7Ih4PgOoX+Q2olfTThJavvHByBTwcxCZhUVzNpj1UsAr/5F7fFIQIXjNbaQ+dmQkHhD5JQcsHNry9nVz2V2Xxqomit41nvmtBnJRMl9YXIp7nMCfxxvWNKKKAhdhnCUbeYVoLU9WNaGLHAyh7831asasqIgH1odk+RTwbePxS4fBea2wJNLRZGZ/SA6RahLcXoV+6lawh1d2cKp7KrjsEpNEQ7YWukI1dH8ndH0EXyBJ1cJDgKUrLBSTbrdylFDYQkQxDaOwSiwai3Nrj/i7Sxu1cAJyAnTijcJTV28RgSpzxkoqERTDCtgLrpmv2npscx7Lnv9z

// @filename: helper.cts
export function helper() {
    console.log("hello world!");
}

// @filename: index.mts
import { helper } from "./helper.cjs";

// prints "hello world!"
helper();

vWqq+S8EMpfiUP8c1YnIgmZ2bzivbzGUhO49Y+G5//qnR30TeG8CyRZPJh1E6HiORkSI+u26Nk3FABzute8db86sI7fnO3MMZMceLWQyI9o9S6aD3vOv9C6n6ZhIN9P/tMcOYSUpKMNdQoFbHKf2r7Y3In8zlyOOsokQ9mN7lk1DSq/U027GaLagxqMfFPsCLCtkKQCcI506HPhB2qWgwT/FjEXRiWa4DRS+JRQfvyftK23ENJuSUYcPvtWebGRFgzKr58uaQZMOo73PdtsIAw==

NhuL/Y6QnewczGjfkb7Sezo1wXtEyWFYN3ENMny9kWHOoNujPHmj7HNvJZiOxanWEjFr72yqh0zzAmDSZZ5mRYEArpKVj4xAh7qF5ViXA+A=

import foo = require("foo");

wj38d1+0dlAJvK8D4pTULIGgixCpmTlL24i8M5JijFxW/RSD0gUoqq5QwZ3oTlDJDcU02eZvv0b+2IG8JpEDDhSOWL/Ww66u6ZowpXhNKMjhZBpbTgL/TOp/q6+btX3/E2GcESUZGkgdZA/TuHqC+kIBGIOOFtWYA61X6OVmJ9AqYQfiYeUT3NNRgsXPzzhHNreZVeE3KvfI9GbVPQwf/uyWJ7dAPcL4UYR4SqN2l/KHVbiiYJ4Dd8fwraGxd44Szt9Fm3wMZI3E/J6plzn4ZqCArS62j73xtumi7vGirjfV6mmtEZJDXGvpdhpLBa8ZY8XP4iSofONBKXabDjsnPWvCM2tAcrhgFuLJDzWVz5SV/bHn6W1VnSm0EOyfujhu6IztRtEJe78NNfP6qI25vEiH5phUcYMvF82BpSc8pA0NY3T316/oNbLDWqJwRa+Wa5M5BFgEne9qExI3y670up9WG8yJOZzsim04I8zjkiqdPvSuaiBIdZISsXOcV4fzWjw+VlK4OXXMNqe03nqPtnfUJ09Y/Xj2cCaCJ4Ge/sSP+BS+554Hxn1EAQKL5d9H

// @filename: helper.cts
export function helper() {
    console.log("hello world!");
}

// @filename: index.mts
import foo = require("./foo.cjs");

foo.helper()

jorZT7BeufliIqob6lg5wGRDrDBeWszaDXjmWZBcMID4IIwLcV/MxKtV0+LbJ6AibA29hUvC2vGumd5Jpq1QruCZvgf6fhZD1Q095ZRvMV79+Ity8aXkoU67u4dQmSSk2Cj3cYkbXHHejxO8dy05b4ebpw2KXDYHPLaF2IJVnOwITwfLdu7TYEGlojStf3FOvyCcIRPMnzclRWfLYEmyZtcphBdr8kNr/0d6cMZ3aiLN4dhOgrj/zSZtAisAxGD0

/L8hCkkKli1N4B6dJ6+7LYcQtI+4nxAsrm2DUT0G+OF4l5rVFQElqVsE5v6cM1JduvVENrCuRKm1W4OqeUu+RqDO2Shwh6zHWAxKl/PM5Gsl6EE4wov6A/N+sT7ygQmGdnV4EHKKAJH8mj6xUzV3xNMRWFh8ZjiqbVMMb9l2J3OVTnLAUuk3SE9hqnjXKiPA

package.json 导出、导入和自引用

LLDkm5dnOYOrelagjImYEflv+a+W+nD423ncAYzN1savKdQI9Wojs9PUhzy3Vl2AF2cUQSIEndQ9YKhEe1oCxVjCyuKFHPMgM6mKCHsiAMSZMX9VCUGNROYdDALIErNqQMHKjB5ojkgDQBrfKNKZbjSnp7rTZVq7J9wSgMfvVVNK+BxUjApb5ix320wlM52Vq0W503OaXNqoPLS6N8lxak6v8hbRn9ru1CyJc8LSCW6h5zNe8rGtL0T5mWm9v4Zpd3SuYvDVw/Sj2uW/ObAWgH+7q+EQHT4OuAtkKbOIT95mY9ZfJOX8Ekgm+/oTMCFp4xZXWJtaGS3MctZojXkW2XSIqGa7ZUk7N4cAqqLOQeC7sbYzdd8qC3JsdpoZFgREgmOXSO3iDOEeIeiRGR0xAz8SjfXVLYoeMDdy63y0Hfk83qcbDkk6xoPKqJOU2DqD

rnn9IN6VOSZnUTUBACRYvq0KleSMB4OYNCYsGqA+Y8aqOsbdpcFeQVRCKkK734Vu7cBAjce+dblQnqOUDvtyGtb/HlcERQzuq7NKfeWUTUs02cgA8VOKxVfMcRJ8P1pv

// package.json
{
    "name": "my-package",
    "type": "module",
    "exports": {
        ".": {
            // Entry-point for `import "my-package"` in ESM
            "import": "./esm/index.js",

            // Entry-point for `require("my-package") in CJS
            "require": "./commonjs/index.cjs",
        },
    },

    // CJS fall-back for older versions of Node.js
    "main": "./commonjs/index.cjs",
}

fiA6qNVh7RJPvtJbJ2O5j+c+0iH7xXUSewNZa4OlMDa7U8guhCCrmo32FOtBB6jNqZ0wZN1umhK3I2LwTNWEi9uvORbCiIYfsGtKFyobn1hfaZhIUR9isKse2azIke056fw71YrAISS0Bq+GvNSsWBNcDBHrXmdlvqzgR/sQYE2VWAr/6XB+rxkbKXa65h70yPvsG1Q+Z3ZiH/SJkdFhS+va9bWBFktQtB8BuzXGgi3dp+oak5xYDiVXhbslh4AM

gBeg2hsCDQl8YrHSpT6u6TQ4/q5jTHKVqVcTLuGfEDSmJFbTEqRRDSPUzbUSPpRklZlgknn6+Z7DLsEzvPxpH2es1br20B5TfBVB3wFxkEMj3Bra7NOxKidXFaWmPF00sELShf6qVIGAUSKFnHmsNnfRTbWqXB+hK5k2MGKyRlgjJVOwkZzPFU5CTW0gPeQJEVzRvmlZSv7OIb52a2PHApSdcZeegXZ2y3D4EUXiyqNH5o2g79LXvSPWRncZC5FaM47CSW4HbrlPmC/0xYsisLSR/bw8bkVK/OAd8MMptFR4/0Xj66enIx56ukDLNkpGt99itqmo+JA5FYISsgwhI7CQ+jSYFPCWNaSfi6qSo++MO6iPuV10o48Vabq48emVaws13h52/ab02Zrn1LjD/TtiFquv9xZWzcRVXJMdKz1A323Hsfh7nkzBLtjnSMmbYk0pb1kt9rZ8el5sOylhErctLwUthlJp2bvwQLgRUFq8n+sUTuofTOz94LG18q08swSpRlMt5YzOOophVvWYmx/60q4zOlrPc3W3gDBvY3Ag1+NRNOLSVIuKa4ZT5rMs

lC+DY8axbW83K06zzKu5KXOeXzxzAA0fFEVcTWs8KQthu7dOZNL+HahhwRy5xDSCvYye3VGFZRT4lhfU34DBx4UwSbOCYvOtHcVWb+sYaxQOYSTTAKnnxb95ts94E+/SawWvzoQOc47M0G0gOdOajAtkPil32NXGMCEGUERjCwBBSpEjznvyS1CdsyWA8lwg1jTpkg1QOPs2BpRbz/pSyAnh8e9NJTCnLY4Uzuif4qb1ZuTgtqQ9QGQ7U0BIcsEi3lOUrBVKiNbSXg0Vp4+xidrRBh///YnNXXqGGKwqoDJ49QZcQVSq4Q1Nf2xtT3NX28jDNrbx2KIBWuYx0uAaGROTS+OsXYbI22YzZHFMToQg3mlpXdMMeNEHoYwTO2kfsBG1GLggohIsFEVWdo6n+0blkyxbgpbZn65mzZL+yoLQL1ayVZztp4wNo/YIfcE3YPZT9COBA1+QQDfzXqPQBiuiHD7mnld6ofhDVp15qdh5xDeTGtJx4vkcj+LJ6VYmUQsTIPW0v+XmfrlH4Pe/W7cblhAn2u/qdh0qPDG95CWrMVnIYy/755VScjTEqsKzbkAYS6/0N94iFbVWsXbPiyrn88oNVYNOnzlsqjRyMTCsHlwmOQDgDlegHGrrocrrnS60rjmoSKO34wNAwc7Sf0tTjTwjPCXqeX3KwNN/qOs=

// package.json
{
    "name": "my-package",
    "type": "module",
    "exports": {
        ".": {
            // Entry-point for TypeScript resolution - must occur first!
            "types": "./types/index.d.ts",

            // Entry-point for `import "my-package"` in ESM
            "import": "./esm/index.js",

            // Entry-point for `require("my-package") in CJS
            "require": "./commonjs/index.cjs",
        },
    },

    // CJS fall-back for older versions of Node.js
    "main": "./commonjs/index.cjs",

    // Fall-back for older versions of TypeScript
    "types": "./types/index.d.ts"
}

x67KawQhC1CZvJRZyFMWhhtjiiiaBHNo7VhkTIMsrRBhy6bzC6kgSfTC42o7YUhM29AA3AGYwWaTl3t34DNjL2pQ5c/+6TVdcMOTU4pvHT4Ht7V4+lHMyVm0lg+SQd5Ukud3oywHbo1L5+sZoUncIiqniwXrnxyL9Q/BUSI2kMKAA5exoblbQvK5IK2JKdhj+Q51BDvuks9M1lNdr4YXZSx18iAG3Ip6H+jenmG0YL0hQ7OFVJG5vg6Fnj69bPbF8Cb8ZJlTaSl0MrvicJRDalMOuutrunag9Bk4lSq9H1xelF1N3GglTru2K9Kfi3QrN9DvWLAX630MYZXVd8uqkfz3BGki0RFiA02zfETgX/9fQr4Jj0p4xWbawsh20S5vqB+s+VYOunekzwKzNqAwqRiyj/qRNRmcEmehpYkre1oFXfK6Ia61s09GOa0zhWhB