Description
@playcanvas/react crashes at import time in Node/SSR environments when used with playcanvas engine ≥ 2.20.0.
getNullApplication() in src/utils/validation.ts creates its SSR mock canvas as a bare object:
const mockCanvas = { id: 'pc-react-mock-canvas' };
return new Application(mockCanvas, { graphicsDevice: new NullGraphicsDevice(mockCanvas) });
Since engine v2.20.0 (playcanvas/engine#8950), the base GraphicsDevice constructor calls this.canvas.getBoundingClientRect(), so new NullGraphicsDevice(mockCanvas) now throws:
TypeError: this.canvas.getBoundingClientRect is not a function
This is compounded by the module-scope call in the same file:
const localApp = getNullApplication();
export const getStaticNullApplication = () => localApp;
Because localApp is created eagerly during module evaluation, any import of @playcanvas/react in Node throws — there is no way for consumers to catch or avoid it.
Impact
Broke the developer.playcanvas.com Docusaurus build (static site generation failed for all 639 doc pages) after upgrading to playcanvas 2.20.4. The site is temporarily pinned to engine ~2.19.7 (playcanvas/developer-site#1074).
The engine-side regression is tracked in playcanvas/engine#8999, but this package should be robust regardless.
Suggested fixes
- Give the mock canvas a
getBoundingClientRect stub (zeroed rect: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 }) plus any other DOM surface the device constructor path touches.
- Make
localApp lazy — initialize on first getStaticNullApplication() call — so a failure inside getNullApplication() can't break module evaluation for every importer.
Verified against playcanvas 2.20.4 (throws) and 2.19.7 (works).
🤖 Generated with Claude Code
Description
@playcanvas/reactcrashes at import time in Node/SSR environments when used with playcanvas engine ≥ 2.20.0.getNullApplication()insrc/utils/validation.tscreates its SSR mock canvas as a bare object:Since engine v2.20.0 (playcanvas/engine#8950), the base
GraphicsDeviceconstructor callsthis.canvas.getBoundingClientRect(), sonew NullGraphicsDevice(mockCanvas)now throws:This is compounded by the module-scope call in the same file:
Because
localAppis created eagerly during module evaluation, any import of@playcanvas/reactin Node throws — there is no way for consumers to catch or avoid it.Impact
Broke the developer.playcanvas.com Docusaurus build (static site generation failed for all 639 doc pages) after upgrading to playcanvas 2.20.4. The site is temporarily pinned to engine
~2.19.7(playcanvas/developer-site#1074).The engine-side regression is tracked in playcanvas/engine#8999, but this package should be robust regardless.
Suggested fixes
getBoundingClientRectstub (zeroed rect:{ left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 }) plus any other DOM surface the device constructor path touches.localApplazy — initialize on firstgetStaticNullApplication()call — so a failure insidegetNullApplication()can't break module evaluation for every importer.Verified against playcanvas 2.20.4 (throws) and 2.19.7 (works).
🤖 Generated with Claude Code