diff --git a/.local.dic b/.local.dic index 0c19f5a993..18383b65b2 100644 --- a/.local.dic +++ b/.local.dic @@ -96,6 +96,8 @@ getters Getters GIFs GitLab +gjs +GJS GlimmerX globbing hackable diff --git a/guides/release/components/template-tag-format.md b/guides/release/components/template-tag-format.md index 6754e4cfec..d8b7a61254 100644 --- a/guides/release/components/template-tag-format.md +++ b/guides/release/components/template-tag-format.md @@ -259,6 +259,117 @@ export default CustomSelect; This can be a powerful refactoring technique to break up large components into smaller ones. (where it makes sense!) +## Low-level, Pure-JavaScript format + +All of template-tag format has an equivalent pure-JS representation. + +The template-only-component case converts like this: + +```gjs +// ----- GJS Syntax ------------------------ +import { pageTitle } from "ember-page-title"; + +const LandingPage = ; + +// ------ Equivalent JS Syntax ------------- +import { pageTitle } from "ember-page-title"; +import { template } from '@ember/template-compiler'; + +const LandingPage = template(`{{pageTitle "Welcome"}} +

Welcome

`, { + scope: () => ({ pageTitle }) +}) +``` + +And the class-based-component case converts likes this: + + +```gjs +// ------ GJS Syntax --------------- +import { pageTitle } from "ember-page-title"; + +class LandingPage extends Component { + +} + +// ------ Equivalent JS Syntax ------------- +import { pageTitle } from "ember-page-title"; +import { template } from '@ember/template-compiler'; + +class LandingPage extends Component { + static { + template(`{{pageTitle "Welcome"}} +

Welcome

`, { + component: this, + scope: () => ({ pageTitle }) + }); + } +} +``` + +Just like the `` syntax, `template()` from `@ember/template-compiler` can be build-time optimized, so you're not allowed to use any syntax other than string literals for the first argument. For example: + +```js +import { template } from '@ember/template-compiler'; + +// This is OK because the first argument to template() is a string literal: +const LandingPage = template(`{{pageTitle "Welcome"}} +

Welcome

`, { + scope: () => ({ pageTitle }) +}) + +// This is a build error because the first argument is not a string literal: +const LandingPage = template(buildTemplate(), { + scope: () => ({ pageTitle }) +}) + +function buildTemplate() { + return `{{pageTitle "Welcome"}} +

Welcome

`; +} +``` + +If you want to relax this restriction, you can opt-in to runtime template compilation instead. This is more expensive at runtime and pulls additional template-compilation code into your app. But it's appropriate for dynamic environments like interactive development tools: + +```js +// Notice the different import path here: +import { template } from '@ember/template-compiler/runtime'; + +// This is now OK because no static build-time analysis will +// be performed, and you can use arbitrary code to produce a +// string value at runtime. +const LandingPage = template(buildTemplate(), { + scope: () => ({ pageTitle }) +}) + +function buildTemplate() { + return `{{pageTitle "Welcome"}} +

Welcome

`; +} +``` + +### Scope Arguments + +The `