Introducing Template Imports!

Chris Hewell Garrett

@pzuraq

Agenda

2

3

What do they look like?

How do they work?

1

What are template imports?

<MyComponent/>

{{some-helper}}

<div {{a-modifier}}>

</div>
import MyComponent from './my-component';
import someHelper from '../helpers/some-helper';
import aModifier from '../modifiers/a-modifier';
  • Better DX, integration with editors and tooling
  • More flexible file layout
  • Better for bundling and build tools
  • Simplifies internals, better performance

Benefits

Agenda

2

3

What do they look like?

How do they work?

1

What are template imports?

---
import MyComponent from './my-component';
import someHelper from './some-helper';
import aModifier from './a-modifier';
---

<MyComponent/>

{{someHelper @arg1 @arg2}}

<div {{aModifier}}>

</div>
<script>
  import MyComponent from './my-component';
  import someHelper from './some-helper';
  import aModifier from './a-modifier';
<script>
<template>
  <MyComponent/>

  {{someHelper @arg1 @arg2}}

  <div {{aModifier}}>
  
  </div>
</template>
import { hbs } from 'ember-cli-htmlbars';
import MyComponent from './my-component';
import someHelper from './some-helper';
import aModifier from './a-modifier';

export default hbs`
  <MyComponent/>

  {{someHelper @arg1 @arg2}}

  <div {{aModifier}}>
  
  </div>
`;

Ship a low level API instead!

import { precompileTemplate } from '@ember/template-compilation';
import MyComponent from './my-component';
import someHelper from './some-helper';
import aModifier from './a-modifier';

export default precompileTemplate(
  `
    <MyComponent/>

    {{someHelper @arg1 @arg2}}

    <div {{aModifier}}>
  
    </div>
  `,
  {
    strictMode: true,
    scope: { MyComponent, someHelper, aModifier } 
  }
);

Available in Ember 3.25+

Shared community addon

$ ember install ember-template-imports

PRs welcome!

Agenda

2

3

What do they look like?

How do they work?

1

What are template imports?

// hello.js
import { hbs } from 'ember-template-imports';

export default hbs`
  Hello, world!
`;
// hello.gjs

<template>
  Hello, world!
</template>

Basic template-only component

// hello.js
import { hbs } from 'ember-template-imports';
import Greeting from './greeting';
import currentTime from './current-time';

export default hbs`
  <Greeting @name={{@name}}/>!

  It is currently {{currentTime}}.
`;
// hello.gjs
import Greeting from './greeting';
import currentTime from './current-time';

<template>
  <Greeting @name={{@name}}/>!

  It is currently {{currentTime}}.
</template>

Using imported values

// hello.js
import { hbs } from 'ember-template-imports';
import { helper } from '@ember/component/helper';
import moment from 'moment';

const Greeting = hbs`
  Hello, {{@name}}!
`

const currentTime = helper(() => {
  return moment().format('h:mm:ss a');
});

export default hbs`
  <Greeting @name={{@name}}/>

  It is currently {{currentTime}}.
`;
// hello.gjs
import { helper } from '@ember/component/helper';
import moment from 'moment';

const Greeting = <template>
  Hello, {{@name}}!
</template>

const currentTime = helper(() => {
  return moment().format('h:mm:ss a');
});

<template>
  <Greeting @name={{@name}}/>!

  It is currently {{currentTime}}.
</template>

Defining values in the same file

// hello.js
import { hbs } from 'ember-template-imports';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';

export default class Hello extends Component {
  @tracked name = 'Tomster';
  
  static template = hbs`
    hello, {{this.name}}!
  `;
}
// hello.gjs
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';

export default class Hello extends Component {
  @tracked name = 'Tomster';
  
  <template>
    hello, {{this.name}}!
  </template>
}

Adding state

Thank you!