1 | # Ember CLI HTMLBars
|
2 |
|
3 | <a href="https://github.com/ember-cli/ember-cli-htmlbars/actions"><img alt="Build Status" src="https://github.com/ember-cli/ember-cli-htmlbars/workflows/CI/badge.svg"></a>
|
4 |
|
5 | ## Compatibility
|
6 |
|
7 | * Ember.js v3.8 or above
|
8 | * Ember CLI v3.8 or above
|
9 | * Node.js v12 or above
|
10 |
|
11 | ## Tagged Template Usage / Migrating from `htmlbars-inline-precompile`
|
12 |
|
13 | Starting with version 4.0, this addon now includes the testing helper from [ember-cli-htmlbars-inline-precompile](https://github.com/ember-cli/ember-cli-htmlbars-inline-precompile)
|
14 |
|
15 | This will require an update to the imports of the `hbs` helper in your tests:
|
16 |
|
17 | Prior syntax:
|
18 |
|
19 | ```
|
20 | import hbs from 'htmlbars-inline-precompile';
|
21 |
|
22 | ...
|
23 |
|
24 | await render(hbs`
|
25 | <MyComponent />
|
26 | `);
|
27 | ```
|
28 |
|
29 | New syntax:
|
30 |
|
31 | ```
|
32 | import { hbs } from 'ember-cli-htmlbars';
|
33 |
|
34 | ...
|
35 |
|
36 | await render(hbs`
|
37 | <MyComponent />
|
38 | `);
|
39 | ```
|
40 |
|
41 | There is a [codemod](https://github.com/ember-codemods/ember-cli-htmlbars-inline-precompile-codemod) available to automate this change.
|
42 |
|
43 | ## Additional Trees
|
44 |
|
45 | For addons which want additional customizations, they are able to interact with
|
46 | this addon directly.
|
47 |
|
48 | ```ts
|
49 | interface EmberCLIHTMLBars {
|
50 | /**
|
51 | Supports easier transpilation of non-standard input paths (e.g. to transpile
|
52 | a non-addon NPM dependency) while still leveraging the logic within
|
53 | ember-cli-htmlbars for transpiling (e.g. custom AST transforms, colocation, etc).
|
54 | */
|
55 | transpileTree(inputTree: BroccoliTree): BroccoliTree;
|
56 | }
|
57 | ```
|
58 |
|
59 | ### `transpileTree` usage
|
60 |
|
61 | ```js
|
62 | // find the ember-cli-htmlbars addon
|
63 | let htmlbarsAddon = this.addons.find(addon => addon.name === 'ember-cli-htmlbars');
|
64 |
|
65 | // invoke .transpileTree passing in the custom input tree
|
66 | let transpiledCustomTree = htmlbarsAddon.transpileTree(someCustomTree);
|
67 | ```
|
68 |
|
69 | ## Adding Custom Plugins
|
70 |
|
71 | You can add custom plugins to be used during transpilation of the `addon/` or
|
72 | `addon-test-support/` trees of your addon (or the `app/` and `tests/` trees of an application)
|
73 | by registering a custom AST transform.
|
74 |
|
75 | ```js
|
76 | var SomeTransform = require('./some-path/transform');
|
77 |
|
78 | module.exports = {
|
79 | name: 'my-addon-name',
|
80 |
|
81 | included: function() {
|
82 | // we have to wrap these in an object so the ember-cli
|
83 | // registry doesn't try to call `new` on them (new is actually
|
84 | // called within htmlbars when compiling a given template).
|
85 | this.app.registry.add('htmlbars-ast-plugin', {
|
86 | name: 'some-transform',
|
87 | plugin: SomeTransform
|
88 | });
|
89 |
|
90 | this._super.included.apply(this, arguments);
|
91 | }
|
92 | };
|
93 | ```
|
94 |
|
95 | ### Options for registering a plugin
|
96 |
|
97 | * `name` - String. The name of the AST transform for debugging purposes.
|
98 | * `plugin` - A function of type [`ASTPluginBuilder`](https://github.com/glimmerjs/glimmer-vm/blob/v0.83.1/packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts#L314-L320).
|
99 | * `dependencyInvalidation` - Boolean. A flag that indicates the AST Plugin may, on a per-template basis, depend on other files that affect its output.
|
100 | * `cacheKey` - function that returns any JSON-compatible value - The value returned is used to invalidate the persistent cache across restarts, usually in the case of a dependency or configuration change.
|
101 | * `baseDir` - `() => string`. A function that returns the directory on disk of the npm module for the plugin. If provided, a basic cache invalidation is performed if any of the dependencies change (e.g. due to a npm install/upgrade).
|
102 |
|
103 | ### Implementing Dependency Invalidation in an AST Plugin
|
104 |
|
105 | Plugins that set the `dependencyInvalidation` option to `true` can provide function for the `plugin` of type `ASTDependencyPlugin` as given below.
|
106 |
|
107 | Note: the `plugin` function is invoked without a value for `this` in context.
|
108 |
|
109 | ```ts
|
110 | import {ASTPluginBuilder, ASTPlugin} from "@glimmer/syntax/dist/types/lib/parser/tokenizer-event-handlers";
|
111 |
|
112 | export type ASTDependencyPlugin = ASTPluginWithDepsBuilder | ASTPluginBuilderWithDeps;
|
113 |
|
114 | export interface ASTPluginWithDepsBuilder {
|
115 | (env: ASTPluginEnvironment): ASTPluginWithDeps;
|
116 | }
|
117 |
|
118 | export interface ASTPluginBuilderWithDeps extends ASTPluginBuilder {
|
119 | /**
|
120 | * @see {ASTPluginWithDeps.dependencies} below.
|
121 | **/
|
122 | dependencies(relativePath): string[];
|
123 | }
|
124 |
|
125 | export interface ASTPluginWithDeps extends ASTPlugin {
|
126 | /**
|
127 | * If this method exists, it is called with the relative path to the current
|
128 | * file just before processing starts. Use this method to reset the
|
129 | * dependency tracking state associated with the file.
|
130 | */
|
131 | resetDependencies?(relativePath: string): void;
|
132 | /**
|
133 | * This method is called just as the template finishes being processed.
|
134 | *
|
135 | * @param relativePath {string} A relative path to the file that may have dependencies.
|
136 | * @return {string[]} paths to files that are a dependency for the given
|
137 | * file. Any relative paths returned by this method are taken to be relative
|
138 | * to the file that was processed.
|
139 | */
|
140 | dependencies(relativePath: string): string[];
|
141 | }
|
142 | ```
|
143 |
|
144 | ## Precompile HTMLBars template strings within other addons
|
145 |
|
146 | ```javascript
|
147 | module.exports = {
|
148 | name: 'my-addon-name',
|
149 |
|
150 | setupPreprocessorRegistry: function(type, registry) {
|
151 | var htmlbarsPlugin = registry.load('template').find(function(plugin) {
|
152 | return plugin.name === 'ember-cli-htmlbars';
|
153 | });
|
154 |
|
155 | // precompile any htmlbars template string via the precompile method on the
|
156 | // ember-cli-htmlbars plugin wrapper; `precompiled` will be a string of the
|
157 | // form:
|
158 | //
|
159 | // Ember.HTMLBars.template(function() {...})
|
160 | //
|
161 | var precompiled = htmlbarsPlugin.precompile("{{my-component}}");
|
162 | }
|
163 | };
|
164 | ```
|
165 |
|
166 | ### Custom Template Compiler
|
167 |
|
168 | You can still provide a custom path to the template compiler (e.g. to test
|
169 | custom template compiler tweaks in an application) by:
|
170 |
|
171 | ```js
|
172 | // ember-cli-build.js
|
173 |
|
174 | module.exports = function(defaults) {
|
175 | let app = new EmberApp(defaults, {
|
176 | 'ember-cli-htmlbars': {
|
177 | templateCompilerPath: `some_path/to/ember-template-compiler.js`,
|
178 | }
|
179 | });
|
180 | };
|
181 | ```
|
182 |
|
183 | ## Using as a Broccoli Plugin
|
184 |
|
185 | ```javascript
|
186 | var HtmlbarsCompiler = require('ember-cli-htmlbars');
|
187 |
|
188 | var templateTree = new HtmlbarsCompiler('app/templates', {
|
189 | isHTMLBars: true,
|
190 |
|
191 | // provide the templateCompiler that is paired with your Ember version
|
192 | templateCompiler: require('./bower_components/ember/ember-template-compiler')
|
193 | });
|
194 | ```
|