☰
ethers.js 的 ESM 构建产物(lib.esm):目录职责、生成机制与 import 使用指南
2026/9/25 4:11:10 网站建设 项目流程
  • 区块链
  • Web3

【免费下载链接】ethers.js

Complete Ethereum library and wallet implementation in JavaScript.

项目地址:https://gitcode.com/gh_mirrors/et/ethers.js
点击查看免费下载

本篇指南围绕 ethers.js 仓库中 misc/basedirs/lib.esm/README.md 展开,系统讲解lib.esm/目录在 ESM(ES Module)项目中的角色、它如何通过npm run build与tsconfig.esm.json生成,以及作为"构建产物只读目录"在使用与维护上应遵循的规则。读完本文,你将掌握:ESM 与 CommonJS 两种构建产物在 ethers.js 中如何共存、package.json的exports双入口如何路由到lib.esm、浏览器环境下的模块替换机制,以及如何在自己的 ESM 项目中正确importethers。

lib.esm 是什么:为 ESM 项目准备的构建产物目录

在 ethers.js 仓库中,lib.esm/目录存放的是使用 ES Module 语法(import/export)编写的编译产物,专门服务于采用 ESM 模块体系的 JavaScript/TypeScript 项目。与它并行的还有一个 lib.commonjs/ 目录,存放使用require的 CommonJS 版本,两者内容同源,只是模块格式不同。

对照两个目录各自的 README(lib.esm/README.md 与 lib.commonjs/README.md),可以看到结构高度一致,都明确写着:"The contents of this folder are for usingimport(或require)in ESM(或 CommonJS)projects"。

从目录实际内容看,lib.esm/与lib.commonjs/保持着镜像式的模块布局,均包含abi/、address/、constants/、contract/、crypto/、hash/、providers/、transaction/、utils/、wallet/、wordlists/等子模块目录,每个模块下同时产出.js、.js.map(source map)、.d.ts、.d.ts.map文件。这种一一对应的结构保证了:无论消费者使用哪种模块体系,都能以相同的路径结构访问到同一套 API。

与 CommonJS 版本的差异

维度lib.esm(ESM)lib.commonjs(CommonJS)
模块语法import/exportrequire/module.exports
适用项目ESM 项目("type": "module"、.mjs、现代打包器)CommonJS 项目(require)
生成命令npm run buildnpm run build-commonjs
编译配置tsconfig.esm.jsontsconfig.commonjs.json
声明文件随 ESM 产物生成.d.ts与 source map随 CommonJS 产物生成.d.ts与 source map

值得注意的是,lib.esm/package.json 中声明了"type": "module",这会让 Node.js 将目录内的.js文件一律按 ESM 解析;而lib.commonjs目录则保持默认的 CommonJS 语义。这是双格式共存时让 Node.js 正确区分模块类型的关键配置。

生成机制:npm run build 与 tsconfig.esm.json

lib.esm/不是手写维护的源码,而是由构建工具自动生成的产物。这一点在 misc/basedirs/lib.esm/README.md 中讲得很清楚:

  • 目录内容通过npm run build目标生成,底层调用的是tsc(TypeScript 编译器)与/tsconfig.esm.json配置;
  • 不要手动修改该目录中的任何文件,因为它们在build-clean时会被整体删除并重新生成。

构建命令与脚本链路

查看 package.json 中的 scripts 可以还原完整的构建链路:

{ "scripts": { "build": "tsc --project tsconfig.esm.json", "build-commonjs": "tsc --project tsconfig.commonjs.json", "build-all": "npm run build && npm run build-commonjs", "build-clean": "npm run clean && npm run build && node lib.esm/_admin/update-version.js && node lib.esm/_admin/update-changelog.js && npm run build-all && npm run _build-dist && npm run _dist-stats", "clean": "rm -rf dist lib.esm lib.commonjs && cp -r misc/basedirs/* ." } }

其中关键点是:

  • npm run build等价于tsc --project tsconfig.esm.json,产出lib.esm/;
  • npm run build-commonjs等价于tsc --project tsconfig.commonjs.json,产出lib.commonjs/;
  • npm run build-clean是"全量重建":先执行clean(删除dist、lib.esm、lib.commonjs三个目录,并从misc/basedirs/复制基础文件回来——这正是两个 README 模板的来源),再依次执行 ESM 构建、版本号更新、CHANGELOG 更新、CommonJS 构建、dist 打包与体积统计;
  • auto-build(npm run build -- -w)开启 TypeScript 的 watch 模式,适合开发期间自动增量编译。

tsconfig.esm.json 的编译配置

tsconfig.esm.json 本身非常精简,通过extends继承公共基础配置:

{ "extends": "./tsconfig.base.json", "compilerOptions": { "module": "es2020", "outDir": "./lib.esm" } }

它只覆盖了两个关键项:

  • "module": "es2020":指定输出 ES2020 模块语法(即标准的import/export),这是 ESM 产物与 CommonJS 产物(tsconfig.commonjs.json 中为"module": "commonjs")的根本区别;
  • "outDir": "./lib.esm":指定输出目录。

其余编译选项统一继承自 tsconfig.base.json,包括"target": "es2022"、"strict": true、"declaration": true(生成.d.ts)、"declarationMap": true、"sourceMap": true(生成.js.map)、"rootDir": "./src.ts"(源码根目录为src.ts/)、"importHelpers": true(复用 tslib 减少重复代码)等。也就是说,lib.esm中的每个.js文件都对应src.ts/下的一个 TypeScript 源文件,.d.ts与.js.map则分别服务于类型提示和调试时的源码映射。

产物目录的只读属性

README 中特别强调了两条维护规则:

  1. 不要修改lib.esm/内的文件——它们是编译输出,任何手改都会在下一次build或build-clean时被覆盖;
  2. 如需修改lib.esm/README.md本身,应修改其模板源 misc/basedirs/lib.esm/README.md(README 中原文指向/output/post-build/lib.esm,结合clean脚本中的cp -r misc/basedirs/* .可知,misc/basedirs/就是这些模板文件的实际存放位置),该目录在build-clean时会被重新复制回lib.esm/。

正确的做法是:改动一律落在src.ts/源码或misc/basedirs/模板中,然后重新构建。

双入口路由:package.json 如何把 ESM 消费者指向 lib.esm

lib.esm/之所以能在发布后直接供 ESM 项目使用,依靠的是根 package.json 中的exports字段——它是 Node.js 与现代打包器(如 Rollup、webpack、Vite)解析包内模块入口的依据。

{ "main": "./lib.commonjs/index.js", "module": "./lib.esm/index.js", "exports": { ".": { "import": "./lib.esm/index.js", "default": "./lib.commonjs/index.js" }, "./abi": { "import": "./lib.esm/abi/index.js", "default": "./lib.commonjs/abi/index.js" }, "./address": { "import": "./lib.esm/address/index.js", "default": "./lib.commonjs/address/index.js" }, "./wallet": { "import": "./lib.esm/wallet/index.js", "default": "./lib.commonjs/wallet/index.js" } } }

解析逻辑如下:

  • ESM 消费者(使用import,或 Node.js 检测到"type": "module")命中"import"条件,加载./lib.esm/index.js;
  • CommonJS 消费者(使用require)命中"default"条件,加载./lib.commonjs/index.js;
  • 细粒度子路径导入:exports为ethers/wallet、ethers/providers、ethers/utils等子模块分别声明了 ESM 与 CommonJS 双入口,便于按需引入。官方文档 docs.wrm/getting-started.wrm 中的示例正是这种用法:import { HDNodeWallet } from "ethers/wallet";;
  • "main"与"module"字段则作为旧工具链的兼容回退:main指向 CommonJS 版本,module指向 ESM 版本,供不支持exports的打包器使用。

值得注意的是,package.json 还声明了"sideEffects": false,配合 ESM 产物使用,打包器可安全地对lib.esm中的模块进行 tree-shaking(按需摇树优化),只保留实际用到的导出。

浏览器环境适配:lib.esm 内的平台替换

lib.esm/不仅服务于 Node.js 的 ESM 项目,也服务于浏览器端的 ESM 打包场景。根 package.json 与 lib.esm/package.json 中都配置了browser字段,把依赖 Node.js 内置能力(或 Node 专有 API)的实现替换为浏览器版:

{ "browser": { "./lib.esm/crypto/crypto.js": "./lib.esm/crypto/crypto-browser.js", "./lib.esm/providers/provider-ipcsocket.js": "./lib.esm/providers/provider-ipcsocket-browser.js", "./lib.esm/providers/ws.js": "./lib.esm/providers/ws-browser.js", "./lib.esm/utils/base64.js": "./lib.esm/utils/base64-browser.js", "./lib.esm/utils/geturl.js": "./lib.esm/utils/geturl-browser.js", "./lib.esm/wordlists/wordlists.js": "./lib.esm/wordlists/wordlists-browser.js" } }

这六组映射覆盖了典型的 Node-only 模块:

  • 加密原语(crypto.js→crypto-browser.js,使用 Web Crypto / 浏览器安全随机源);
  • IPC Socket 提供者(provider-ipcsocket.js→provider-ipcsocket-browser.js,浏览器中不存在本地 IPC 通道);
  • WebSocket 实现(ws.js→ws-browser.js,替换 Node 的ws包为浏览器原生 WebSocket);
  • Base64 编解码(base64.js→base64-browser.js,使用atob/btoa);
  • HTTP 请求(geturl.js→geturl-browser.js,使用fetch/XMLHttpRequest);
  • 词库加载(wordlists.js→wordlists-browser.js)。

根package.json中的映射键带./lib.esm/前缀,与子包内自带的映射互为补充,共同保证打包器在浏览器目标下替换掉这些模块。这解释了为何一个仓库能同时支撑 Node 服务端与浏览器端的 ESM 应用。

在 ESM 项目中实际使用 lib.esm

理解了生成机制与路由规则后,在真实的 ESM 项目中消费 ethers 就非常直接。安装与导入方式如下(示例源自 docs.wrm/getting-started.wrm):

# 安装 ethers npm install ethers
// 方式一:整体导入,所有 API 挂载在 ethers 对象上 import { ethers } from "ethers"; // 方式二:按需导入少量对象 import { BrowserProvider, parseUnits } from "ethers"; // 方式三:从细粒度子路径导入(对应 package.json 的 exports 子入口) import { HDNodeWallet } from "ethers/wallet";

在浏览器中,也可以直接用<script type="module">从 CDN 引入 ESM 构建:

<script type="module"> import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js"; // Your code here... </script>

当你的项目满足以下任一条件时,Node.js 或打包器就会命中lib.esm分支:

  • 项目package.json声明了"type": "module";
  • 使用.mjs扩展名;
  • 使用 Rollup、Vite、webpack 等以 ESM 为目标的现代打包器,并通过"import"条件解析。

lib.esm中各子模块的入口文件(如 lib.esm/wallet/index.js、lib.esm/providers/index.js)会进一步导出该模块的完整 API 集合;而 lib.esm/ethers.js 汇总了全部公共导出(从 ABI 编解码、地址处理、合约、密码学到 Provider/Signer、交易、钱包与词库),lib.esm/index.js 则同时提供ethers命名空间对象与平铺导出两种形式。版本信息由 lib.esm/_version.js 导出(当前为6.17.0),该文件同样由构建流程中的update-version.js自动维护,不应手改。

小结

  • lib.esm/是 ethers.js 为 ESM 项目生成的只读构建产物,与lib.commonjs/一一对应,共用同一套 TypeScript 源码(src.ts/);
  • 它由npm run build(即tsc --project tsconfig.esm.json)生成,tsconfig.esm.json通过"module": "es2020"与"outDir": "./lib.esm"决定输出格式与位置;
  • 根 package.json 的exports字段将import消费者路由到lib.esm/index.js,将require消费者路由到lib.commonjs/index.js,并提供ethers/wallet等子路径细粒度入口;
  • browser字段在浏览器打包场景下把 Node 专属实现替换为浏览器版(crypto、ws、base64、geturl、ipcsocket、wordlists);
  • 维护规则:不要手改lib.esm/内文件,如需调整 README 模板应改 misc/basedirs/lib.esm/README.md,所有功能改动落在src.ts/后重新构建。

对源码级细节感兴趣的读者,可以继续深入 src.ts/index.ts、src.ts/ethers.ts(ESM 产物的编译输入)以及 lib.commonjs/README.md(对照理解 CommonJS 一侧的生成规则)。

  • 区块链
  • Web3

【免费下载链接】ethers.js

Complete Ethereum library and wallet implementation in JavaScript.

项目地址:https://gitcode.com/gh_mirrors/et/ethers.js
点击查看免费下载

相关推荐

上一篇:cli-anything-iterm2 技术指南:通过 CLI 无头驱动 iTerm2 会话、tmux 集成与偏好设置
下一篇:CefFlashBrowser:让Flash内容重获新生的终极解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询