」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 為具有 ESM 依賴項的 CommonJS 建置 NPM 包

為具有 ESM 依賴項的 CommonJS 建置 NPM 包

發佈於2024-08-14
瀏覽:381

Building NPM packages for CommonJS with ESM dependencies

總長DR

您必須使用諸如 esbuild 之類的打包程序,它將編譯您的專案並將其所有依賴項與其一起打包,這樣它們就不會被導入。這繞過了 ESM/CommonJS 不相容問題。

如果你不耐煩,可以直接看這個範例實現的程式碼。

情境

在周末準備發布我的新專案 Token.js 時,我遇到了一個非常令人沮喪的問題。我希望我的包除了 ESM 之外還支援 CommonJS,但我有純粹的 ESM 依賴項。純粹的 ESM 鬥士們可能對我這麼說很不高興,但如果你正在建造一個 NPM 包並希望它被廣泛使用,你仍然需要在 2024 年支持 CommonJS。

Token.js 是一個簡單的 TypeScript SDK,可讓您整合來自 9 個不同提供者(OpenAI、Anthropic、Cohere 等)的 60 個 LLM。無恥的插件,如果你喜歡產生人工智慧,請檢查一下並告訴我你的想法。

現在有許多線上資源討論如何為 ESM、CommonJS 或兩者建立 Javascript 專案。然而,我特別難以處理這樣一個事實:我有純 ESM 的依賴項。我發現這很難處理,因為我不熟悉捆綁程式(我主要從事 Web 應用程式後端),也無法找到有關該主題的良好指南。

因此,如果其他人遇到此問題,這裡是解決方案。

指導

安裝esbuild

我們將使用 esbuild 作為捆綁器。

yarn add esbuild --save-dev

建立建置腳本

我們需要一個簡單的建置腳本來執行 esbuild 並輸出結果。

import esbuild from 'esbuild'

const entrypoint = ""
const tsconfig = ""

const build = async () => {
  await Promise.all([
    // bundle for commonjs
    esbuild.build({
      entryPoints: [entrypoint],
      bundle: true,
      minify: true,
      format: 'cjs',
      outfile: `./dist/index.cjs`,
      platform: 'node',
      treeShaking: true,
      tsconfig,
    }),
  ])
}

build()

將建置腳本新增至 package.json

使用您首選的運行時運行。

"scripts": {
  "build": "vite-node ./scripts/build.ts",
}

我個人很喜歡vite-node。因此,如果您想完全遵循,則需要安裝:

yarn add vite-node --save-dev

建立您的專案

yarn build

這將導致使用 esbuild 建立您的項目,您將看到一個新檔案 dist/index.cjs,它是您的套件的 CommonJS 建置。

配置入口點

更新您的 package.json 以指向您的 CommonJS 入口點。

"main": "dist/index.cjs",

嘭!現在,您已經為 CommonJS 建立了套件。即使您有 ESM 依賴項,這也將起作用,因為依賴項將被捆綁
連同您的包裹。

由於呼叫 esbuild 時存在欄位“bundle: true”,因此依賴項包含在輸出中。

TypeScript 聲明

雖然技術上不需要,但您很可能還需要 TypeScript 聲明,遺憾的是 esbuild 目前無法輸出這些聲明。所以生成
那些,你會想要使用普通的 tsc。

更新您的 tsconfig.json

將這些選項新增至 tsconfig.json 檔案將導致僅輸出 TypeScript 聲明。這正是我們想要的,因為包的其餘部分
正在使用 esbuild 建置。

"declaration": true,
"declarationDir": "./dist",
"emitDeclarationOnly": true

更新您的建置腳本

"scripts": {
  "build:tsc": "yarn tsc -p tsconfig.json",
  "build": "vite-node ./scripts/build.ts && yarn build:tsc",
}

雙入口點

本指南建議僅為您的包輸出單一 CommonJS 入口點。就我個人而言,我認為這是最好的選擇,原因有兩個:

  • 最小化捆綁包大小
  • 避免雙重包裝危險

然而,這不是唯一的選擇。您也可以使用 CommonJS 和 ESM 的雙入口點發布包。

更新您的建置腳本以包含 ESM 構建

import esbuild from 'esbuild'

const entrypoint = ""
const tsconfig = ""

const build = async () => {
  await Promise.all([
    // bundle for commonjs
    esbuild.build({
      entryPoints: [entrypoint],
      bundle: true,
      minify: true,
      format: 'cjs',
      outfile: `./dist/index.cjs`,
      platform: 'node',
      treeShaking: true,
      tsconfig,
    }),
    // bundle for ESM
    esbuild.build({
      entryPoints: [entrypoint],
      bundle: true,
      minify: true,
      format: 'esm',
      outfile: `./dist/index.js`,
      platform: 'node',
      treeShaking: true,
      tsconfig,
    }),
  ])
}

build()

更新您的 package.json 檔案以包含雙入口點

"main": "dist/index.cjs",
"module": "dist/index.js",
"type": "module",
"exports": {
  ".": {
    "import": "./dist/index.js",
    "require": "./dist/index.cjs",
    "types": "./dist/index.d.ts"
  }
},

原始碼

版本聲明 本文轉載於:https://dev.to/ryan_pate_f494c0931176673/how-to-build-npm-packages-for-commonjs-with-pure-esm-dependencies-38jm?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何使用Regex在PHP中有效地提取括號內的文本
    如何使用Regex在PHP中有效地提取括號內的文本
    php:在括號內提取文本在處理括號內的文本時,找到最有效的解決方案是必不可少的。一種方法是利用PHP的字符串操作函數,如下所示: 作為替代 $ text ='忽略除此之外的一切(text)'; preg_match('#((。 &&& [Regex使用模式來搜索特...
    程式設計 發佈於2025-07-05
  • 如何使用node-mysql在單個查詢中執行多個SQL語句?
    如何使用node-mysql在單個查詢中執行多個SQL語句?
    Multi-Statement Query Support in Node-MySQLIn Node.js, the question arises when executing multiple SQL statements in a single query using the node-mys...
    程式設計 發佈於2025-07-05
  • 如何正確使用與PDO參數的查詢一樣?
    如何正確使用與PDO參數的查詢一樣?
    在pdo 中使用類似QUERIES在PDO中的Queries時,您可能會遇到類似疑問中描述的問題:此查詢也可能不會返回結果,即使$ var1和$ var2包含有效的搜索詞。錯誤在於不正確包含%符號。 通過將變量包含在$ params數組中的%符號中,您確保將%字符正確替換到查詢中。沒有此修改,PD...
    程式設計 發佈於2025-07-05
  • PHP未來:適應與創新
    PHP未來:適應與創新
    PHP的未來將通過適應新技術趨勢和引入創新特性來實現:1)適應云計算、容器化和微服務架構,支持Docker和Kubernetes;2)引入JIT編譯器和枚舉類型,提升性能和數據處理效率;3)持續優化性能和推廣最佳實踐。 引言在編程世界中,PHP一直是網頁開發的中流砥柱。作為一個從1994年就開始發展...
    程式設計 發佈於2025-07-05
  • 如何從PHP中的數組中提取隨機元素?
    如何從PHP中的數組中提取隨機元素?
    從陣列中的隨機選擇,可以輕鬆從數組中獲取隨機項目。考慮以下數組:; 從此數組中檢索一個隨機項目,利用array_rand( array_rand()函數從數組返回一個隨機鍵。通過將$項目數組索引使用此鍵,我們可以從數組中訪問一個隨機元素。這種方法為選擇隨機項目提供了一種直接且可靠的方法。
    程式設計 發佈於2025-07-05
  • 如何使用替換指令在GO MOD中解析模塊路徑差異?
    如何使用替換指令在GO MOD中解析模塊路徑差異?
    在使用GO MOD時,在GO MOD 中克服模塊路徑差異時,可能會遇到衝突,其中3個Party Package將另一個PAXPANCE帶有導入式套件之間的另一個軟件包,並在導入式套件之間導入另一個軟件包。如迴聲消息所證明的那樣: go.etcd.io/bbolt [&&&&&&&&&&&&&&&&...
    程式設計 發佈於2025-07-05
  • Async Void vs. Async Task在ASP.NET中:為什麼Async Void方法有時會拋出異常?
    Async Void vs. Async Task在ASP.NET中:為什麼Async Void方法有時會拋出異常?
    在ASP.NET async void void async void void void void void的設計無需返回asynchroncon而無需返回任務對象。他們在執行過程中增加未償還操作的計數,並在完成後減少。在某些情況下,這種行為可能是有益的,例如未期望或明確預期操作結果的火災和...
    程式設計 發佈於2025-07-05
  • JavaScript計算兩個日期之間天數的方法
    JavaScript計算兩個日期之間天數的方法
    How to Calculate the Difference Between Dates in JavascriptAs you attempt to determine the difference between two dates in Javascript, consider this s...
    程式設計 發佈於2025-07-05
  • 如何處理PHP文件系統功能中的UTF-8文件名?
    如何處理PHP文件系統功能中的UTF-8文件名?
    在PHP的Filesystem functions中處理UTF-8 FileNames 在使用PHP的MKDIR函數中含有UTF-8字符的文件很多flusf-8字符時,您可能會在Windows Explorer中遇到comploreer grounder grounder grounder gro...
    程式設計 發佈於2025-07-05
  • CSS可以根據任何屬性值來定位HTML元素嗎?
    CSS可以根據任何屬性值來定位HTML元素嗎?
    靶向html元素,在CSS 中使用任何屬性值,在CSS中,可以基於特定屬性(如下所示)基於特定屬性的基於特定屬性的emants目標元素: 字體家庭:康斯拉斯(Consolas); } 但是,出現一個常見的問題:元素可以根據任何屬性值而定位嗎?本文探討了此主題。 的目標元素有任何任何屬性值,...
    程式設計 發佈於2025-07-05
  • Android如何向PHP服務器發送POST數據?
    Android如何向PHP服務器發送POST數據?
    在android apache httpclient(已棄用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    程式設計 發佈於2025-07-05
  • C++中如何將獨占指針作為函數或構造函數參數傳遞?
    C++中如何將獨占指針作為函數或構造函數參數傳遞?
    在構造函數和函數中將唯一的指數管理為參數 unique pointers( unique_ptr [2啟示。通過值: base(std :: simelor_ptr n) :next(std :: move(n)){} 此方法將唯一指針的所有權轉移到函數/對象。指針的內容被移至功能中,在操作...
    程式設計 發佈於2025-07-05
  • 如何使用Depimal.parse()中的指數表示法中的數字?
    如何使用Depimal.parse()中的指數表示法中的數字?
    在嘗試使用Decimal.parse(“ 1.2345e-02”中的指數符號表示法時,您可能會出現錯誤。這是因為默認解析方法無法識別指數符號。 成功解析這樣的字符串,您需要明確指定它代表浮點數。您可以使用numbersTyles.Float樣式進行此操作,如下所示:[&& && && &&華氏度D...
    程式設計 發佈於2025-07-05
  • MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    在兩個條件下插入或更新或更新 solution:的答案在於mysql的插入中...在重複鍵更新語法上。如果不存在匹配行或更新現有行,則此功能強大的功能可以通過插入新行來進行有效的數據操作。如果違反了唯一的密鑰約束。 實現所需的行為,該表必須具有唯一的鍵定義(在這種情況下為'名稱'...
    程式設計 發佈於2025-07-05
  • 如何限制動態大小的父元素中元素的滾動範圍?
    如何限制動態大小的父元素中元素的滾動範圍?
    在交互式接口中實現垂直滾動元素的CSS高度限制問題:考慮一個佈局,其中我們具有與用戶垂直滾動一起移動的可滾動地圖div,同時與固定的固定sidebar保持一致。但是,地圖的滾動無限期擴展,超過了視口的高度,阻止用戶訪問頁面頁腳。 $("#map").css({ margin...
    程式設計 發佈於2025-07-05

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3