Fixing PixiJS iOS Page Refreshes and JS Scope Issues in Shadow DOM
Understanding Shadow DOM vs. Iframes for Canvas Games
Migrating embedded interactive applications like PixiJS games from <iframe> elements to Shadow DOM is a popular choice for improving integration and performance. However, this architecture shift introduces subtle differences in how web browsers manage JavaScript execution contexts, WebGL rendering pipelines, and memory constraints—especially on iOS WebKit devices.
Problem 1: Does Shadow DOM Isolate JavaScript Scope?
A common misconception is that Shadow DOM provides a JavaScript sandbox similar to an <iframe>. It does not.
Shadow DOM provides DOM tree isolation and CSS style encapsulation, but it shares the global window context with the parent document.
When scripts are dynamically loaded or injected into a Shadow Root without standard module isolation, top-level variable declarations (such as const lang = "en";) are evaluated in the global scope. If two independent games declare the same top-level constant using const or let in the global execution context, JavaScript throws an unhandled Uncaught SyntaxError: Identifier 'lang' has already been declared exception.
How to Ensure Complete JS Isolation
To prevent global namespace pollution without using an iframe, you must explicitly scope your scripts using one of the following approaches:
- Use IIFEs (Immediately Invoked Function Expressions): Wrap custom build bundles inside an IIFE closure to isolate variables.
- Use ES Modules: Ensure dynamically loaded scripts use
type="module"or are bundled as ES module formats (ESM) through Module Federation.