創(chuàng)建一個(gè)雙模式跨運(yùn)行時(shí)的 JavaScript 包,你學(xué)會(huì)了嗎
本文將指導(dǎo)你發(fā)布雙模式、跨運(yùn)行時(shí)的 JavaScript 包。了解如何創(chuàng)建與 ESM 和 CommonJS 以及 Node.js、Deno 和瀏覽器等不同運(yùn)行時(shí)兼容的庫。
隨著 JavaScript 開發(fā)的不斷發(fā)展,人們?cè)絹碓叫枰茉诙喾N環(huán)境中運(yùn)行的強(qiáng)大依賴包。在本文中,我們將探討如何發(fā)布跨運(yùn)行時(shí)、雙模式的 JavaScript 包。這些包彌補(bǔ)了 ESM 和 CommonJS 之間的差距,讓開發(fā)人員可以在任何環(huán)境下使用相同的包和文檔。
在深入了解之前,讓我們先熟悉一些關(guān)鍵概念:
雙模式包
雙模式包旨在與多個(gè) JavaScript 模塊系統(tǒng)(尤其是 ES Modules (ESM) 和 CommonJS (CJS))配合使用。這確保了代碼在各種環(huán)境中的可重用性和靈活性。創(chuàng)建雙模式包有幾個(gè)好處:
- 「更廣泛的兼容性」:并非所有項(xiàng)目都已過渡到使用 ESM。雙模式確保你的包可以在仍然依賴于 CommonJS 的項(xiàng)目中使用。
- 「無縫過渡」:隨著 JavaScript 生態(tài)系統(tǒng)逐步轉(zhuǎn)向 ESM,雙模式包可確保用戶實(shí)現(xiàn)無縫過渡,而無需更換包或重構(gòu)代碼庫。
- 「減少維護(hù)」:雙模式包允許用戶管理單一代碼庫,而無需分別維護(hù) ESM 和 CJS 包。
不過,雙模式并不能保證軟件包在不同的運(yùn)行環(huán)境下都能正常工作,這就帶來了以下問題:
跨運(yùn)行時(shí)包
跨運(yùn)行時(shí)包可在 Deno、瀏覽器和 Node.js 等多種環(huán)境中運(yùn)行。它們旨在為不同運(yùn)行時(shí)提供一致的 API。一個(gè)全面的跨運(yùn)行時(shí)包應(yīng)同時(shí)支持 ESM 和 CJS,尤其是因?yàn)?Node.js 在很大程度上仍在使用 CommonJS。
如果我們忽略 Node.js 的傳統(tǒng)限制(Node.js 嚴(yán)重依賴 CommonJS),我們可以只使用 ES 模塊構(gòu)建跨運(yùn)行時(shí)包。這將簡化包,但會(huì)限制其與舊版 Node.js 項(xiàng)目的兼容性。
Node還是Deno優(yōu)先
你有兩種主要方法:從 Deno 或 Node.js 開始。Deno 優(yōu)先方法使用 Deno 的內(nèi)置工具和 Deno 到Node工具(DNT)。另一方面,Node優(yōu)先方法使用傳統(tǒng)的構(gòu)建工具來完成測(cè)試、檢查和打包等任務(wù)。這種方法是轉(zhuǎn)換現(xiàn)有 NPM 庫的首選。
Deno優(yōu)先方法
Deno優(yōu)先方法依賴于DNT,你可以在GitHub[1]上找到。
該工具通過版本庫中的自定義構(gòu)建腳本使用。
第一步是建立一個(gè)基本的 Deno 庫,準(zhǔn)備發(fā)布到 deno.land/x。之后,你就可以使用 DNT 了。
「添加腳本」
Deno優(yōu)先方法的核心是構(gòu)建流程。下面這個(gè)名為 scripts/build_npm.ts 的腳本使用 DNT 創(chuàng)建一個(gè) /npm 文件夾,其中包含一個(gè)完整的 NPM 包,可以隨時(shí)發(fā)布。
該腳本將處理清除 NPM 目錄、復(fù)制測(cè)試數(shù)據(jù)和構(gòu)建軟件包等任務(wù)。它還會(huì)創(chuàng)建一個(gè)完整的 package.json 文件。
讓我們一起來看看吧,請(qǐng)務(wù)必閱讀注釋。
import { build, copy, emptyDir } from "./deps.ts";
// Clear NPM directory
await emptyDir("./npm");
// (optional) Copy test data, if you have some
// await copy("tests/data", "npm/esm/tests/data", { overwrite: true });
// This assumes that the entrypoint of your module is ./mod.ts
await build({
entryPoints: ["./mod.ts"],
outDir: "./npm",
shims: {
deno: "dev",
},
/*
mappings: {
"<https://deno.land/x/zipjs@v2.7.17/index.js>": {
name: "@zip.js/zip.js",
version: "^2.7.17"
},
},
*/
package: {
// package.json template
name: "my-library-name",
version: Deno.args[0],
description: "My library description.",
license: "MIT",
repository: {/* ... */},
author: "You <your@mail>",
/* Additional information */
},
});
// (optional) post build steps, you might want to copy some files?
// ---------------------------------------------------------------
// Deno.copyFileSync("LICENSE", "npm/LICENSE");
// Deno.copyFileSync("README.md", "npm/README.md");
// (optional) Add .npmignore
// ---------------------------------------------------------------
// ensure the test data is ignored in the `.npmignore` file
// so it doesn't get published with your npm package, if relevant
/*
await Deno.writeTextFile(
"npm/.npmignore",
"esm/tests/data\nscript/tests/data\n",
{ append: true },
);
*/
現(xiàn)在,你只需運(yùn)行 deno run -A scripts/build_npm.ts 0.0.1 來構(gòu)建 0.0.1 版本的 npm 軟件包。所有相關(guān)文件都將在 ./npm 中生成。
最后一步是導(dǎo)航到 ./npm 目錄,然后運(yùn)行 npm publish,就可以了!
「使用 deno.json 更新構(gòu)建管道流」
要記錄這一構(gòu)建步驟,可以修改 deno.json 的task部分,將新的 NPM 構(gòu)建步驟包括在內(nèi)。下面是一個(gè)設(shè)置測(cè)試和 NPM 構(gòu)建的配置示例:
{
/* ... existing configuration ... */
"tasks": {
"test": "deno test tests --allow-read",
"build": "deno run -A scripts/build_npm.ts"
}
}
現(xiàn)在,運(yùn)行 deno task build 0.0.1 時(shí)將生成 npm 包。
Node優(yōu)先方法
或者,你也可以選擇Node優(yōu)先的方法來創(chuàng)建跨運(yùn)行時(shí)包。
第一步是確保你的項(xiàng)目同時(shí)支持 ESM 和 CommonJS。這既可以手動(dòng)完成,也可以使用構(gòu)建工具來處理。代碼庫最好是非轉(zhuǎn)譯的 javascript 或 typescript,以便 Rollup 或類似工具處理。
讓我們以 @hexagon/base64 庫為例進(jìn)行分析。該庫使用 Rollup 生成 ESM 和 CommonJS 版本的代碼,配置如下:
// rollup.config.js
export default [
{
input: "./src/base64.single.js",
output: {
file: "dist/base64.cjs",
format: "umd",
name: "base64",
exports: "default"
}
},
{
input: "./src/base64.js",
output: {
file: "dist/base64.mjs",
format: "es"
}
}
];
該庫的源代碼(/src/base64.js)是以各種方式導(dǎo)出 base64 對(duì)象的普通 ES JavaScript。
// src/base64.js
/* ...
Library code making up the base64 object
... */
// Default export
export default base64;
// Named export
export { base64 };
Rollup 無法處理多重導(dǎo)出,因此我還創(chuàng)建了一個(gè) /src/base64.single.js,默認(rèn)情況下它只負(fù)責(zé)重新導(dǎo)出 base64 對(duì)象。這是 Rollup 配置的 UMD 目標(biāo)所使用的。
// /src/base64.single.js
import base64 from "./base64.js";
export default base64;
package.json
package.json 文件是設(shè)置雙模式、跨運(yùn)行時(shí) JavaScript 包的關(guān)鍵。它決定了包在不同環(huán)境中的結(jié)構(gòu)和行為方式。讓我們來仔細(xì)看看其中的關(guān)鍵部分及其重要性:
{
/* ... your metadata ... */
"scripts": {
/* ... your existing build steps ... */
"build:dist": "rollup -c ./rollup.config.js",
},
"type": "module",
"main": "./dist/base64.cjs",
"browser": "./dist/base64.min.js",
"module": "./src/base64.js",
"types": "types/base64.single.d.ts",
"exports": {
".": {
"import": "./src/base64.js",
"require": "./dist/base64.cjs",
"browser": "./dist/base64.min.js"
}
}
}
- 「"scripts"」 :該部分包含構(gòu)建和管理包所需的腳本。在提供的示例中,"build:dist"用于觸發(fā) Rollup 打包過程。根據(jù)包的具體要求,你可能還需要其他腳本來進(jìn)行測(cè)試、檢查或執(zhí)行其他任務(wù)。
- 「"type"」 :該字段設(shè)置為"module",表示你的包是為使用 ESM(ES 模塊)導(dǎo)入而設(shè)計(jì)的。
- 「"main"」 :該字段指定了 CommonJS 環(huán)境(如 Node.js)的入口點(diǎn)。它指向包的 CommonJS 版本,通常位于 dist 目錄中。
- 「"browser"」 :該字段用于指定瀏覽器環(huán)境的替代入口點(diǎn)。它指向包的最小化版本,以增強(qiáng)與瀏覽器的兼容性。
- 「"module"」 :與 "main"字段類似,該字段用于指定 ESM 環(huán)境的入口點(diǎn)。它指向軟件包的 ESM 版本。
- 「"types"」 :此字段指明軟件包的 TypeScript 聲明文件(.d.ts)的位置。這些文件為 TypeScript 用戶提供了類型信息,改善了開發(fā)人員的體驗(yàn)。
- 「"exports"」 :該字段是一項(xiàng)最新功能,允許你定義如何導(dǎo)入包。它為 ESM、CommonJS 和瀏覽器環(huán)境指定了不同的導(dǎo)入路徑,確保了跨運(yùn)行時(shí)的流暢兼容性。
根據(jù)包的具體需求和配置,你可能需要對(duì) package.json 進(jìn)行或多或少的修改。仔細(xì)調(diào)整和測(cè)試該文件以確保其在發(fā)布時(shí)正常運(yùn)行至關(guān)重要。
跨運(yùn)行時(shí)部分
前面提到的步驟主要是在 Node.js 中設(shè)置雙模式兼容性。雖然 Deno 可以使用開箱即用的 npm 軟件包,但要?jiǎng)?chuàng)建一個(gè)完整的跨運(yùn)行時(shí)包,你還應(yīng)該將其適配到 Deno。
這包括閱讀 Deno 庫的工作原理[2]、將軟件包發(fā)布到 deno.land/x[3]。
還有就是,讓你的軟件包成為雙模式軟件也能幫助其他項(xiàng)目。
總結(jié)
創(chuàng)建雙模式、跨運(yùn)行時(shí)的 JavaScript 包是一種有益的體驗(yàn)。它能使你的代碼具有可移植性和可重用性,讓你在不同的 JavaScript 環(huán)境中接觸到更多的用戶。雖然會(huì)有一些障礙和注意事項(xiàng),如管理兼容性以及與不同模塊系統(tǒng)和運(yùn)行時(shí)的配合,但利大于弊。
本文譯自:https://hexagon.56k.guru/posts/dual-mode-cross-runtime-packages/
以上就是本文的全部內(nèi)容,如果對(duì)你所有幫助,歡迎點(diǎn)贊、收藏、轉(zhuǎn)發(fā)~
參考資料
[1]GitHub:https://github.com/denoland/dnt
[2]Deno 庫的工作原理:https://deno.land/manual@v1.36.4/introduction
[3]將軟件包發(fā)布到 deno.land/x:https://deno.land/manual@v1.36.4/advanced/publishing