Skip to content

Relocate deprecated API shims so the ESM engine tree-shakes - #9251

Open
willeastcott wants to merge 1 commit into
mainfrom
relocate-deprecated-shims-for-tree-shaking
Open

Relocate deprecated API shims so the ESM engine tree-shakes#9251
willeastcott wants to merge 1 commit into
mainfrom
relocate-deprecated-shims-for-tree-shaking

Conversation

@willeastcott

Copy link
Copy Markdown
Contributor

Description

Any import from the ESM package currently retains most of the engine: deprecated.js is the one module listed in sideEffects, and its module-scope prototype patches statically import AppBase, StandardMaterial, ForwardRenderer, RigidBodyComponentSystem and more — so bundlers must keep that entire graph even for import { Vec3 } from 'playcanvas'.

This PR moves every prototype-patch shim onto the class it patches, as a regular member with @ignore/@deprecated JSDoc (the existing Entity#getGuid idiom). Each shim now ships only when its class does and behaves identically at runtime. deprecated.js keeps only side-effect-free aliases and helper functions, and package.json now declares "sideEffects": false.

Measured with esbuild (minified), same tree before/after:

Bundle Before After
import { Vec3 } only 882 KB raw / 229 KB gzip (559 modules) 3.2 KB / 1.1 KB (3 modules)
Minimal engine-only cube app 1129 KB / 297 KB gzip 1056 KB / 279 KB gzip
Full namespace (everything used) 2391 KB 2391 KB — unchanged

@playcanvas/react and web-components inherit the win automatically. UMD builds are unaffected (all exports retained, shims applied identically).

Notes for reviewers:

  • Shims with runtime-computed names can't be class members and remain module-scope helper loops (StandardMaterial vertex-color/tint aliases, StandardMaterialOptions litOptions forwarding). These are invisible to tsc, so they don't affect the d.ts.
  • ForwardRenderer#renderComposition is patched from app-base.js because it needs getApplication and scene code must not import from framework.
  • The anisotropy entry is removed from the rollup-types-fixup synthesis list — the real accessor now provides the typing. This also fixes its d.ts doc text, which was previously mis-sliced from anisotropyIntensity's @property doc.
  • Three StandardMaterial setters assign their target properties via Object.assign because tsc declaration emit synthesizes duplicate member declarations from literal this.x = ... assignments to fixup-managed dynamic props.
  • Deprecated members now appear in the d.ts typed and @deprecated-tagged (previously invisible to TypeScript users); @ignore keeps them out of the API docs, as with Entity#getGuid.
  • New canary test in test/bundles/treeshake.test.mjs bundles import { Vec3 } against the built ESM tree and fails above 10 KB, so a future module-scope side effect can't silently regress tree-shaking.

Verified: full unit suite (2337 passing, failures identical to main baseline), all 61 bundle tests (exports parity across all 11 targets, smoke, canary), build:types + test:types, lint, publint, plus a runtime check that all 27 shim behaviors and deprecated exports are unchanged.

Checklist

  • I have read the contributing guidelines
  • My code follows the project's coding standards
  • This PR focuses on a single change

🤖 Generated with Claude Code

deprecated.js was the one module listed in package.json sideEffects, and
its module-scope prototype patches statically imported AppBase,
StandardMaterial, ForwardRenderer, RigidBodyComponentSystem and more. As
a result, any import from the ESM package retained most of the engine:
a Vec3-only app bundled to 882 KB (229 KB gzip).

Each shim now lives on the class it patches as a regular member with
@ignore/@deprecated JSDoc (matching Entity#getGuid), so it ships only
when the class does and behaves identically. Shims with runtime-computed
names (StandardMaterial vertex-color/tint aliases, StandardMaterialOptions
litOptions forwarding) remain module-scope helper loops, and the
ForwardRenderer#renderComposition patch stays in app-base.js because it
needs getApplication and scene code must not import from framework.
deprecated.js keeps only side-effect-free aliases and helper functions,
and package.json now declares sideEffects: false.

Type declarations: the anisotropy entry is removed from the
rollup-types-fixup synthesis list since the real accessor now provides
the typing (this also fixes its doc text, which was mis-sliced from
anisotropyIntensity). Three StandardMaterial setters assign their target
properties via Object.assign because tsc declaration emit synthesizes
duplicate members from literal this.x assignments to fixup-managed props.

A canary test bundles 'import { Vec3 }' against the built ESM tree and
fails if it exceeds 10 KB, so a future module-scope side effect cannot
silently regress tree-shaking.

Measured (esbuild, minified): Vec3-only app 882 KB -> 3.2 KB
(229 KB -> 1.1 KB gzip); minimal engine-only cube app 1129 KB -> 1056 KB
(297 KB -> 279 KB gzip); full-namespace bundle unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2389.6 KB (−0.8 KB, −0.03%) 614.4 KB (−0.3 KB, −0.05%) 476.8 KB (−0.3 KB, −0.06%)
playcanvas.min.mjs 2387.0 KB (−0.8 KB, −0.03%) 613.1 KB (−0.3 KB, −0.05%) 476.4 KB (−0.1 KB, −0.02%)

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant