Skip to content

feat(galacean): add conditional exports#3058

Open
luo2430 wants to merge 5 commits into
galacean:dev/2.0from
luo2430:fix/galacean
Open

feat(galacean): add conditional exports#3058
luo2430 wants to merge 5 commits into
galacean:dev/2.0from
luo2430:fix/galacean

Conversation

@luo2430

@luo2430 luo2430 commented Jul 1, 2026

Copy link
Copy Markdown
  • The commit message follows our guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

主要用于适配在一个utils包中包装部分功能并且 export * from "@galacean/engine"; 以方便其它库使用的情况。

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The top-level browser field in packages/galacean/package.json was removed and replaced with an exports map for ".", defining conditional entry points for types, import, and default. The unpkg and jsdelivr fields remain unchanged.

Changes

Package Exports Configuration

Layer / File(s) Summary
Exports map replaces browser field
packages/galacean/package.json
Removed top-level browser field and added exports["."] mapping types, import, and default conditions to ./types/index.d.ts, ./dist/module.js, and ./dist/main.js respectively.

Estimated code review effort: 1 (Trivial) | ~3 minutes

Poem

A rabbit hops through package.json's field,
No more browser gate, new exports revealed,
Types and imports, each finds its way,
Through tidy little maps that guide the play. 🐇📦

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding conditional exports to the galacean package.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.36%. Comparing base (721b42a) to head (e4cfc2d).

Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #3058      +/-   ##
===========================================
- Coverage    79.37%   79.36%   -0.02%     
===========================================
  Files          903      903              
  Lines       100632   100632              
  Branches     11260    11256       -4     
===========================================
- Hits         79879    79865      -14     
- Misses       20569    20583      +14     
  Partials       184      184              
Flag Coverage Δ
unittests 79.36% <ø> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/galacean/package.json (1)

17-24: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Missing "./package.json" subpath export.

Once "exports" is defined, only listed subpaths remain accessible — tools that read the dependency's own package.json (bundlers, React Native/Metro, require.resolve('galacean/package.json'), etc.) will fail with ERR_PACKAGE_PATH_NOT_EXPORTED. This is a well-known gotcha (see nodejs/node#33460, react-native-community/cli#1168) that has broken several popular packages after adopting exports.

🔧 Suggested addition
   "exports": {
     ".": {
       "types": "./types/index.d.ts",
       "import": "./dist/module.js",
       "browser": "./dist/browser.js",
       "default": "./dist/main.js"
-    }
+    },
+    "./package.json": "./package.json"
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/galacean/package.json` around lines 17 - 24, The package exports map
in the package.json currently omits the package’s own package.json subpath,
which breaks consumers that resolve it directly. Update the exports block in the
package manifest to include the "./package.json" subpath alongside the existing
"." entry so tools like bundlers, Metro, and require.resolve can access it. Keep
the fix localized to the package.json exports definition and preserve the
current main/browser/module/type entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/galacean/package.json`:
- Around line 17-24: The package exports map in the galacean package is ordered
incorrectly, causing resolvers that match both conditions to select the import
target before the browser build. Update the object in the exports entry so the
browser condition is listed before import, keeping the types entry unchanged and
preserving the existing default fallback.

---

Nitpick comments:
In `@packages/galacean/package.json`:
- Around line 17-24: The package exports map in the package.json currently omits
the package’s own package.json subpath, which breaks consumers that resolve it
directly. Update the exports block in the package manifest to include the
"./package.json" subpath alongside the existing "." entry so tools like
bundlers, Metro, and require.resolve can access it. Keep the fix localized to
the package.json exports definition and preserve the current
main/browser/module/type entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f2285e36-c5e1-4739-9a7c-dfcab3783759

📥 Commits

Reviewing files that changed from the base of the PR and between 721b42a and 48abd80.

📒 Files selected for processing (3)
  • packages/galacean/package.json
  • packages/galacean/src/ShaderPool.ts
  • packages/galacean/src/index.ts

Comment on lines +17 to +24
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./dist/module.js",
"browser": "./dist/browser.js",
"default": "./dist/main.js"
}
},

@coderabbitai coderabbitai Bot Jul 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What condition key order do Vite, Webpack 5, and Rollup use when resolving package.json "exports" for browser + ESM builds, and does key order in the exports object take priority over the resolver's condition list order?

💡 Result:

Vite, Webpack 5, and Rollup all adhere to the Node.js module resolution specification, which mandates that within the "exports" object of a package.json file, key order is significant [1][2][3]. During conditional export resolution, keys are checked in the order they appear in the object; the first matching condition found is the one that takes precedence [2][4][5]. Because the resolution process stops as soon as a match is found, the order of keys in the "exports" object effectively defines the priority of your conditions [2][4]. The standard practice is to list conditions from most specific to least specific (e.g., placing custom environment conditions before general fallbacks like "default") [5][3]. Regarding your question on priority: key order within the "exports" object takes absolute priority over the order in which you might list or "enable" conditions in a resolver's configuration [1][2]. While the bundler's configuration (such as Webpack's resolve.conditionNames or Vite/Rollup's export conditions) determines which conditions are currently "active" or available to be matched, the resolver will only select a condition if it exists in that active list AND appears earliest in the "exports" object's defined order [1][2][4]. Consequently, if you have both "import" and "require" active in your configuration, the one that appears first in your package.json "exports" object will be the one chosen [4].

Citations:


Place browser before import in the package exports map

exports resolution follows object key order, so with "import" first, browser ESM resolvers that enable both conditions will match ./dist/module.js before ./dist/browser.js. Move "browser" ahead of "import" to make the browser build selectable.

Suggested fix
   "exports": {
     ".": {
       "types": "./types/index.d.ts",
-      "import": "./dist/module.js",
       "browser": "./dist/browser.js",
+      "import": "./dist/module.js",
       "default": "./dist/main.js"
     }
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./dist/module.js",
"browser": "./dist/browser.js",
"default": "./dist/main.js"
}
},
"exports": {
".": {
"types": "./types/index.d.ts",
"browser": "./dist/browser.js",
"import": "./dist/module.js",
"default": "./dist/main.js"
}
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/galacean/package.json` around lines 17 - 24, The package exports map
in the galacean package is ordered incorrectly, causing resolvers that match
both conditions to select the import target before the browser build. Update the
object in the exports entry so the browser condition is listed before import,
keeping the types entry unchanged and preserving the existing default fallback.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@luo2430 Got it, kicking off the change to reorder the exports map.

  • Reorder exports["."] in packages/galacean/package.json so browser precedes import, keeping types first and default last.

Failed to handle agent chat message. Please try again.

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

总结

两个 commit:feat@galacean/engineexports 条件导出映射;refactor 把 3 处 @ts-ignore@ts-expect-error 并把注册循环从 for...inObject.entriesrefactor 部分全部正确,但 exports 映射的条件排序有方向性错误——而且 CodeRabbit 建议、作者已回复 "apply" 的那个"修复"会把问题从「无效」变成「有害」。请勿 apply 那个 diff。

先厘清三个产物的真实格式(来自 rollup.config.js):

dist 文件 格式 用途
dist/module.js ES moduleformat:"es",可 tree-shake) ESM import
dist/browser.js UMDformat:"umd",全局 Galacean <script> 标签
dist/main.js CommonJSformat:"commonjs" require / node

关键:browser.jsUMD,不是「浏览器版 ESM」。

问题

[P1] packages/galacean/package.json:17-24exports 里把 UMD 挂到 browser 条件,排序两难,正确解是删掉这个条件

exports 条件按对象键顺序匹配,且 browser格式无关的环境条件(只表示"浏览器变体",不表示 ESM/CJS)。而这里 browser 指向的是 UMD bundle。于是:

  • 当前状态(import 在前,browser 在后):所有现代打包器(Vite/Webpack5/Rollup)在浏览器 ESM 模式下同时启用 browserimport,键顺序让 importmodule.js(ESM) 先命中。browser 这条永远轮不到,是死条件——只有"启用 browser 但不启用 import"的解析器才会命中它,现实中不存在。所以现在不会坏,但 browser 条目毫无作用。

  • CodeRabbit 建议 + 作者已回 "apply" 的改法(browser 提到 import 前):浏览器打包器会先命中 browser→拿到 UMD browser.js,而不是可 tree-shake 的 ESM module.js。这是实打实的退化:UMD 不可 tree-shake、破坏静态 import 分析、bundle 体积变大。方向反了,请不要 apply。

根因是「把 UMD 产物放进 exportsbrowser 条件」这件事本身就错——browser 条件的语义是"给浏览器用的模块变体",正确填法应是浏览器用的 ESM(也就是 module.js),而不是 UMD。但 module.js 已经由 import 覆盖,所以 browser 条件在 exports没有独立价值

建议exports 里直接删掉 browser 条件,只保留标准三段:

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

(把兜底的 default 语义显式拆出 require+default,比单个 default 更清晰;也可只留 import+default。)UMD 的 browser.js 继续通过 CDN 的 unpkg/jsdelivr 字段和 <script> 直链分发,不需要进 exports

竞品对标:Three.js(Web 引擎标杆)的 exports 只有 import/require 两条,根本不放 browser 条件——它的 three.module.js(ESM) 就是浏览器构建,因为现代打包器要的就是 ESM。UMD 只走 <script>,不进 exports。Galacean 这里应对齐同一模型。

补充一个副作用提示(非阻塞):新增 exports 后,任何支持 exports 的解析器会以 exports唯一入口,顶层 main/module 字段被其覆盖。本包只导出 barrel、无深层子路径导入,所以安全;但这属于 module resolution 的语义变更,建议在 commit body 里点一句 BREAKING/behavior-change 备案。

已验证无问题的改动(回应作者"仍需验证")

  • index.ts 注册循环 for...inObject.entries:等价且正确import * as CoreObjectsmodule namespace object——原型为 null、所有导出都是 own+enumerable 的字符串键。for...in(无原型链可走)与 Object.entries 在此枚举完全相同的键集,不会漏注册任何类;export type 只存在于类型层、运行时已被擦除不进 namespace。改动同时消除了 CoreObjects[key] 的 TS 索引类型报错。作者担心的"循环原型链"其实对 namespace object 不成立(原型是 null),但改法本身仍是净改进。无需再验证
  • 3 处 @ts-ignore@ts-expect-error:安全且更优。挂在 _createFromPrecompiled/_feedbackVaryings/SystemInfo._initialize 三处真实 @internal 违规上,确有 TS error,@ts-expect-error 合法;一旦这些成员将来转公开,@ts-expect-error 会主动报"未使用的抑制"提醒清理,比 @ts-ignore 强。index.ts 删掉 version 行上方的 //@ts-ignore 也安全——\__buildVersion` 是普通模板字面量、编译期无 error;若真有 error,b:types`(tsc) 会拦。

问题(元信息)

[P2] PR 标题混装 feat + refactor

标题 feat(galacean): ... | refactor(galacean): ... 把一个新功能和一次重构塞进同一 PR。这会影响 changelog 生成和回滚粒度(revert 一个会连带丢掉另一个)。建议拆成两个 PR,或标题只体现主体变更类型。提一次,不阻塞。


自检:refactor 两项已逐一从第一性原理验证等价性(namespace object 枚举语义 / @ts-expect-error 触发条件);exports 结论与 CodeRabbit 相反(其建议方向错误),非重复而是纠正;产物格式均已从 rollup.config.js 实证(browser.js=UMD)。

@luo2430 luo2430 changed the title feat(galacean): add conditional exports with browser field support | refactor(galacean): replace @ts-ignore with @ts-expect-error and modernize loop feat(galacean): add conditional exports Jul 1, 2026
@luo2430

luo2430 commented Jul 1, 2026

Copy link
Copy Markdown
Author

改好了,不会是还没睡吧

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

总结

作者把前一版整体 revert(ffa133f02 撤 refactor、7bae7d55f 撤旧 feat),重新以单文件 e4cfc2d9e feat(galacean): add conditional exports 落地——packages/galacean/package.json 净加 7 行 exports 块,其余全部退出本 PR。方向完全正确,上轮唯一阻塞 P1 已闭环。

上轮问题闭环情况

  • [P1] exports 里 UMD 挂 browser 条件✅ 已按我的建议修复。新 exports 只保留标准三段 types/import/default没有 browser 条件。作者虽然对 CodeRabbit 的 inline 回了 "apply",但并未真的 apply 那个「browser 提到 import 前」的有害改法(那会让浏览器打包器拿到不可 tree-shake 的 UMD),而是走了删掉 browser 条件的正解。对齐 Three.js 模型(exports 只放 import/require 类条件,UMD 走顶层字段 + CDN)。
  • [P2] 标题混装 feat+refactor✅ 已消除。refactor commit 已 revert,PR 现在是纯 feat、单文件。

本轮复核(新 HEAD e4cfc2d9e

逐条从第一性原理确认最终形态正确:

  • types 在首位 ✅(Node 规范要求类型条件先于运行时条件命中)
  • import./dist/module.js(ESM,可 tree-shake)✅
  • default./dist/main.js(CJS,兜底覆盖 require 及其他解析器)✅
  • 顶层 browser: "dist/browser.js" 字段保留且留在 exports 之外——这是对的:legacy browserify/webpack4 的 browser-field remap 独立于 exports,保留无害;unpkg/jsdelivr 是 CDN 专用非标准字段,不受 exports 影响。
  • 顺带确认了那条上轮标注的非阻塞 side-effect(exports 一旦存在即成为 "." 的唯一解析入口、覆盖顶层字段)确实安全:全仓 grep 无任何 @galacean/engine/<subpath> 深层导入,消费者一律走 barrel,exports 只导出 "." 不 break 任何内部依赖。

无 P0/P1/P2/P3 新问题。之前的 CHANGES_REQUESTED 门控随本次 approve 解除。LGTM。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants