首頁 > web前端 > js教程 > Node.js 和 esbuild:小心地混合使用 cjs 和 esm

Node.js 和 esbuild:小心地混合使用 cjs 和 esm

Patricia Arquette
發布: 2024-12-28 20:49:18
原創
710 人瀏覽過

Node.js and esbuild: beware of mixing cjs and esm

長話短說

當使用 esbuild 將程式碼與 --platform=node 捆綁在一起(依賴於混合了 cjs 和 esm 入口點的 npm 套件)時,請使用以下經驗法則:

  • 使用--bundle時,將--format設定為cjs。這適用於除具有頂級等待的 esm 模組之外的所有情況。
    • --format=esm 可以使用,但需要一個像這樣的polyfill。
  • 使用--packages=external時,將--format設定為esm。

如果您想知道 cjs 和 esm 之間的區別,請查看 Node.js:cjs、捆綁程式和 esm 的簡史。

症狀

使用 --platform=node 執行 esbuild 捆綁程式碼時,您可能會遇到以下執行時間錯誤之一:

Error: Dynamic require of "<module_name>" is not supported
登入後複製
登入後複製
Error [ERR_REQUIRE_ESM]: require() of ES Module (...) from (...) not supported.
Instead change the require of (...) in (...) to a dynamic import() which is available in all CommonJS modules.
登入後複製
登入後複製

原因

這是因為以下限制之一:

  • esbuild 的 esm 到 cjs(反之亦然)轉換。
  • Node.js cjs/esm 互通性。

分析

esbuild 在 esm 和 cjs 之間的轉換能力有限。此外,某些場景雖然受 esbuild 支持,但 Node.js 本身並不支援。從 esbuild@0.24.0 開始,下表總結了支援的內容:

Format Scenario Supported?
cjs static import Yes
cjs dynamic import() Yes
cjs top-level await No
cjs --packages=external of esm entry point No*
esm require() of user modules** Yes***
esm require() of node:* modules No****
esm --packages=external of cjs entry point Yes

* esbuild 支持,但 Node.js 不支援

** 指 npm 套件或相對路徑檔。

*** 支援使用者模組,但有一些注意事項:如果沒有膩子填充,則不支援 __dirname 和 __filename。

**** 節點:* 模組可以使用相同的 polyfill 支援。

以下是這些場景的詳細描述,不使用任何填充:


npm 包

我們將使用以下範例 npm 套件:

靜態導入

具有靜態導入的esm模組:

Error: Dynamic require of "<module_name>" is not supported
登入後複製
登入後複製

動態導入

esm 模組在非同步函數中具有動態 import():

Error [ERR_REQUIRE_ESM]: require() of ES Module (...) from (...) not supported.
Instead change the require of (...) in (...) to a dynamic import() which is available in all CommonJS modules.
登入後複製
登入後複製

頂級等待

具有動態 import() 和頂層等待的 esm 模組:

import { version } from "node:process";

export function getVersion() {
  return version;
}
登入後複製

要求

帶有 require() 呼叫的 cjs 模組:

export async function getVersion() {
  const { version } = await import("node:process");
  return version;
}
登入後複製

--格式=cjs

我們將使用以下參數來執行 esbuild:

const { version } = await import("node:process");

export function getVersion() {
  return version;
}
登入後複製

及以下程式碼:

const { version } = require("node:process");

exports.getVersion = function() {
  return version;
}
登入後複製

靜態導入

產生以下運作良好的內容:

esbuild --bundle --format=cjs --platform=node --outfile=bundle.cjs src/main.js
登入後複製

動態導入()

產生以下運作良好的內容:

import { getVersion } from "{npm-package}";

(async () => {
  // version can be `string` or `Promise<string>`
  const version = await getVersion();

  console.log(version);
})();
登入後複製

注意動態 import() 沒有轉換為 require(),因為它在 cjs 模組中也是允許的。

頂級等待

esbuild 失敗並出現以下錯誤:

// node_modules/static-import/index.js
var import_node_process = require("node:process");
function getVersion() {
  return import_node_process.version;
}

// src/main.js
(async () => {
  const version2 = await getVersion();
  console.log(version2);
})();
登入後複製

--packages=外部

對所有 npm 套件使用 --packages=external 都會成功:

// (...esbuild auto-generated helpers...)

// node_modules/dynamic-import/index.js
async function getVersion() {
  const { version } = await import("node:process");
  return version;
}

// src/main.js
(async () => {
  const version = await getVersion();
  console.log(version);
})();
登入後複製

產生:

[ERROR] Top-level await is currently not supported with the "cjs" output format

    node_modules/top-level-await/index.js:1:20:
      1 │ const { version } = await import("node:process");
        ╵                     ~~~~~
登入後複製

但是,它們都無法運行,因為 Nodes.js 不允許 cjs 模組導入 esm 模組:

esbuild --packages=external --format=cjs --platform=node --outfile=bundle.cjs src/main.js
登入後複製

--格式=esm

我們現在將使用以下參數來執行 esbuild:

var npm_package_import = require("{npm-package}");
(async () => {
  const version = await (0, npm_package_import.getVersion)();
  console.log(version);
})();
登入後複製

使用者模組的 require()

src/main.js

/(...)/bundle.cjs:1
var import_static_import = require("static-import");
                           ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /(...)/node_modules/static-import/index.js from /(...)/bundle.cjs not supported.
Instead change the require of index.js in /(...)/bundle.cjs to a dynamic import() which is available in all CommonJS modules.
登入後複製

產生以下運作良好的結果:

esbuild --bundle --format=esm --platform=node --outfile=bundle.mjs src/main.js
登入後複製

節點的 require():* 模組

src/main.js

const { getVersion } = require("static-import");

console.log(getVersion());
登入後複製

產生以下:

// (...esbuild auto-generated helpers...)

// node_modules/static-import/index.js
var static_import_exports = {};
__export(static_import_exports, {
  getVersion: () => getVersion
});
import { version } from "node:process";
function getVersion() {
  return version;
}
var init_static_import = __esm({
  "node_modules/static-import/index.js"() {
  }
});

// src/main.js
var { getVersion: getVersion2 } = (init_static_import(), __toCommonJS(static_import_exports));
console.log(getVersion2());
登入後複製

但是,它無法運作:

import { getVersion } from "require";

console.log(getVersion());
登入後複製

--packages=外部

對所有 npm 套件使用 --packages=external 都會成功,包括那些帶有 cjs 入口點的套件。例如:

// (...esbuild auto-generated helpers...)

var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
  if (typeof require !== "undefined") return require.apply(this, arguments);
  throw Error('Dynamic require of "' + x + '" is not supported');
});

// (...esbuild auto-generated helpers...)

// node_modules/require/index.js
var require_require = __commonJS({
  "node_modules/require/index.js"(exports) {
    var { version } = __require("node:process");
    exports.getVersion = function() {
      return version;
    };
  }
});

// src/main.js
var import_require = __toESM(require_require());
console.log((0, import_require.getVersion)());
登入後複製

與:

src/index.js

Error: Dynamic require of "node:process" is not supported
登入後複製

產生幾乎逐字輸出,運作得很好,因為 esm 模組可以使用 cjs 入口點導入 npm 套件:

esbuild --packages=external --format=esm --platform=node --outfile=bundle.mjs src/main.js
登入後複製

結論

我希望您發現這篇文章對於現在和將來解決 esbuild 輸出問題很有用。請在下面告訴我你的想法!

以上是Node.js 和 esbuild:小心地混合使用 cjs 和 esm的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板