ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PlayCanvas npm 包的 ESM 非打包模块树与 sideEffects 配置对 tree-shaking 有何影响?

PlayCanvas npm 包的 ESM 非打包模块树与 sideEffects 配置对 tree-shaking 有何影响? PlayCanvas npm 包的 ESM 非打包模块树与 sideEffects 配置对 tree-shaking 有何影响【免费下载链接】enginePowerful web graphics runtime built on WebGL, WebGPU, WebXR and glTF项目地址: https://gitcode.com/GitHub_Trending/en/engine如果你在业务项目里用打包工具esbuild、Rollup、Vite 等引用playcanvasnpm 包或者你正在给 PlayCanvas 引擎本身贡献代码、需要保证新增模块不破坏包体的按需裁剪那么包内import playcanvas到底解析到什么产物、sideEffects: false声明带来哪些约束就是绕不开的问题。本文基于仓库中的 package.json、构建规则 AGENTS.md 和test/bundles/测试套件说明这套打包结构如何影响 tree-shaking并给出在仓库内运行 tree-shaking 验证测试的完整步骤。import playcanvas解析到非打包模块树package.json 的exports字段区分了两种消费方式。import条件按 Node 的 conditions 解析到非打包的 ESM 模块树require条件解析到单文件 UMD 包exports: { .: { types: ./build/playcanvas.d.ts, development: { import: ./build/playcanvas.dbg/src/index.js, require: ./build/playcanvas.dbg.js }, profiler: { import: ./build/playcanvas.prf/src/index.js, require: ./build/playcanvas.prf.js }, production: { import: ./build/playcanvas/src/index.js, require: ./build/playcanvas.js }, default: { import: ./build/playcanvas/src/index.js, require: ./build/playcanvas.js } }, ./debug: { import: ./build/playcanvas.dbg/src/index.js, require: ./build/playcanvas.dbg.js }, ./profiler: { import: ./build/playcanvas.prf/src/index.js, require: ./build/playcanvas.prf.js } }AGENTS.md 第 9 节Build System说明构建管线如何产出这些文件每种构建类型rel、dbg、prf、min都会输出一个 UMD 单文件包build/playcanvas*.js和一个 ESM 单文件包build/playcanvas*.mjs其中rel、dbg、prf的 ESM 构建额外输出一个非打包的模块树build/playcanvas/src/、build/playcanvas.dbg/src/、build/playcanvas.prf/src/而import playcanvas解析到的正是这个模块树。min构建没有模块树这一点在 test/bundles/helpers.mjs 的ESM_TARGETS定义中也得到了印证四个单文件 ESM 包加上三个 esm tree注释标明min has no tree。这就是 tree-shaking 生效的结构前提消费方的 bundler 拿到的是保留模块边界的文件树而不是一个已合并的大文件才能按模块粒度裁剪没有被 import 的部分。单文件产物playcanvas.mjs、playcanvas.js等仍可通过./build/*子路径直接使用。sideEffects: false的双向影响package.json 顶层声明了sideEffects: false。按 AGENTS.md 的说明这意味着消费方的 bundler 会丢弃引擎里所有未被 import 的模块。test/bundles/treeshake.test.mjs 开头的注释进一步指出这个声明是双向的原文cuts both ways模块树中任何一处从src/index.js可达的模块级副作用module-scope side effect都会把大量实现拖进每个消费方的包体——测试注释举例deprecated.js曾经的 prototype patches 就是这样把数百 KB 拉进所有消费方 bundle 的反过来一个没有挂在其所属类模块里的 deprecated shim会在消费方 bundle 中被整个丢弃。因此对引擎的贡献者AGENTS.md 给出三条硬性规则不要添加模块级副作用——顶层调用、prototype patches、registry 写入、window访问都算注册逻辑必须放在构造函数或函数内部deprecated 常量别名与辅助函数统一放在 src/deprecated/deprecated.js且该文件必须保持无模块级副作用——该文件头部的注释重申了这一点bundlers can drop it entirely when unuseddeprecated prototype shim例如Object.defineProperty(Foo.prototype, ...)要放在定义该类的模块底部这样它只在该类被消费时才进入 bundle。AGENTS.md 同时说明test/bundles/treeshake.test.mjs是守护上述两条规则的测试。验证方式运行仓库的 tree-shaking 测试前置条件Node 18.3.0package.json 的engines字段。在仓库根目录执行npm install npm run build npm run test:buildtest:build的脚本定义是mocha --recursive test/bundles/**/*.test.mjs --timeout 30000会跑完test/bundles/下的导出一致性、tree-shaking、live bindings 等全部测试。其中 test/bundles/treeshake.test.mjs 用 esbuild 以消费方 bundler 的方式对模块树打小应用包共 4 个用例a single small import stays small打包import { Vec3 } from playcanvas的最小应用断言输出大于 500 字节且小于 10240 字节——即只 import 一个数学类时bundle 应保持在约 10 KB 量级AppBase with container loading does not retain the gsplat implementation只 importAppBase和ContainerHandler通过 esbuild 的 metafile 检查保留的模块列表断言没有任何/scene/gsplat/、/scene/gsplat-unified/、khr-gaussian-splatting.js等 gsplat 实现模块被拖入ContainerHandler does not retain the gsplat resource implementation对ContainerHandler单 import 做同样的 metafile 断言deprecated shims survive tree-shaking and still apply打包一个 import 了AppBase、StandardMaterial等符号的 cjs 应用并在 Node 中执行断言 deprecated 兼容属性仍然生效如m.shininess 50后m.gloss为 0.5验证裁剪没有误伤挂在对类模块底部的 shim。测试里消费方打包的核心配置如下摘自该测试文件ESM_TREE_INDEX在测试中指向build/playcanvas/src/index.js与 production 条件下import playcanvas解析到的文件一致contents为被测应用源码esbuild.build({ stdin: { contents, resolveDir: REPO_ROOT, loader: js }, alias: { playcanvas: ESM_TREE_INDEX }, bundle: true, minify: true, write: false, metafile: true, format, // 用例指定 esm 或 cjs target: es2020, external: [node:worker_threads, url], logLevel: silent });其中external一项值得注意测试文件注释说明引擎的 worker 源码在 Node 环境下会 importnode:worker_threads和urlreal app bundlers must externalize them the same way——你自己的应用打包配置也应把这两个标记为 external。验证成功条件npm run test:build全部通过即导出面与src/index.js一致test/bundles/exports.test.mjs、小 import 保持小体积、gsplat 实现未被无关 import 保留、deprecated shim 未被误裁剪。如果你修改过package.json的exports/sideEffects等包元数据仓库还提供了npm run publint执行publint --level error可用于检查包字段。边界与限制tree-shaking 的模块树只对import条件生效且只覆盖rel、dbg、prf三种构建min构建不输出模块树package.json 中require条件对应的单文件 UMD 包则不适用本文讨论的按模块裁剪。消费方能否裁到多小取决于 import 图本身只 import 一个类是 10 KB 量级importAppBase这样的入口级符号自然会保留其依赖闭包但测试证明了无关子系统如 gsplat 实现仍会被裁掉。本文所有规则与数值均来自仓库文档与测试体积阈值500–10240 字节是 test/bundles/treeshake.test.mjs 的断言条件用于守护小 import 保持小体积这一性质不要把它当成某个固定版本的精确包体大小。【免费下载链接】enginePowerful web graphics runtime built on WebGL, WebGPU, WebXR and glTF项目地址: https://gitcode.com/GitHub_Trending/en/engine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表