Skip to content

Commit 808cba4

Browse files
committed
Add note about component names in blueprint
1 parent 028f3be commit 808cba4

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

text/0779-first-class-component-templates.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,58 @@ The current blueprints support generating a backing class for any existing compo
642642

643643
2. Reimplement the blueprint using an AST transform (which we have prior art for: route generation uses that approach), to add a backing class for an existing default export in the module.
644644

645-
We should take (1) here as a default starting point, while encouraging the community to implement (2) if interested.
645+
(We should take (1) here as a default starting point, while encouraging the community to implement (2) if interested.)
646+
647+
We should also update the name of the class generated for a component class. The default behavior of today's blueprint when generating a component is to suffix the class name with `Component`. Thus, running `ember generate component greeting --component-class=@glimmer/component` will produce a class named `GreetingComponent`.[^ts-component-name]
648+
649+
There was room for debate about whether this made sense for naming component classes up till now, since the invocation name was based on the file name (using Ember's resolution rules) and *not* the class name. Now, though, it *will* be based on the imported name, and the standard behavior of auto-import tooling is to import classes by their full name—whether the item is a named export or a default export. When a user goes to autocomplete `Greeting` (e.g. in [Glint][glint]), they will end up with `GreetingComponent`, leading to this sort of thing if they don’t rename it:
650+
651+
```js
652+
import GreetingComponent from './greeting';
653+
654+
<template>
655+
<GreetingComponent @name={{@user.name}} />
656+
</template>
657+
```
658+
659+
This is obviously undesirable, but avoiding this will mean mean renaming locally after the autocomplete works. That renaming operation is needless papercut in the best case of importing a default export. It rises to the level of a significant annoyance when using named imports:
660+
661+
```js
662+
import {
663+
ButtonComponent as UIButton,
664+
FormComponent as UIForm,
665+
InputComponent as UIInput,
666+
} from './ui';
667+
668+
<template>
669+
<UIForm @onSubmit={{@saveName}}>
670+
<UIInput @label="Name" @value={{@name}} @onUpdate={{@updateName}} />
671+
<UIButton @label="Save" type="submit" />
672+
</UIForm>
673+
</template>
674+
```
675+
676+
And it makes namespace-style imports basically unusable: to invoke *without* `Component` everywhere, you have to rebind all the imports you use!
677+
678+
```js
679+
import * as _UI from './ui';
680+
const UI = {
681+
Form: _UI.FormComponent,
682+
Button: _UI.ButtonComponent,
683+
Input: _UI.InputComponent
684+
}
685+
686+
<template>
687+
<UI.Form @onSubmit={{@saveName}}>
688+
<UI.Input @label="Name" @value={{@name}} @onUpdate={{@updateName}} />
689+
<UI.Button @label="Save" type="submit" />
690+
</UI.Form>
691+
</template>
692+
```
693+
694+
Accordingly, we should switch to generating *without* a class name: `ember generate component greeting --component-class=@glimmer/component` should produce a class named `Greeting`, *not* `GreetingComponent`. The generated names for routes, services, and controllers can remain as they are, since they are never invoked this way.
695+
696+
[^ts-component-name]: In TypeScript, this also extends to `GreetingComponentArgs` (or, with [RFC #0748][rfc-0748], something like `GreetingComponentSignature`), which gets *really* unwieldy!
646697

647698

648699
#### Linting and formatting

0 commit comments

Comments
 (0)