Load Ember-addons on demand from main application

Yes, embroider can lazily load components (with their whole subgraph of dependencies).

The caveat is that Ember itself doesn’t yet offer a convenient way to invoke a component that you just imported. Like, this doesn’t work:

import Component from '@glimmer/component';
import SomeComponent from './some-component';
export default class extends Component {
  constructor() {
    super();
    this.SomeComponent = SomeComponent;
  }
}
<this.SomeComponent/>

So even though embroider lets you do this and all the code will load correctly:

import Component from '@glimmer/component';
export default class extends Component {
  @action
  loadSomeComponent() {
    this.SomeComponent = await import('./some-component');
  }
}
{{#if this.SomeComponent}}
  <this.SomeComponent/>
{{/if}}

Ember won’t be able to invoke the component, because you’ve imported the component class which is not the same thing as the component definition.

This is likely to get fixed in Ember itself, because lots of people want this kind of pattern to work and it’s basically a requirement for things like strict mode rfc and sfc and template imports rfc.

But until then, it can be worked around something like:

@action
loadComponent() {
  let component = await import('./the-lazy-component');
  this.componentName = 'whatever-name-you-want';
  define(`my-app/components/${this.componentName}`, await import('./the-lazy-component'));
  // if you aren't using template colocation, you would also need to
  // load and define the template separately. So probably 
  // just use template  colocation because that's simpler
}
{{#if this.componentName}}
  {{component this.componentName}}
{{/if}}
5 Likes