-
-
Notifications
You must be signed in to change notification settings - Fork 514
docs: Add Template Tag format guides #1978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
1aaceec
docs: add initial template tag format page
2c2a67a
docs: add IDE setup
e5e765b
docs: tweak sentence
528f4f6
docs: port code examples of template-imports readme
3f4a1b4
docs: full rewrite of the template tag format guide
e7151b0
fix: typos
2cc1e39
docs: remove simply as it might not be simple for everyone
b78bbcb
docs: add nested component info
3e16462
docs: fix import path
11474cf
Update guides/release/components/template-tag-format.md
IgnaceMaes 206b746
docs: reword tip sentence
aa39c52
fix: use your own app
a494d34
docs: rephrase sentence
c57a53c
fix: colon typo
a61262e
Apply suggestions from code review
IgnaceMaes 0fa636e
refactor: use function over arrow syntax
11ff45a
feat: link to previous section
af94444
feat: add co-location RFC link
c03e910
docs: use relative imports
af128c4
Update guides/release/components/template-tag-format.md
IgnaceMaes 4214351
docs: add link to rfc
4a24993
fix: include the in link
aeb3de2
Update guides/release/components/template-tag-format.md
IgnaceMaes ad2ebd6
docs: clarify invokables
294d26b
docs: make inline import blocks explicit
7cd69d0
docs: remove barrel file mention
b3d6344
docs: clarify rfc stage
57cdaa3
docs: add camelCase convention
dd0fc74
docs: callout installation
b3b707f
docs: make built-ins an actual code block
d7f6312
docs: fix internal link
9e40721
docs: reword
020308e
fix: typo
c68687a
docs: reword sentence on imports
5ea8d3d
deps: set override for ember-cli-showdown
6ad0e9b
Revert "deps: set override for ember-cli-showdown"
3a96d53
chore: point to vsc repo for textmate grammars
IgnaceMaes ceaa2e0
docs: add keywords section
IgnaceMaes 7334378
Fix linting
mansona a406109
fix test
mansona 41bd12b
fix node tests
mansona File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| The template tag component format allows defining a component's template using a `<template>` tag block. This block is a first-class participant in JavaScript and TypeScript with strict mode template semantics. For this new format, the extensions `.gjs` and `.gts` are used respectively. | ||
|
|
||
| Template tag components address a number of pain points when defining a template as a separate file, and provide a number of new capabilities: | ||
|
|
||
|
IgnaceMaes marked this conversation as resolved.
|
||
| - Accessing local JavaScript values requires no backing class, enabling much easier use of existing JavaScript ecosystem tools. | ||
| - Authoring more than one component in a single file, where colocation makes sense. | ||
| - Creating locally-scoped helpers, modifiers, and other JavaScript functionality *just works*. | ||
|
|
||
| ## Installation | ||
|
|
||
| To use template tag components, install the [ember-template-imports](https://github.com/ember-template-imports/ember-template-imports) addon: | ||
|
|
||
| ```bash | ||
| npm add --save-dev ember-template-imports | ||
| ``` | ||
|
|
||
| For integration with tools like Prettier and Glint, and information on version compatibility, refer to the addon's readme. | ||
|
|
||
| ## Editor Integrations | ||
|
|
||
| To get syntax highlighting inside embedded templates and support for the GJS file extension, you may need to configure your editor. | ||
|
|
||
| ### Visual Studio Code | ||
|
|
||
| The [Ember.js extension pack](https://marketplace.visualstudio.com/items?itemName=EmberTooling.emberjs) bundles everything you need to get started. More specifically, the [vscode-glimmer-syntax](https://marketplace.visualstudio.com/items?itemName=lifeart.vscode-glimmer-syntax) extension will add support for `glimmer-js` and `glimmer-ts` languages. | ||
|
|
||
| ### Neovim | ||
|
|
||
| Here's an [example Neovim Config](https://github.com/NullVoxPopuli/dotfiles/blob/main/home/.config/nvim/lua/plugins/syntax.lua#L52) with support for good highlighting of embedded templates in JS and TS, using: | ||
|
|
||
| - [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) | ||
| - [tree-sitter-glimmer](https://github.com/alexlafroscia/tree-sitter-glimmer) | ||
|
|
||
| ### Other editors | ||
|
|
||
| For other editors, you may be able to get support using one of these other syntax definitions: | ||
|
|
||
| - [TextMate](https://github.com/IgnaceMaes/glimmer-textmate-grammar) | ||
| - [TreeSitter](https://github.com/alexlafroscia/tree-sitter-glimmer) | ||
|
|
||
| ## Using Template Tags and `.gjs`/`.gts` Files | ||
|
|
||
| The new `<template>` tag format is available in `.gjs` and `.gts` files. These file extensions represent a new file format "GlimmerJS" and "GlimmerTS", which are supersets of standard JavaScript and TypeScript respectively. In this syntax, templates are defined in JavaScript files directly. | ||
|
|
||
| This example defines a template-only component, which is the default export of hello.gjs: | ||
|
|
||
| ```text {data-filename="app/components/hello.gjs"} | ||
| <template> | ||
| <span>Hello, {{@name}}!</span> | ||
| </template> | ||
| ``` | ||
|
|
||
| You would be able to use this component in another component like so: | ||
|
|
||
| ```text {data-filename="app/components/world.gjs"} | ||
| import Hello from 'example-app/components/hello'; | ||
|
|
||
| <template> | ||
| <Hello @name="world" /> | ||
| </template> | ||
| ``` | ||
| You can also export the component explicitly: | ||
|
|
||
| ```text {data-filename="components/hello.gjs"} | ||
| export default <template> | ||
| <span>Hello, {{@name}}!</span> | ||
| </template>; | ||
| ``` | ||
|
|
||
| Omitting the `export default` is just syntactic sugar. In addition, you can | ||
| define template-only components and assign them to variables, allowing you to | ||
| export components with named exports: | ||
|
|
||
| ```text {data-filename="components/hello.gjs"} | ||
| export const First = <template>First</template>; | ||
|
|
||
| export const Second = <template>Second</template>; | ||
|
|
||
| export const Third = <template>Third</template>; | ||
| ``` | ||
|
|
||
| This also allows you to create components that are only used locally, in the | ||
| same file: | ||
|
|
||
| ```text {data-filename="components/custom-select.gjs"} | ||
| const Option = <template> | ||
| <option selected={{@selected}} value={{@value}}> | ||
| {{or @title @value}} | ||
| </option> | ||
| </template>; | ||
|
|
||
| export const CustomSelect = <template> | ||
| <select> | ||
| {{#each @options as |opt|}} | ||
| <Option | ||
| @value={{opt.value}} | ||
| @selected={{eq opt @selectedOption}} | ||
| /> | ||
| {{/each}} | ||
| </select> | ||
| </template>; | ||
| ``` | ||
|
|
||
| Helpers and modifiers can also be defined in the same file as your components, | ||
| making them very flexible: | ||
|
|
||
| ```text {data-filename="components/list.gjs"} | ||
| import { modifier } from 'ember-modifier'; | ||
|
|
||
| const plusOne = (num) => num + 1; | ||
|
|
||
| const setScrollPosition = modifier((element, [position]) => { | ||
| element.scrollTop = position | ||
| }); | ||
|
|
||
| <template> | ||
| <div class="scroll-container" {{setScrollPosition @scrollPos}}> | ||
| {{#each @items as |item index|}} | ||
| Item #{{plusOne index}}: {{item}} | ||
| {{/each}} | ||
| </div> | ||
| </template> | ||
| ``` | ||
|
|
||
| Finally, to associate a template with a class-based component, you can use the | ||
| template syntax directly in the class body: | ||
|
|
||
| ```text {data-filename="components/hello.gjs"} | ||
| import Component from '@glimmer/component'; | ||
| import { tracked } from '@glimmer/tracking'; | ||
| import { on } from '@ember/modifier'; | ||
|
|
||
| export default class Hello extends Component { | ||
| @tracked count = 0; | ||
|
|
||
| increment = () => { | ||
| this.count += 1; | ||
| }; | ||
|
|
||
| decrement = () => { | ||
| this.count -= 1; | ||
| }; | ||
|
|
||
| <template> | ||
| <button {{on "click" this.increment}}>+</button> | ||
| Count: {{this.count}} | ||
| <button {{on "click" this.decrement}}>−</button> | ||
| </template> | ||
| } | ||
| ``` | ||
|
|
||
| Template tag components can also be used for writing tests. In fact, this aligned syntax between app code and test code is one of the big advantages of the new authoring format. | ||
|
|
||
| Just like in app code, the template tag has access to the outer scope. This means you can reference variables directly in your tests: | ||
|
|
||
| ```text {data-filename="tests/integration/components/hello-test.gjs"} | ||
| import Hello from 'example-app/components/hello'; | ||
| import { module, test } from 'qunit'; | ||
| import { setupRenderingTest } from 'ember-qunit'; | ||
| import { render } from '@ember/test-helpers'; | ||
|
|
||
| module('Integration | Component | hello', function (hooks) { | ||
| setupRenderingTest(hooks); | ||
|
|
||
| test('renders name argument', async function (assert) { | ||
| const name = 'world'; | ||
| await render(<template><Hello @name={{name}} /></template>); | ||
| assert.dom('[data-test-id="some-selector"]').hasText(name); | ||
| }); | ||
| }); | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.