From 632b999e9cee7edab022b7d726d7a3685a872495 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 10:28:07 -0400 Subject: [PATCH 01/17] Add a section for using vanilla classes with dependency injection --- guides/release/services/index.md | 131 +++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index e9daa7e421..8fcdf59bf4 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -140,3 +140,134 @@ Note `cart` being used below to get data from the cart. ``` + +### Accessing services from native classes + +[api-ember-owner]: https://api.emberjs.com/ember/release/modules/@ember%2Fowner +[api-getOwner]: https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/getOwner +[api-setOwner]: https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/setOWner +[api-cached]: https://api.emberjs.com/ember/5.3/functions/@glimmer%2Ftracking/cached + +if you want to access a service from a plain JavaScript class, you'll need to get a reference to the "[owner][api-ember-owner]" object, which is responsible for managing services. + +First, we can define a classs that accesses services as described above + +```javascript {data-filename=app/components/cart-content/vanilla-class.js} +import { getOwner } from '@ember/owner'; +import { service } from '@ember/service'; + +export class VanillaClass { + @service shoppingCart; + + someMethod() { + // Now you can use the service + this.shoppingCart.add(/* ... */); + } +} +``` + +but to wire up `VanillaClass` to work with `@service`, you'll need to implement a ceramony: + +```javascript {data-filename=app/components/cart-content/index.js} +import { VanillaClass } from './vanilla-class'; + +export default class CartContentsComponent extends Component { + @cached + get vanillaClass() { + let instance = new VanillaClass(); + + setOwner(instance, getOwner(this)); + + return instance; + } +} +``` + +In reality, this could be any framework-construct: a service, route, controller, etc -- in this case we use a component, but this could also be done in another vanilla class that's already be wired up. +The pattern here is to use a [`@cached`][api-cached] getter to ensure a stable reference[^stable-reference] to the class, and then using [`setOwner`][api-setOwner] and [`getOwner`][api-getOwner], we finish the wiring ceramony needed to make native classes work with services. + +[^stable-reference]: note that a stable reference in this situation means that when the property is accessed multiple times the same reference is returned. Without the `@cached` decorator, a new `VanillaClass` would be instatiated upon each access of the getter. + +The exact way in which the wiring ceramony is done is up to you, but it often depends on what is needed, and community libraries may abstract away all of these if they wish. + +#### With arguments + +If your native class needs arguments, we can change the above example to instantiate the class like this: + +```javascript {data-filename=app/components/cart-content/index.js} +import { VanillaClass } from './vanilla-class'; + +export default class CartContentsComponent extends Component { + @cached + get vanillaClass() { + let instance = new VanillaClass(this.args.foo); + + setOwner(instance, getOwner(this)); + + return instance; + } +} +``` + +and then back in the `VanillaClass` itself, you must store the value somewhere, via the constructor: + +```javascript {data-filename=app/components/cart-content/vanilla-class.js} +import { getOwner } from '@ember/owner'; +import { service } from '@ember/service'; + +export class VanillaClass { + @service shoppingCart; + + constructor(foo) { + this.foo = foo; + } + + /* ... */ +} +``` + +In this situation, when the component's `@foo` argument changes (accessed in js via `this.args.foo`), a new `VanillaClass` will be instiantiated and wired up if it was accessed. + +#### Reactive arguments + +Sometimes you'll want `@tracked` state to retain its reactivity when passing to a native class, so for that you'll need to use an anonymous arrow function. + + +```javascript {data-filename=app/components/cart-content/index.js} +import { VanillaClass } from './vanilla-class'; + +export default class CartContentsComponent extends Component { + @cached + get vanillaClass() { + let instance = new VanillaClass(() => this.args.foo); + + setOwner(instance, getOwner(this)); + + return instance; + } +} +``` + +and then back in the `VanillaClass` itself, you must store the value somewhere and possibly provide yourself an easy way to access the value: + +```javascript {data-filename=app/components/cart-content/vanilla-class.js} +import { getOwner } from '@ember/owner'; +import { service } from '@ember/service'; + +export class VanillaClass { + @service shoppingCart; + + constructor(fooFunction) { + this.fooFunction = fooFunction; + } + + get foo() { + return this.fooFunction(); + } + + /* ... */ +} +``` + +With this technique, the tracked data provided by `this.arg.foo` is lazily evaluated in `VanillaClass`, allowing the `VanillaClass` to participate in lazy evaluation and auto-tracking like everywherer else you may be used to in an app. + From 018f09e9a5b96fa9a3ae72464f1a220f720288ca Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 11:07:50 -0400 Subject: [PATCH 02/17] Address remark issues --- guides/release/services/index.md | 38 +++++++++++++++++++------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 8fcdf59bf4..0b7f06c600 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -143,14 +143,9 @@ Note `cart` being used below to get data from the cart. ### Accessing services from native classes -[api-ember-owner]: https://api.emberjs.com/ember/release/modules/@ember%2Fowner -[api-getOwner]: https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/getOwner -[api-setOwner]: https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/setOWner -[api-cached]: https://api.emberjs.com/ember/5.3/functions/@glimmer%2Ftracking/cached +If you want to access a service from a plain JavaScript class, you'll need to get a reference to the "[owner](https://api.emberjs.com/ember/release/modules/@ember%2Fowner)" object, which is responsible for managing services. -if you want to access a service from a plain JavaScript class, you'll need to get a reference to the "[owner][api-ember-owner]" object, which is responsible for managing services. - -First, we can define a classs that accesses services as described above +First, we can define a class that accesses services as described above ```javascript {data-filename=app/components/cart-content/vanilla-class.js} import { getOwner } from '@ember/owner'; @@ -166,7 +161,7 @@ export class VanillaClass { } ``` -but to wire up `VanillaClass` to work with `@service`, you'll need to implement a ceramony: +And then to wire up `VanillaClass` to work with `@service`, you'll need to implement a ceremony: ```javascript {data-filename=app/components/cart-content/index.js} import { VanillaClass } from './vanilla-class'; @@ -184,11 +179,24 @@ export default class CartContentsComponent extends Component { ``` In reality, this could be any framework-construct: a service, route, controller, etc -- in this case we use a component, but this could also be done in another vanilla class that's already be wired up. -The pattern here is to use a [`@cached`][api-cached] getter to ensure a stable reference[^stable-reference] to the class, and then using [`setOwner`][api-setOwner] and [`getOwner`][api-getOwner], we finish the wiring ceramony needed to make native classes work with services. +The pattern here is to use a [`@cached`](https://api.emberjs.com/ember/5.3/functions/@glimmer%2Ftracking/cached) getter to ensure a stable reference to the class, and then using [`setOwner`]( https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/setOwner) and [`getOwner`](https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/getOwner), we finish the wiring ceremony needed to make native classes work with services. + + +
+
+
+
Zoey says...
+
+ +Note that a stable reference in this situation means that when the property is accessed multiple times the same reference is returned. Without the `@cached` decorator, a new `VanillaClass` would be instantiated upon each access of the getter. -[^stable-reference]: note that a stable reference in this situation means that when the property is accessed multiple times the same reference is returned. Without the `@cached` decorator, a new `VanillaClass` would be instatiated upon each access of the getter. +
+
+ +
+
-The exact way in which the wiring ceramony is done is up to you, but it often depends on what is needed, and community libraries may abstract away all of these if they wish. +The exact way in which the wiring ceremony is done is up to you, but it often depends on what is needed, and community libraries may abstract away all of these if they wish. #### With arguments @@ -209,7 +217,7 @@ export default class CartContentsComponent extends Component { } ``` -and then back in the `VanillaClass` itself, you must store the value somewhere, via the constructor: +Back in the `VanillaClass` itself, you must store the value somewhere, via the constructor: ```javascript {data-filename=app/components/cart-content/vanilla-class.js} import { getOwner } from '@ember/owner'; @@ -226,7 +234,7 @@ export class VanillaClass { } ``` -In this situation, when the component's `@foo` argument changes (accessed in js via `this.args.foo`), a new `VanillaClass` will be instiantiated and wired up if it was accessed. +In this situation, when the component's `@foo` argument changes (accessed in JavaScript via `this.args.foo`), a new `VanillaClass` will be instantiated and wired up if it was accessed. #### Reactive arguments @@ -248,7 +256,7 @@ export default class CartContentsComponent extends Component { } ``` -and then back in the `VanillaClass` itself, you must store the value somewhere and possibly provide yourself an easy way to access the value: +Back in the `VanillaClass` itself, you must store the value somewhere and possibly provide yourself an easy way to access the value: ```javascript {data-filename=app/components/cart-content/vanilla-class.js} import { getOwner } from '@ember/owner'; @@ -269,5 +277,5 @@ export class VanillaClass { } ``` -With this technique, the tracked data provided by `this.arg.foo` is lazily evaluated in `VanillaClass`, allowing the `VanillaClass` to participate in lazy evaluation and auto-tracking like everywherer else you may be used to in an app. +With this technique, the tracked data provided by `this.arg.foo` is lazily evaluated in `VanillaClass`, allowing the `VanillaClass` to participate in lazy evaluation and auto-tracking like every where else you may be used to in an app. From 1d1a0032dbe205df51802143f9bcbb6a1593067f Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:00:42 -0400 Subject: [PATCH 03/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 0b7f06c600..48fd12a2fa 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -242,6 +242,8 @@ Sometimes you'll want `@tracked` state to retain its reactivity when passing to ```javascript {data-filename=app/components/cart-content/index.js} +import { setOwner, getOwner } from '@ember/owner'; + import { VanillaClass } from './vanilla-class'; export default class CartContentsComponent extends Component { From 8108309414479283665a5bec8a101f05f934f815 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:00:56 -0400 Subject: [PATCH 04/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 48fd12a2fa..131bd15a17 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -145,7 +145,7 @@ Note `cart` being used below to get data from the cart. If you want to access a service from a plain JavaScript class, you'll need to get a reference to the "[owner](https://api.emberjs.com/ember/release/modules/@ember%2Fowner)" object, which is responsible for managing services. -First, we can define a class that accesses services as described above +First, we can define a class that accesses services as described above: ```javascript {data-filename=app/components/cart-content/vanilla-class.js} import { getOwner } from '@ember/owner'; From f6d6e5a897d90fedb6decff011cf09757c262fea Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:01:18 -0400 Subject: [PATCH 05/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 131bd15a17..6132965752 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -169,7 +169,7 @@ import { VanillaClass } from './vanilla-class'; export default class CartContentsComponent extends Component { @cached get vanillaClass() { - let instance = new VanillaClass(); + const instance = new VanillaClass(); setOwner(instance, getOwner(this)); From ad978298eaee47a496f3fd4c4e08729be9aa3953 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:01:35 -0400 Subject: [PATCH 06/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 6132965752..14876c9ac7 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -203,6 +203,8 @@ The exact way in which the wiring ceremony is done is up to you, but it often de If your native class needs arguments, we can change the above example to instantiate the class like this: ```javascript {data-filename=app/components/cart-content/index.js} +import { setOwner, getOwner } from '@ember/owner'; + import { VanillaClass } from './vanilla-class'; export default class CartContentsComponent extends Component { From ea5d37ac0d721540796751207819b82c8dd30086 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:01:45 -0400 Subject: [PATCH 07/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 14876c9ac7..d42179b5b6 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -210,7 +210,7 @@ import { VanillaClass } from './vanilla-class'; export default class CartContentsComponent extends Component { @cached get vanillaClass() { - let instance = new VanillaClass(this.args.foo); + const instance = new VanillaClass(this.args.foo); setOwner(instance, getOwner(this)); From 986f9200ee2fdf0fe776120df3ddb023a64c4c24 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:02:16 -0400 Subject: [PATCH 08/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index d42179b5b6..b809706ddb 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -251,7 +251,7 @@ import { VanillaClass } from './vanilla-class'; export default class CartContentsComponent extends Component { @cached get vanillaClass() { - let instance = new VanillaClass(() => this.args.foo); + const instance = new VanillaClass(() => this.args.foo); setOwner(instance, getOwner(this)); From 4f6bd049ba71d36f9e1cd1adb4bb6f5b48afc32b Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:02:42 -0400 Subject: [PATCH 09/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index b809706ddb..ea1d7bbde5 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -263,7 +263,6 @@ export default class CartContentsComponent extends Component { Back in the `VanillaClass` itself, you must store the value somewhere and possibly provide yourself an easy way to access the value: ```javascript {data-filename=app/components/cart-content/vanilla-class.js} -import { getOwner } from '@ember/owner'; import { service } from '@ember/service'; export class VanillaClass { From d408c3eb40ad5d4bbbd03e7febb6a5a08927757b Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:42:12 -0400 Subject: [PATCH 10/17] Update guides/release/services/index.md Co-authored-by: Krystan HuffMenne --- guides/release/services/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index ea1d7bbde5..30ffc7b792 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -148,7 +148,6 @@ If you want to access a service from a plain JavaScript class, you'll need to ge First, we can define a class that accesses services as described above: ```javascript {data-filename=app/components/cart-content/vanilla-class.js} -import { getOwner } from '@ember/owner'; import { service } from '@ember/service'; export class VanillaClass { From 9a7114938b4f8fe19dc4b6b03c7910510f72b10d Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:42:23 -0400 Subject: [PATCH 11/17] Update guides/release/services/index.md Co-authored-by: Krystan HuffMenne --- guides/release/services/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 30ffc7b792..9d859b6d15 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -163,6 +163,7 @@ export class VanillaClass { And then to wire up `VanillaClass` to work with `@service`, you'll need to implement a ceremony: ```javascript {data-filename=app/components/cart-content/index.js} +import { getOwner, setOwner } from '@ember/owner'; import { VanillaClass } from './vanilla-class'; export default class CartContentsComponent extends Component { From d010687e917230931f4d088d8d85b4976b7362a5 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:44:07 -0400 Subject: [PATCH 12/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 9d859b6d15..d60397ad01 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -162,7 +162,7 @@ export class VanillaClass { And then to wire up `VanillaClass` to work with `@service`, you'll need to implement a ceremony: -```javascript {data-filename=app/components/cart-content/index.js} +```javascript {data-filename=app/components/cart-contents/index.js} import { getOwner, setOwner } from '@ember/owner'; import { VanillaClass } from './vanilla-class'; From afaf5f08f35f1234b7d066879dc244c05f295028 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:44:22 -0400 Subject: [PATCH 13/17] Update guides/release/services/index.md --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index d60397ad01..66ef588ccd 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -147,7 +147,7 @@ If you want to access a service from a plain JavaScript class, you'll need to ge First, we can define a class that accesses services as described above: -```javascript {data-filename=app/components/cart-content/vanilla-class.js} +```javascript {data-filename=app/components/cart-contents/vanilla-class.js} import { service } from '@ember/service'; export class VanillaClass { From b85246655760d78d6e62c00565290d94efc35961 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:44:30 -0400 Subject: [PATCH 14/17] Update guides/release/services/index.md Co-authored-by: Lukas Nys --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 66ef588ccd..ceb9ff2416 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -202,7 +202,7 @@ The exact way in which the wiring ceremony is done is up to you, but it often de If your native class needs arguments, we can change the above example to instantiate the class like this: -```javascript {data-filename=app/components/cart-content/index.js} +```javascript {data-filename=app/components/cart-contents/index.js} import { setOwner, getOwner } from '@ember/owner'; import { VanillaClass } from './vanilla-class'; From 6a20bf7951ba04e646d68fc336dd91b9eb41ed38 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:44:48 -0400 Subject: [PATCH 15/17] Update guides/release/services/index.md --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index ceb9ff2416..0fbbb7931c 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -221,7 +221,7 @@ export default class CartContentsComponent extends Component { Back in the `VanillaClass` itself, you must store the value somewhere, via the constructor: -```javascript {data-filename=app/components/cart-content/vanilla-class.js} +```javascript {data-filename=app/components/cart-contents/vanilla-class.js} import { getOwner } from '@ember/owner'; import { service } from '@ember/service'; From c773137429448b5311543aebebc719a1cc1a5f00 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:45:07 -0400 Subject: [PATCH 16/17] Update guides/release/services/index.md --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 0fbbb7931c..247c4dd0a2 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -243,7 +243,7 @@ In this situation, when the component's `@foo` argument changes (accessed in Jav Sometimes you'll want `@tracked` state to retain its reactivity when passing to a native class, so for that you'll need to use an anonymous arrow function. -```javascript {data-filename=app/components/cart-content/index.js} +```javascript {data-filename=app/components/cart-contents/index.js} import { setOwner, getOwner } from '@ember/owner'; import { VanillaClass } from './vanilla-class'; From 5a1ee2eef7da1f88e355c0772351fb90d97c8dfd Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:45:24 -0400 Subject: [PATCH 17/17] Update guides/release/services/index.md --- guides/release/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/release/services/index.md b/guides/release/services/index.md index 247c4dd0a2..404dae0d35 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -262,7 +262,7 @@ export default class CartContentsComponent extends Component { Back in the `VanillaClass` itself, you must store the value somewhere and possibly provide yourself an easy way to access the value: -```javascript {data-filename=app/components/cart-content/vanilla-class.js} +```javascript {data-filename=app/components/cart-contents/vanilla-class.js} import { service } from '@ember/service'; export class VanillaClass {