Skip to content

Commit bfaf9c7

Browse files
committed
Wip, Implement experiment for: emberjs/rfcs#905
1 parent f6000af commit bfaf9c7

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed

.changeset/hip-fishes-agree.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
"ember-resources": minor
3+
---
4+
5+
Add link() and @link
6+
7+
<details><summary>Example property usage</summary>
8+
9+
```js
10+
import { link } from 'ember-resources/link';
11+
12+
class MyClass { ... }
13+
14+
export default class Demo extends Component {
15+
// This usage does now allow passing args to `MyClass`
16+
@link(MyClass) myInstance;
17+
}
18+
```
19+
20+
</details>
21+
22+
<details><summary>Example inline usage</summary>
23+
24+
```js
25+
import Component from '@glimmer/component';
26+
import { cached } from '@glimmer/tracking';
27+
import { link } from 'ember-resources/link';
28+
29+
export default class Demo extends Component {
30+
// To pass args to `MyClass`, you must use this form
31+
// NOTE though, that `instance` is linked to the `Demo`s lifecycle.
32+
// So if @foo is changing frequently, memory pressure will increase rapidly
33+
// until the `Demo` instance is destroyed.
34+
//
35+
// Resources are a better fit for this use case, as they won't add to memory pressure.
36+
@cached
37+
get myFunction() {
38+
let instance = new MyClass(this.args.foo);
39+
40+
return link(instance, this);
41+
}
42+
}
43+
```
44+
45+
</details>
46+
47+
48+
This abstracts away the following boilerplate:
49+
```js
50+
import { getOwner, setOwner } from '@ember/owner';
51+
import { associateDestroyableChild } from '@ember/destroyable';
52+
53+
class MyClass { /* ... */ }
54+
55+
export default class Demo extends Component {
56+
@cached
57+
get myInstance() {
58+
let instance = new MyClass();
59+
60+
associateDestroyableChild(this, instance);
61+
62+
let owner = getOwner(this);
63+
64+
if (owner) {
65+
setOwner(instance, owner);
66+
}
67+
68+
return instance;
69+
}
70+
}
71+
```
72+

ember-resources/src/util/link.ts

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { getOwner, setOwner } from "@ember/application";
2+
import { assert } from "@ember/debug";
3+
import { associateDestroyableChild } from "@ember/destroyable";
4+
5+
/**
6+
* A util to abstract away the boilerplate of linking of "things" with an owner
7+
* and making them destroyable.
8+
*
9+
*
10+
* Example as a class property:
11+
* ```js
12+
* import { link } from 'ember-resources/link';
13+
*
14+
* class MyClass { ... }
15+
*
16+
* export default class Demo extends Component {
17+
* @link(MyClass) myInstance;
18+
* }
19+
* ```
20+
*
21+
* Example inline usage:
22+
* ```js
23+
* import Component from '@glimmer/component';
24+
* import { cached } from '@glimmer/tracking';
25+
* import { link } from 'ember-resources/link';
26+
*
27+
* export default class Demo extends Component {
28+
* @cached
29+
* get myFunction() {
30+
* let instance = new MyClass(this.args.foo);
31+
*
32+
* return link(instance, this);
33+
* }
34+
* }
35+
* ```
36+
*/
37+
function link(_prototype: object, key: string, descriptor?: Descriptor): void {
38+
if (!descriptor) return;
39+
40+
assert(`@link can only be used with string-keys`, typeof key === 'string');
41+
42+
43+
let { initializer } = descriptor;
44+
45+
assert(
46+
`@link may only be used on initialized properties. For example, ` +
47+
`\`@link foo = new MyClass();\``,
48+
initializer
49+
);
50+
51+
52+
let caches = new WeakMap<object, any>();
53+
54+
// https://github.com/pzuraq/ember-could-get-used-to-this/blob/master/addon/index.js
55+
return {
56+
get(this: object) {
57+
let child = caches.get(this);
58+
59+
if (!child) {
60+
child = initializer.call(this);
61+
62+
associateDestroyableChild(this, child);
63+
64+
let owner = getOwner(this);
65+
66+
if (owner) {
67+
setOwner(child, owner);
68+
}
69+
70+
caches.set(this, child);
71+
assert(`Failed to create cache for internal resource configuration object`, child);
72+
}
73+
74+
return child;
75+
},
76+
} as unknown as void /* Thanks TS. */;
77+
}

0 commit comments

Comments
 (0)