From a0f05abf7930857def0f9dad6bdf37b52b3118ee Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Fri, 9 May 2025 10:24:41 -0400 Subject: [PATCH 1/5] Remove microtask in runtime compiler --- packages/@ember/template-compiler/lib/template.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/@ember/template-compiler/lib/template.ts b/packages/@ember/template-compiler/lib/template.ts index 7140656fffd..51f77b71f8f 100644 --- a/packages/@ember/template-compiler/lib/template.ts +++ b/packages/@ember/template-compiler/lib/template.ts @@ -242,12 +242,10 @@ export function template( const normalizedOptions = compileOptions(options); const component = normalizedOptions.component ?? templateOnly(); - queueMicrotask(() => { - const source = glimmerPrecompile(templateString, normalizedOptions); - const template = templateFactory(evaluate(`(${source})`) as SerializedTemplateWithLazyBlock); + const source = glimmerPrecompile(templateString, normalizedOptions); + const template = templateFactory(evaluate(`(${source})`) as SerializedTemplateWithLazyBlock); - setComponentTemplate(template, component); - }); + setComponentTemplate(template, component); return component; } From 5395bcdabdd7f2e8b7ac5a9fee9c6ff3a66b7303 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Fri, 9 May 2025 10:32:51 -0400 Subject: [PATCH 2/5] Failing test --- ...runtime-template-compiler-implicit-test.ts | 55 ++++++++++++++++++- .../@ember/template-compiler/lib/template.ts | 8 ++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts index 3aaf14d29f4..7d35a2fab58 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts +++ b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts @@ -1,5 +1,6 @@ +import { tracked } from '@ember/-internals/metal'; import { template } from '@ember/template-compiler/runtime'; -import { RenderingTestCase, defineSimpleModifier, moduleFor } from 'internal-test-helpers'; +import { RenderingTestCase, defineSimpleModifier, moduleFor, runTask } from 'internal-test-helpers'; import GlimmerishComponent from '../../utils/glimmerish-component'; import { on } from '@ember/modifier/on'; import { fn } from '@ember/helper'; @@ -7,6 +8,58 @@ import { fn } from '@ember/helper'; moduleFor( 'Strict Mode - Runtime Template Compiler (implicit)', class extends RenderingTestCase { + async '@test can have in-scope tracked data'(assert: Assert) { + class State { + @tracked str = `hello there`; + + get component() { + assert.step('get component'); + + let getStr = () => { + assert.step('getStr()'); + return this.str; + }; + + hide(getStr); + + return template(`{{ (getStr) }}`, { + eval() { + return eval(arguments[0]); + }, + }); + } + } + + let state = new State(); + + await this.renderComponentModule(() => { + return template('', { + eval() { + assert.step('eval'); + return eval(arguments[0]); + }, + }); + }); + + this.assertHTML('hello there'); + this.assertStableRerender(); + assert.verifySteps([ + // for every value in the component, for eevry node traversed in the compiler + 'eval', // precompileJSON -> ... ElementNode -> ... -> lexicalScope -> isScope('state', ...) + 'eval', // "..." + 'eval', // "..." + 'eval', // creating the templateFactory + 'get component', + 'getStr()', + ]); + + runTask(() => (state.str += '!')); + + this.assertHTML('hello there!'); + this.assertStableRerender(); + assert.verifySteps(['getStr()']); + } + async '@test Can use a component in scope'() { await this.renderComponentModule(() => { let Foo = template('Hello, world!', { diff --git a/packages/@ember/template-compiler/lib/template.ts b/packages/@ember/template-compiler/lib/template.ts index 51f77b71f8f..7140656fffd 100644 --- a/packages/@ember/template-compiler/lib/template.ts +++ b/packages/@ember/template-compiler/lib/template.ts @@ -242,10 +242,12 @@ export function template( const normalizedOptions = compileOptions(options); const component = normalizedOptions.component ?? templateOnly(); - const source = glimmerPrecompile(templateString, normalizedOptions); - const template = templateFactory(evaluate(`(${source})`) as SerializedTemplateWithLazyBlock); + queueMicrotask(() => { + const source = glimmerPrecompile(templateString, normalizedOptions); + const template = templateFactory(evaluate(`(${source})`) as SerializedTemplateWithLazyBlock); - setComponentTemplate(template, component); + setComponentTemplate(template, component); + }); return component; } From 4f48e3bee65d47d7752c561300808f8a79ae4002 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Fri, 9 May 2025 10:33:00 -0400 Subject: [PATCH 3/5] Make test pass --- packages/@ember/template-compiler/lib/template.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/@ember/template-compiler/lib/template.ts b/packages/@ember/template-compiler/lib/template.ts index 7140656fffd..51f77b71f8f 100644 --- a/packages/@ember/template-compiler/lib/template.ts +++ b/packages/@ember/template-compiler/lib/template.ts @@ -242,12 +242,10 @@ export function template( const normalizedOptions = compileOptions(options); const component = normalizedOptions.component ?? templateOnly(); - queueMicrotask(() => { - const source = glimmerPrecompile(templateString, normalizedOptions); - const template = templateFactory(evaluate(`(${source})`) as SerializedTemplateWithLazyBlock); + const source = glimmerPrecompile(templateString, normalizedOptions); + const template = templateFactory(evaluate(`(${source})`) as SerializedTemplateWithLazyBlock); - setComponentTemplate(template, component); - }); + setComponentTemplate(template, component); return component; } From 2cfb538a824698b497355014a33689b9ccc94d77 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 13 May 2025 14:00:27 -0400 Subject: [PATCH 4/5] use a clearer test for this PR This test was presumably extracted from https://github.com/emberjs/ember.js/pull/20907/files wher eit makes sense. I'm replacing it with one that only covers the immediate change being made in this PR. --- ...runtime-template-compiler-implicit-test.ts | 39 ++----------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts index 7d35a2fab58..78a5852ed16 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts +++ b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts @@ -1,6 +1,5 @@ -import { tracked } from '@ember/-internals/metal'; import { template } from '@ember/template-compiler/runtime'; -import { RenderingTestCase, defineSimpleModifier, moduleFor, runTask } from 'internal-test-helpers'; +import { RenderingTestCase, defineSimpleModifier, moduleFor } from 'internal-test-helpers'; import GlimmerishComponent from '../../utils/glimmerish-component'; import { on } from '@ember/modifier/on'; import { fn } from '@ember/helper'; @@ -8,34 +7,19 @@ import { fn } from '@ember/helper'; moduleFor( 'Strict Mode - Runtime Template Compiler (implicit)', class extends RenderingTestCase { - async '@test can have in-scope tracked data'(assert: Assert) { + async '@test can immediately render a runtime-compiled template'() { class State { - @tracked str = `hello there`; - get component() { - assert.step('get component'); - - let getStr = () => { - assert.step('getStr()'); - return this.str; - }; - - hide(getStr); - - return template(`{{ (getStr) }}`, { - eval() { - return eval(arguments[0]); - }, - }); + return template(`hello there`); } } + // eslint-disable-next-line @typescript-eslint/no-unused-vars let state = new State(); await this.renderComponentModule(() => { return template('', { eval() { - assert.step('eval'); return eval(arguments[0]); }, }); @@ -43,21 +27,6 @@ moduleFor( this.assertHTML('hello there'); this.assertStableRerender(); - assert.verifySteps([ - // for every value in the component, for eevry node traversed in the compiler - 'eval', // precompileJSON -> ... ElementNode -> ... -> lexicalScope -> isScope('state', ...) - 'eval', // "..." - 'eval', // "..." - 'eval', // creating the templateFactory - 'get component', - 'getStr()', - ]); - - runTask(() => (state.str += '!')); - - this.assertHTML('hello there!'); - this.assertStableRerender(); - assert.verifySteps(['getStr()']); } async '@test Can use a component in scope'() { From da1d2fd6ba3c5195beb0b13ac7fd1e8ef3c14d77 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:33:33 -0400 Subject: [PATCH 5/5] Fix hidden variable --- .../components/runtime-template-compiler-implicit-test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts index 78a5852ed16..5d4e975acc1 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts +++ b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts @@ -14,9 +14,10 @@ moduleFor( } } - // eslint-disable-next-line @typescript-eslint/no-unused-vars let state = new State(); + hide(state); + await this.renderComponentModule(() => { return template('', { eval() {