Hello. I am currently in the process of upgrading an Ember app from 3.16 to 3.24 and am hitting a wall. The goal is to immediately go to 3.28, but that requires updating a bunch of add ons and switching to ember-auto-import 2, webpack, etc… but if a better path is 3.16 → 3.28 for the issue described below let me know.
My Problem
The way our app works is that users can sign up for searchable “integrations”, they can subscribe and unsubscribe to these on the fly. Then when they enter a search term, the server returns results based on the subscribed-to integrations.
Each integration supplies the client with an Ember component (JS and template). This is done through an integation-loader service. For example the wikipedia integration:
// wikipedia.js
'use strict';
polarity.export = PolarityComponent.extend({
details: Ember.computed.alias('block.data.details')
});
and a template:
<h1 class="p-title">{{fa-icon "search" fixedWidth=true}} Search Result</h1>
<div>
<span class="p-key">Article: </span>
<span class="p-value"><a class="p-link" href="{{details.match.link}}">{{details.match.label}} {{fa-icon "external-link" class="external-link-icon"}}</a></span>
</div>
{{#if (gt details.relatedList.length 0)}}
<h1 class="p-title">{{fa-icon "link" fixedWidth=true}} Related Wikipedia Articles</h1>
<ul class="link-list">
{{#each details.relatedList as |item|}}
<li><a class="p-link" href="{{item.link}}">{{item.label}}</a></li>
{{/each}}
</ul>
{{/if}}
This template is compiled on the server and sent to the client in the “wire” format.
{
"id": "5sJCSUQF",
"block": "{\"symbols\":[\"item\"],\"statements\":[[7,\"h1\",true.............,
"meta": {}
}
The server @ember-source matches the client @ember-source, so the wire format is 3.16 for 3.16 and 3.24 for 3.24.
Our current implementation uses createTemplateFactory
like so:
app.register('component:/wikipedia', evaluatedJS);
app.register('template:/wikipedia', createTemplateFactory(compiled));
In Ember 3.16 the createTemplateFactory uses this function (via @ember/-internals/glimmer/index):
var TEMPLATE_COMPILER_MAIN = (0, _container.privatize)`template-compiler:main`;
function template(json) {
var glimmerFactory = (0, _opcodeCompiler.templateFactory)(json);
var cache = new WeakMap();
var factory = owner => {
var result = cache.get(owner);
if (result === undefined) {
counters.cacheMiss++;
var compiler = owner.lookup(TEMPLATE_COMPILER_MAIN);
result = glimmerFactory.create(compiler, {
owner
});
cache.set(owner, result);
} else {
counters.cacheHit++;
}
return result;
};
factory.__id = glimmerFactory.id;
factory.__meta = glimmerFactory.meta;
return factory;
}
This has changed to the following in 3.24 (via @glimmer/opcode-compiler)
function templateFactory({
id: templateId,
moduleName,
block
}) {
// TODO(template-refactors): This should be removed in the near future, as it
// appears that id is unused. It is currently kept for backwards compat reasons.
var id = templateId || `client-${clientId++}`; // TODO: This caches JSON serialized output once in case a template is
// compiled by multiple owners, but we haven't verified if this is actually
// helpful. We should benchmark this in the future.
var parsedBlock;
var ownerlessTemplate = null;
var templateCache = new WeakMap();
var factory = owner => {
if (parsedBlock === undefined) {
parsedBlock = JSON.parse(block);
}
if (owner === undefined) {
if (ownerlessTemplate === null) {
templateCacheCounters.cacheMiss++;
ownerlessTemplate = new TemplateImpl({
id,
block: parsedBlock,
moduleName,
owner: null
});
} else {
templateCacheCounters.cacheHit++;
}
return ownerlessTemplate;
}
var result = templateCache.get(owner);
if (result === undefined) {
templateCacheCounters.cacheMiss++;
result = new TemplateImpl({
id,
block: parsedBlock,
moduleName,
owner
});
templateCache.set(owner, result);
} else {
templateCacheCounters.cacheHit++;
}
return result;
};
factory.__id = id;
factory.__meta = {
moduleName
};
return factory;
}
So now I am receiving the error:
Error occurred:
- While rendering:
-top-level
application
integrations/wikipedia
I have tried using the following babel plugins:
babel-plugin-htmlbars-inline-precompile
babel-plugin-ember-template-compilation
But have not had much luck. These seem to be focused on the hbs
functionality and when using the compile
function, I am greeted with Ember.HTMLbars.compile
is not a function. Also I do not want the configuration in my ember-cli-build.js to affect my build time templates only my runtime ones.
The server does also send the non-wire template. i.e:
// wikipedia.hbs
<h1 class="p-title">{{fa-icon "search" fixedWidth=true}} Search Result</h1>
<div>
<span class="p-key">Article: </span>
<span class="p-value"><a class="p-link" href="{{details.match.link}}">{{details.match.label}} {{fa-icon "external-link" class="external-link-icon"}}</a></span>
</div>
{{#if (gt details.relatedList.length 0)}}
<h1 class="p-title">{{fa-icon "link" fixedWidth=true}} Related Wikipedia Articles</h1>
<ul class="link-list">
{{#each details.relatedList as |item|}}
<li><a class="p-link" href="{{item.link}}">{{item.label}}</a></li>
{{/each}}
</ul>
{{/if}}
and if I just call hbs(the above code)
it works, but hbs(${stringPlaceholder})
does not work and has been documented to not be possible which is unfortunate.
My Question What can I use to register a template either in hbs or wire format at runtime post Ember 3.16?
More specifically what can I pass as the second argument to the app.register( )
function for a template at runtime?