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() {