From d9b283732d9d58b49f1f0511a4ef392fbc701534 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:18:15 -0400 Subject: [PATCH 1/5] Create 0000-add-helper-manager-for-service.md --- text/0000-add-helper-manager-for-service.md | 198 ++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 text/0000-add-helper-manager-for-service.md diff --git a/text/0000-add-helper-manager-for-service.md b/text/0000-add-helper-manager-for-service.md new file mode 100644 index 0000000000..07bfc8f552 --- /dev/null +++ b/text/0000-add-helper-manager-for-service.md @@ -0,0 +1,198 @@ +--- +stage: accepted +start-date: 2025-06-15T00:00:00.000Z # In format YYYY-MM-DDT00:00:00.000Z +release-date: # In format YYYY-MM-DDT00:00:00.000Z +release-versions: +teams: + - framework + - typescript +prs: + accepted: # Fill this in with the URL for the Proposal RFC PR +project-link: +suite: +--- + + +# Service Helper Manager + +## Summary + +Add helper manager capabilities to `@ember/service`'s `service` export, enabling direct template usage while maintaining backward compatibility with existing service injection patterns. + +## Motivation + +Current service access in templates requires unnecessary boilerplate: + +```js +import Component from '@glimmer/component'; +import { service } from '@ember/service'; + +export default class extends Component { + @service theme; + + // Boilerplate just to expose the service + get exposedTheme() { + return this.theme; + } +} +``` + +```hbs +{{this.exposedTheme.toggle}} +``` + +With helper manager capabilities, eliminate the boilerplate: + +```gjs +import Component from '@glimmer/component'; +import { service } from '@ember/service'; + + + +export default class extends Component {} +``` + +## Detailed design + +### Enhanced `service` Export + +The `service` export gains helper manager capabilities while preserving existing patterns: + +```js +// All existing usage unchanged +@service theme; +@service('user-preferences') prefs; +theme = service('theme'); +``` + +```gjs +// New template helper usage + +``` + +### Implementation + +```js +class ServiceHelperManager { + createHelper(state, { positional: [serviceName] }) { + return { service: getOwner(state).lookup(`service:${serviceName}`) }; + } + + getValue({ service }) { + return service; + } +} +``` + +### Template-only Components + +Perfect for template-only components: + +```gjs + +``` + +### Common Patterns + +```gjs + +``` + +### TypeScript Support + +Full type inference: + +```gts + +``` + +## How we teach this + +### Mental Model + +"Service gets you a service" - consistent whether in classes or templates. Template usage follows standard Handlebars patterns with `{{#let}}` for method calls. + +### Documentation + +Update `@ember/service` docs with template examples. Add Guides section on "Services in Templates" emphasizing the `{{#let}}` pattern for method calls. + +## Drawbacks + +- **API Surface**: Another way to access services +- **Template Verbosity**: `{{#let}}` adds nesting for method calls + +## Alternatives + +Keep requiring backing class injection. Maintains separation but creates boilerplate. + +This leads to utilities like [service in reactiveweb](https://reactive.nullvoxpopuli.com/functions/resource_service.service.html) + +## Unresolved questions + +- Error handling for missing services? + - Would be more doable if we had try/catch in templates +- Build-time vs runtime service validation? + - forbid dynamic service names? From d819f83af75f652a0f942611faa50dfc26a9aa9d Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:19:14 -0400 Subject: [PATCH 2/5] Update and rename 0000-add-helper-manager-for-service.md to 1118-add-helper-manager-for-service.md --- ...er-for-service.md => 1118-add-helper-manager-for-service.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-add-helper-manager-for-service.md => 1118-add-helper-manager-for-service.md} (98%) diff --git a/text/0000-add-helper-manager-for-service.md b/text/1118-add-helper-manager-for-service.md similarity index 98% rename from text/0000-add-helper-manager-for-service.md rename to text/1118-add-helper-manager-for-service.md index 07bfc8f552..453cf51b18 100644 --- a/text/0000-add-helper-manager-for-service.md +++ b/text/1118-add-helper-manager-for-service.md @@ -7,7 +7,7 @@ teams: - framework - typescript prs: - accepted: # Fill this in with the URL for the Proposal RFC PR + accepted: https://github.com/emberjs/rfcs/pull/1118 project-link: suite: --- From 61e1a2b50019d0f7be803e3d77bbc2246543bef5 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 23 Jun 2025 16:03:24 -0400 Subject: [PATCH 3/5] Apply suggestions from code review --- text/1118-add-helper-manager-for-service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/1118-add-helper-manager-for-service.md b/text/1118-add-helper-manager-for-service.md index 453cf51b18..c5c483d16a 100644 --- a/text/1118-add-helper-manager-for-service.md +++ b/text/1118-add-helper-manager-for-service.md @@ -102,7 +102,7 @@ theme = service('theme'); {{/let}} {{! Property access }} -
+
Content here
From 936b557d370ac38cb37ff9ff597e5cb9b3ec7a6f Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:41:16 -0400 Subject: [PATCH 4/5] Update 1118-add-helper-manager-for-service.md --- text/1118-add-helper-manager-for-service.md | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/text/1118-add-helper-manager-for-service.md b/text/1118-add-helper-manager-for-service.md index c5c483d16a..2fae265498 100644 --- a/text/1118-add-helper-manager-for-service.md +++ b/text/1118-add-helper-manager-for-service.md @@ -75,13 +75,17 @@ export default class extends Component {} The `service` export gains helper manager capabilities while preserving existing patterns: ```js -// All existing usage unchanged -@service theme; -@service('user-preferences') prefs; -theme = service('theme'); +class { + // All existing usage unchanged + @service theme; + @service('user-preferences') prefs; + theme = service('theme'); +} ``` ```gjs +import { service } from '@ember/service'; + // New template helper usage