embroider-build / embroider

Compiling Ember apps into spec-compliant, modern Javascript.
MIT License
329 stars 137 forks source link

Compile Hbs route templates correctly #1856

Closed BlueCutOfficial closed 1 month ago

BlueCutOfficial commented 1 month ago

Relates to #1776

Problem In main branch, any hbs that is not colocated with its js is compiled as a template-only component. This behavior breaks the possibility for addons to provide hbs templates that are not components, like route templates.

Solution This PR introduces the possibility of specifying in config the hbs files that should not be compiled as template-only components.

Two different layers transform the standalone .hbs in the codebase into a template-only component .js in the addon build: the Rollup plugin rollup-hbs-plugin and the Babel plugin template-colocation-plugin. As Rollup config and Babel config are currently not shared, the glob patterns that prevent this compilation from happening will have to be specified for both tools.

In the rollup.config.mjs of the v2 addon:

// Ensure that standalone .hbs files are properly integrated as Javascript.
- addon.hbs(),
+ addon.hbs({
+  excludeColocation: ['templates/**/*'] // all files in the templates folder are not colocated components
+ })

In the babel.config.json of the v2 addon:

"plugins": [
- "@embroider/addon-dev/template-colocation-plugin",
+ ["@embroider/addon-dev/template-colocation-plugin", {
+   exclude: ['templates/**/*'] 
+ }],
],

Required refactorings Helpers that are not provided by the addon itself need to be explicitly imported.

For instance, let's assume your v1 addon used to have a dependency to ember-root-url and the helper was called in a hbs route template:

<img src={{root-url "images/hello.png"}} />

You'll be able to build the v2 addon, but when starting the app you'll run into Attempted to resolve 'root-url', which was expected to be a component or helper, but nothing was found.

To get rid of the error, one solution is to import the helper into the route controller so it's passed down to the template through the context:

import Controller from '@ember/controller';
import rootUrl from 'ember-root-url/helpers/root-url';

export default class ApplicationController extends Controller {
  rootUrl = rootUrl;
}
<img src={{this.root-url "images/hello.png"}} />

(This example doesn't apply to built-in helpers like the {{component}} helper, the hbs route template your v2 addon provides can use such a helper and it will continue to work with your classic Ember app.)