|
1 | 1 | import { setComponentTemplate } from '@ember/component'; |
2 | 2 | import { getOwner } from '@ember/application'; |
3 | | -import { compileTemplate } from '@ember/template-compilation'; |
4 | 3 | import { importSync } from '@embroider/macros'; |
5 | 4 | import Component from '@glimmer/component'; |
| 5 | +import { createTemplateFactory } from '@ember/template-factory'; |
| 6 | +const { getTemplateLocals } = importSync('@glimmer/syntax'); |
| 7 | +const { precompileJSON } = importSync('@glimmer/compiler'); |
6 | 8 |
|
7 | 9 | let templateOwnerMap = new Map(); |
8 | 10 |
|
@@ -30,11 +32,15 @@ export default class DynamicTemplateComponent extends Component { |
30 | 32 | if (component === undefined) { |
31 | 33 | let compiledTemplate; |
32 | 34 | try { |
33 | | - compiledTemplate = compileTemplate(templateString); |
| 35 | + compiledTemplate = compileTemplate(templateString, { |
| 36 | + moduleName: this.args.componentId, |
| 37 | + }); |
34 | 38 | } catch (err) { |
35 | 39 | console.error(err); |
36 | 40 | console.error(templateString); |
37 | | - compiledTemplate = compileTemplate(`<DynamicTemplateError />`); |
| 41 | + compiledTemplate = compileTemplate(`<DynamicTemplateError />`, { |
| 42 | + moduleName: this.args.componentId, |
| 43 | + }); |
38 | 44 | } |
39 | 45 |
|
40 | 46 | component = owner.factoryFor(`component:${this.args.componentId}`); |
@@ -66,3 +72,46 @@ export default class DynamicTemplateComponent extends Component { |
66 | 72 | return component; |
67 | 73 | } |
68 | 74 | } |
| 75 | + |
| 76 | +// copied from https://github.com/NullVoxPopuli/limber/blob/main/packages/ember-repl/addon/src/compile/formats/hbs.ts |
| 77 | +function compileTemplate(source, { moduleName, scope = {} }) { |
| 78 | + let localScope = { ...scope }; |
| 79 | + let locals = getTemplateLocals(source); |
| 80 | + |
| 81 | + let options = { |
| 82 | + strictMode: true, |
| 83 | + moduleName, |
| 84 | + locals, |
| 85 | + isProduction: false, |
| 86 | + meta: { moduleName }, |
| 87 | + }; |
| 88 | + |
| 89 | + // Copied from @glimmer/compiler/lib/compiler#precompile |
| 90 | + let [block, usedLocals] = precompileJSON(source, options); |
| 91 | + |
| 92 | + let usedScope = usedLocals.map((key) => { |
| 93 | + let value = localScope[key]; |
| 94 | + |
| 95 | + if (!value) { |
| 96 | + throw new Error( |
| 97 | + `Attempt to use ${key} in compiled hbs, but it was not available in scope. ` + |
| 98 | + `Available scope includes: ${Object.keys(localScope)}`, |
| 99 | + ); |
| 100 | + } |
| 101 | + |
| 102 | + return value; |
| 103 | + }); |
| 104 | + |
| 105 | + let blockJSON = JSON.stringify(block); |
| 106 | + let templateJSONObject = { |
| 107 | + id: moduleName, |
| 108 | + block: blockJSON, |
| 109 | + moduleName: moduleName ?? '(dynamically compiled component)', |
| 110 | + scope: () => usedScope, |
| 111 | + isStrictMode: true, |
| 112 | + }; |
| 113 | + |
| 114 | + let factory = createTemplateFactory(templateJSONObject); |
| 115 | + |
| 116 | + return factory; |
| 117 | +} |
0 commit comments