Can addons use template-only components?

Came across another question related to Octane and addons: Assuming the addon only supports ember >= 3.15 could it use template-only components without requiring template-only-glimmer-components feature to be enabled on consuming application?

Or should it add an empty glimmer component to prevent a wrapper div if that optional feature is disabled? If so: Does this have any performance impact?

And assuming that’s the case: Did someone already wrote an addon that adds the boilerplate classes at build-time only if needed?

1 Like

Locks pointed me to the RFC which covers that question: https://emberjs.github.io/rfcs/0481-component-templates-co-location.html#template-only-components

Currently, the only way to create a “true” template-only component is by enabling an optional feature in the app. Since addons cannot assume the value of that flag in the consuming app, they currently cannot take advantage of the feature. By providing this function, addon authors can work around this problem by explicitly defining a JavaScript file with templateOnlyComponent() as the default export.

3 Likes

does that mean that instead of writting the addon/components/x-foo/index.js component file with

import Component from "@glimmer/component";
export default class XFooComponent extends Component {}

an addon author could do

import templateOnly from '@ember/component/template-only';
export default templateOnly();

If so, I don’t really see what’s to gain. But I feel like there is something I am missing here

If I got it right there is a performance difference between a template-only component and one with a class.

Thx @jelhan :+1:

Anyone from the core teams could confirm this and maybe give some metrics?

Under the hood, there are three typical cases for what kind of Class backs your component: EmberComponent, GlimmerComponent, and TemplateOnlyComponent.

One of the biggest differences between them is that EmberComponent adds a wrapping div around your actual template, whereas both GlimmerComponent and TemplateOnlyComponent do not.

The biggest difference between GlimmerComponent and TemplateOnlyComponent is that TemplateOnlyComponent has no {{this}}, and is cheaper to render because the rendering engine knows to entirely skip the instantiation of the backing class a runtime.

The name TemplateOnlyComponent can be misleading, because it has long been possible to make a template without a JS file, and people think of these as “template-only components”, but traditionally those always still got an EmberComponent class automatically generated for them. The first time that changed was the introduction of the template-only-glimmer-components optional feature.

That feature flag affects an entire app, and causes hbs files without js files to get backed by TemplateOnlyComponent instead of EmberComponent. It’s an easy feature to enable, because a codemod can just generate actual EmberComponent files for you before flipping the flag, so your existing components don’t suddenly change.

But addons can’t rely on that flag, which was the original context of this thread.

However, as of Ember Octane (3.15 and newer), there is a straightforward way for any app or addon to make template-only components that are backed by actual TemplateOnlyComponent. The key is that Octane added template co-location, which now allows hbs files directly inside app/components and addon/components, as opposed to needing to put them in app/templates/components and addon/templates/components. Since there’s no legacy behavior in these paths, those hbs files will always get backed by TemplateOnlyComponent (unless of course you add a corresponding JS files, and then you’re choosing EmberComponent or GlimmerComponent explicitly).

4 Likes

Thank you for the detailed answser @ef4 :+1: