Skip to content

Commit 03c4948

Browse files
lifeartclaude
andcommitted
fix(gxt): swap globalThis.owner per outlet render so engine refinements don't bleed into application
The shared `<ember-outlet>` element calls `tpl.render(nestedContext, this)` without first swapping `globalThis.owner`. When the nested outlet's owner is an engine instance (different from the application owner), curly bare identifiers like `{{ambiguous-curlies}}` resolve via `$_maybeHelper`, which reads `globalThis.owner` to call `factoryFor('component:...')` — picking up the application's registry instead of the engine's. A template registered in BOTH the application and the engine therefore resolved engine-scoped component refinements against the application owner, leaking application state into the engine's render output. Save the previous `globalThis.owner`, swap to the nested outlet's render owner for the duration of `tpl.render`, and restore it in the finally block. This matches the analogous swap already present in `gxt-backend/outlet.gts`'s EmberOutletElement implementation. Fixes the two failing 'has separate refinements' tests in `Application test: engine rendering` (20/20 pass; smoke 333/333). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent 1c51bd4 commit 03c4948

1 file changed

Lines changed: 17 additions & 0 deletions

File tree

  • packages/@ember/-internals/glimmer/lib/templates

packages/@ember/-internals/glimmer/lib/templates/outlet.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,20 @@ class EmberOutletElement extends HTMLElement {
250250
/* ignore */
251251
}
252252

253+
// Engine support: when the nested outlet's render owner is an engine
254+
// instance (different from the application owner), swap globalThis.owner
255+
// for the duration of tpl.render so that $_maybeHelper / $_tag / component
256+
// resolution find the engine's registry (e.g. engine-scoped helpers,
257+
// components registered only on the engine). Without this swap a shared
258+
// template registered in BOTH application and engine would resolve curly
259+
// bare identifiers (`{{ambiguous-curlies}}`) against the application owner
260+
// even while rendering inside the engine's outlet, leaking application
261+
// refinements into the engine's render output.
262+
const previousGlobalOwner = (globalThis as any).owner;
263+
const ownerSwapped = owner && owner !== previousGlobalOwner;
264+
if (ownerSwapped) {
265+
(globalThis as any).owner = owner;
266+
}
253267
try {
254268
if (typeof tpl?.render === 'function') {
255269
tpl.render(nestedContext, this);
@@ -262,6 +276,9 @@ class EmberOutletElement extends HTMLElement {
262276
}
263277
}
264278
} finally {
279+
if (ownerSwapped) {
280+
(globalThis as any).owner = previousGlobalOwner;
281+
}
265282
(globalThis as any).__currentOutletState = previousOutletState;
266283
if (_parentViewPushed) {
267284
try {

0 commit comments

Comments
 (0)