4

创建一个双模式跨运行时的 JavaScript 包 - chuckQu

 8 months ago
source link: https://www.cnblogs.com/chuckQu/p/17929422.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

创建一个双模式跨运行时的 JavaScript 包

本文将指导你发布双模式、跨运行时的 JavaScript 包。了解如何创建与 ESM 和 CommonJS 以及 Node.js、Deno 和浏览器等不同运行时兼容的库。

随着 JavaScript 开发的不断发展,人们越来越需要能在多种环境中运行的强大依赖包。在本文中,我们将探讨如何发布跨运行时、双模式的 JavaScript 包。这些包弥补了 ESM 和 CommonJS 之间的差距,让开发人员可以在任何环境下使用相同的包和文档。

在深入了解之前,让我们先熟悉一些关键概念:

双模式包旨在与多个 JavaScript 模块系统(尤其是 ES Modules (ESM) 和 CommonJS (CJS))配合使用。这确保了代码在各种环境中的可重用性和灵活性。创建双模式包有几个好处:

  • 更广泛的兼容性:并非所有项目都已过渡到使用 ESM。双模式确保你的包可以在仍然依赖于 CommonJS 的项目中使用。
  • 无缝过渡:随着 JavaScript 生态系统逐步转向 ESM,双模式包可确保用户实现无缝过渡,而无需更换包或重构代码库。
  • 减少维护:双模式包允许用户管理单一代码库,而无需分别维护 ESM 和 CJS 包。

不过,双模式并不能保证软件包在不同的运行环境下都能正常工作,这就带来了以下问题:

跨运行时包

跨运行时包可在 Deno、浏览器和 Node.js 等多种环境中运行。它们旨在为不同运行时提供一致的 API。一个全面的跨运行时包应同时支持 ESM 和 CJS,尤其是因为 Node.js 在很大程度上仍在使用 CommonJS。

如果我们忽略 Node.js 的传统限制(Node.js 严重依赖 CommonJS),我们可以只使用 ES 模块构建跨运行时包。这将简化包,但会限制其与旧版 Node.js 项目的兼容性。

Node还是Deno优先

你有两种主要方法:从 Deno 或 Node.js 开始。Deno 优先方法使用 Deno 的内置工具和 Deno 到Node工具(DNT)。另一方面,Node优先方法使用传统的构建工具来完成测试、检查和打包等任务。这种方法是转换现有 NPM 库的首选。

Deno优先方法

Deno优先方法依赖于DNT,你可以在GitHub上找到。

该工具通过版本库中的自定义构建脚本使用。

第一步是建立一个基本的 Deno 库,准备发布到 deno.land/x。之后,你就可以使用 DNT 了。

添加脚本

Deno优先方法的核心是构建流程。下面这个名为 scripts/build_npm.ts 的脚本使用 DNT 创建一个 /npm 文件夹,其中包含一个完整的 NPM 包,可以随时发布。

该脚本将处理清除 NPM 目录、复制测试数据和构建软件包等任务。它还会创建一个完整的 package.json 文件。

让我们一起来看看吧,请务必阅读注释。

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/[email protected]/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 },
);
*/

现在,你只需运行 deno run -A scripts/build_npm.ts 0.0.1 来构建 0.0.1 版本的 npm 软件包。所有相关文件都将在 ./npm 中生成。

最后一步是导航到 ./npm 目录,然后运行 npm publish,就可以了!

使用 deno.json 更新构建管道流

要记录这一构建步骤,可以修改 deno.jsontask部分,将新的 NPM 构建步骤包括在内。下面是一个设置测试和 NPM 构建的配置示例:

{
    /* ... existing configuration ... */
    "tasks": {
        "test": "deno test tests --allow-read",
        "build": "deno run -A scripts/build_npm.ts"
    }
}

现在,运行 deno task build 0.0.1 时将生成 npm 包。

Node优先方法

或者,你也可以选择Node优先的方法来创建跨运行时包。

第一步是确保你的项目同时支持 ESM 和 CommonJS。这既可以手动完成,也可以使用构建工具来处理。代码库最好是非转译的 javascript 或 typescript,以便 Rollup 或类似工具处理。

让我们以 @hexagon/base64 库为例进行分析。该库使用 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)是以各种方式导出 base64 对象的普通 ES JavaScript。

// src/base64.js
/* ...
   Library code making up the base64 object
   ... */

// Default export
export default base64;

// Named export
export { base64 };

Rollup 无法处理多重导出,因此我还创建了一个 /src/base64.single.js,默认情况下它只负责重新导出 base64 对象。这是 Rollup 配置的 UMD 目标所使用的。

// /src/base64.single.js
import base64 from "./base64.js";
export default base64;

package.json

package.json 文件是设置双模式、跨运行时 JavaScript 包的关键。它决定了包在不同环境中的结构和行为方式。让我们来仔细看看其中的关键部分及其重要性:

{
  /* ... 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" :该部分包含构建和管理包所需的脚本。在提供的示例中,"build:dist"用于触发 Rollup 打包过程。根据包的具体要求,你可能还需要其他脚本来进行测试、检查或执行其他任务。
  • "type" :该字段设置为"module",表示你的包是为使用 ESM(ES 模块)导入而设计的。
  • "main" :该字段指定了 CommonJS 环境(如 Node.js)的入口点。它指向包的 CommonJS 版本,通常位于 dist 目录中。
  • "browser" :该字段用于指定浏览器环境的替代入口点。它指向包的最小化版本,以增强与浏览器的兼容性。
  • "module" :与 "main"字段类似,该字段用于指定 ESM 环境的入口点。它指向软件包的 ESM 版本。
  • "types" :此字段指明软件包的 TypeScript 声明文件(.d.ts)的位置。这些文件为 TypeScript 用户提供了类型信息,改善了开发人员的体验。
  • "exports" :该字段是一项最新功能,允许你定义如何导入包。它为 ESM、CommonJS 和浏览器环境指定了不同的导入路径,确保了跨运行时的流畅兼容性。

根据包的具体需求和配置,你可能需要对 package.json 进行或多或少的修改。仔细调整和测试该文件以确保其在发布时正常运行至关重要。

跨运行时部分

前面提到的步骤主要是在 Node.js 中设置双模式兼容性。虽然 Deno 可以使用开箱即用的 npm 软件包,但要创建一个完整的跨运行时包,你还应该将其适配到 Deno。

这包括阅读 Deno 库的工作原理将软件包发布到 deno.land/x

还有就是,让你的软件包成为双模式软件也能帮助其他项目。

创建双模式、跨运行时的 JavaScript 包是一种有益的体验。它能使你的代码具有可移植性和可重用性,让你在不同的 JavaScript 环境中接触到更多的用户。虽然会有一些障碍和注意事项,如管理兼容性以及与不同模块系统和运行时的配合,但利大于弊。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK