ember-resources-codemod 0.1.0 (minor) ember-resources 7.0.3 (patch)
ember-resources-codemod
,test-app
- #1147 Add v6 to v7 codemod (@NullVoxPopuli)
ember-resources
,test-app-definitely-typed
,test-app
- #1158 Cleaning (@NullVoxPopuli)
- Ozy Wu-Li (@ozywuli)
- @NullVoxPopuli
- @johanrd
ember-resources 7.0.2 (patch)
ember-resources
,test-app
- #1135 Fix issue where, in some situations, the immediate-invoker helper manager (used when you use
resourceFactory
) was not correctly destroying the previous instance of a resource (such as when args change)) (@NullVoxPopuli)
- #1135 Fix issue where, in some situations, the immediate-invoker helper manager (used when you use
ember-resources 7.0.1 (patch)
ember-resources
,test-app
- #1129 Fix use types (@NullVoxPopuli)
- #1115 Update migrations for 7.0 (@NullVoxPopuli)
- #1130 Update release-plan (@NullVoxPopuli)
ember-resources 7.0.0 (major)
ember-resources
,test-app
- #1101 Require an owner to exist to be wired through to the resource. (@NullVoxPopuli)
- #1087 Remove modifier (@NullVoxPopuli)
- #1085 Remove link (@NullVoxPopuli)
- #1082 Remove class-based Resource (@NullVoxPopuli)
test-app
- #1100 Require ember-cli-app-consumers have at least ember-cli-babel 8.2 (@NullVoxPopuli)
ember-resources
- #1090 Remove the 'core' import, only allowing importing from 'ember-resources' (@NullVoxPopuli)
@nullvoxpopuli/estimate-bytes
,docs
,ember-resources
,test-app
- #1083 Remove service (@NullVoxPopuli)
docs
,ember-resources
,test-app
- #1080 Drop all of the util imports (@NullVoxPopuli)
@nullvoxpopuli/estimate-bytes
,docs
,ember-resources
,test-app
- #1097 Infra modernization, support both built in types from ember-source, as well as the types from DefinitelyTyped (@NullVoxPopuli)
- Other
- #1099 Test against (and add support for) TypeScript 5.3 (@NullVoxPopuli)
ember-resources
- #1096 Drop unused dependencies and widen peers further (@NullVoxPopuli)
test-app
- #1095 Support ember-source 5.4 (@NullVoxPopuli)
- #1089 Ensure every supported version of Ember has no deprecations triggered from ember-resources' usage. (@NullVoxPopuli)
@nullvoxpopuli/estimate-bytes
,ember-resources
,test-app
- #1091 Implement custom usables,
regusterUsable
(@NullVoxPopuli)
- #1091 Implement custom usables,
ember-resources
,test-app
- #1101 Require an owner to exist to be wired through to the resource. (@NullVoxPopuli)
docs
,ember-resources
- #1107 Move recommendation of resourceFactory to better align with how TypeScript works (@NullVoxPopuli)
- Other
- #1103 Remove class-based resource documentation (@NullVoxPopuli)
- #1102 Fix API Reference docs by moving from Cloudflare to Vercel (@NullVoxPopuli)
- #1079 Add link to the v6 branch (@NullVoxPopuli)
docs
- #1086 Remove API Reference docs' sidebar (@NullVoxPopuli)
@nullvoxpopuli/estimate-bytes
,docs
- #1084 Remove utils from API Reference docs (typedoc) (@NullVoxPopuli)
- Other
- #1106 Use fix for release-plan from: embroider-build/github-changelog#8 (@NullVoxPopuli)
- #1099 Test against (and add support for) TypeScript 5.3 (@NullVoxPopuli)
test-app
- #1104 Remove MSW (@NullVoxPopuli)
- #1088 Remove deprecation testing app that was added in v6 (@NullVoxPopuli)
ember-resources
- #1098 Remove unused type utils (@NullVoxPopuli)
ember-resources 6.5.0 (minor)
ember-resources
- #1076 Deprecate and move service and modifier to reactiveweb (@NullVoxPopuli)
- #1077 Deprecate the class-based Resource, moved to ember-modify-based-class-resource (@NullVoxPopuli)
- #1070 [v6]: Deprecate util/* imports (@NullVoxPopuli)
ember-resources
- #1078 Update deprecation links (@NullVoxPopuli)
test-app
- #1074 [v6]: Ensure that the available API for v7 does not throw deprecations (@NullVoxPopuli)
ember-resources 6.4.3 (patch)
ember-resources
,test-app
ember-resources
test-app
- #1069 Eslint plugin ember alpha v12 testing (@NullVoxPopuli)
- Other
- #1062 Setup release plan (@NullVoxPopuli)
- Peter Wagenet (@wagenet)
- Yelin Zhang (@Yelinz)
- @NullVoxPopuli
- @johanrd
-
#1019
d63d7b7
Thanks @wagenet! - ThekeepLatest
utility previously incorrectly had a| undefined
type for the return value. That's been removed.| undefined
is still a valid type if the passed value is possibly| undefined
. This made the| undefined
onkeepLatest
redundant.
-
#1011
606ba4b
Thanks @NullVoxPopuli! -trackedFunction
: Fix timing issue where updating tracked data consumed intrackedFunction
would not re-cause theisLoading
state to becometrue
again.Resolves #1010
-
#975
1a964f1
Thanks @NullVoxPopuli! -trackedFunction
can now be composed just like regular resources.The function body still auto-tracks and will update within consuming resource appropriately.
Example
const Person = resourceFactory((maybeIdFn) => { return resource(({ use }) => { let request = use( trackedFunction(async () => { let id = typeof maybeIdFn === "function" ? maybeIdFn() : maybeIdFn; let response = await fetch(`https://api.github.com/users/${id}`); return response.json(); }), ); // `use` returns a ReadonlyCell where `.current` // is the State of trackedFunction. return () => request.current; }); });
Usage examples:
<template> {{#let (Person 1) as |request|}} {{#if request.isLoading}} ... loading ... {{/if}} {{#if request.value}} {{/if}} {{/let}} </template>
An async doubler
const Doubled = resourceFactory((num: number) => { return resource(({ use }) => { let doubler = use(trackedFunction(async () => num * 2)); // Since current is the "State" of `trackedFunction`, // accessing .value on it means that the overall value of // `Doubled` is the eventual return value of the `trackedFunction` return () => doubler.current.value; }); }); // Actual code from a test class State { @tracked num = 2; } let state = new State(); setOwner(state, this.owner); await render(<template><out>{{Doubled state.num}}</out></template>);
Example with arguments
Imagine you want to compute the hypotenuse of a triangle, but all calculations are asynchronous (maybe the measurements exist on external APIs or something).
// Actual code from a test type NumberThunk = () => number; const Sqrt = resourceFactory((numFn: NumberThunk) => trackedFunction(async () => { let num = numFn(); return Math.sqrt(num); }), ); const Squared = resourceFactory((numFn: NumberThunk) => trackedFunction(async () => { let num = numFn(); return Math.pow(num, 2); }), ); const Hypotenuse = resourceFactory((aFn: NumberThunk, bFn: NumberThunk) => { return resource(({ use }) => { const aSquared = use(Squared(aFn)); const bSquared = use(Squared(bFn)); const c = use( Sqrt(() => { return (aSquared.current.value ?? 0) + (bSquared.current.value ?? 0); }), ); // We use the function return because we want this property chain // to be what's lazily evaluated -- in this example, since // we want to return the hypotenuse, we don't (atm) // care about loading / error state, etc. // In real apps, you might care about loading state though! return () => c.current.value; // In situations where you care about forwarding other states, // you could do this return { get value() { return c.current.value; }, get isLoading() { return ( a.current.isLoading || b.current.isLoading || c.current.isLoading ); }, }; }); });
-
#960
77d54e6
Thanks @NullVoxPopuli! - Resolves: #958use
d Resources can now be immediately returned from other resources.const Clock = resource(({ use }) => { return use(Instant({ intervalMs: 1000 }); }); const Stopwatch = resource(({ use }) => { return use(Instant({ intervalMs: 0 }); }); <template> <time>{{Clock}}</time> MS since Epoch: {{Stopwatch}} </template>
-
#952
1551b33
Thanks @NullVoxPopuli! - Introduce resources as modifiers. This brings alignment with Starbeam's plans for modifiers as a universal primitive.In ember-resources, using modifiers as resources looks like this:
import { resource } from 'ember-resources'; import { modifier } from 'ember-resources/modifier'; const wiggle = modifier((element, arg1, arg2, namedArgs) => { return resource(({ on }) => { let animation = element.animate([ { transform: `translateX(${arg1}px)` }, { transform: `translateX(-${arg2}px)` }, ], { duration: 100, iterations: Infinity, }); on.cleanup(() => animation.cancel()); }); }); <template> <div {{wiggle 2 5 named="hello"}}>hello</div> </template>
The signature for the modifier here is different from
ember-modifier
, where positional args and named args are grouped together into an array and object respectively.This signature for ember-resource's
modifier
follows the plain function invocation signature.in Starbeam
import { resource } from '@starbeam/universal'; function wiggle(element, arg1, arg2, namedArgs) { return resource(({ on }) => { let animation = element.animate([ { transform: `translateX(${arg1}px)` }, { transform: `translateX(-${arg2}px)` }, ], { duration: 100, iterations: Infinity, }); on.cleanup(() => animation.cancel()); }); } <template> <div {{wiggle 2 5 named="hello"}}>hello</div> </template>
- #947
16b844e
Thanks @NullVoxPopuli! - Update in-editor docs on the function resource
-
#941
bfc432b
Thanks @NullVoxPopuli! - Fix an issue with a new (not yet used feature) where Resources could directly return aCell
, and it would have its.current
method automatically called when resolving the value of a Resource.import { resource, cell } from 'ember-resources'; export const Now = resource(({ on }) => { const now = cell(Date.now()); const timer = setInterval(() => now.set(Date.now())); on.cleanup(() => clearInterval(timer)); return now; }); <template> It is: <time>{{Now}}</time> </template>
-
#936
6246a3c
Thanks @NullVoxPopuli! - Theuse
import fromember-resources
now supports an alternate style of usage. This is partly to provide consistency across the different kinds of resources (and resource builders), whether or not arguments are provided.The motivation from this change comes from trying to better align with Starbeam's composition capabilities, and "define something once, use it anywhere" approach to that composition.
For example, before, only this was possible:
import { resource, use } from "ember-resources"; const StuckClock = resource(() => 2); class MyClass { @use data = StuckClock; } new MyClass().data === 2;
That looks a little awkward, because it looks like
data
is set to a constant. InTypeScript
, this still worked out, and the type ofdata
would be anumber
, but it still didn't look intuitive.Now, we can do this:
import { resource, use } from "ember-resources"; const StuckClock = resource(() => 2); class MyClass { data = use(this, StuckClock); } new MyClass().data.current === 2;
The key difference here is that
data
is now aReactive<number>
, which, like acell
, has a.current
property. This is a readonly value -- howevercurrent
can still return a mutable data structure.This style of
use
ends up extending nicely to Resources that take arguments:import { tracked } from "@glimmer/tracking"; import { resource, use, resourceFactory } from "ember-resources"; const Clock = resourceFactory((locale) => resource(/* ... */)); class MyClass { @tracked locale = "en-US"; data = use( this, Clock(() => this.locale), ); }
Note
The old way of using@use
as a decorator is still supported, and has no plans of being deprecated.Another approach
I can't recommend this approach for general usage, but it is supported under SemVer (for exploration and feedback).
import { resource, use } from "ember-resources"; const StuckClock = resource(() => 2); class MyClass { @use(StuckClock) declare data: number; } new MyClass().data === 2;
This should feel familiar as it looks like what we're familiar with when it comes to declaring
@tracked
properties as well as@service
s.However, this has the same problems as
@service
-- in TypeScript, it requires you to usedeclare
and specify a type, which may or may not match the actual type ofStuckClock
.Additionally, whenever we want to pass arguments to the resource, like this:
import { tracked } from '@glimmer/tracking'; import { resource, use } from 'ember-resources'; const Clock = resourceFactory((locale) => resource( /* ... */); class MyClass { @tracked locale = 'en-US'; @use(Clock(() => this.locale) declare data: number; }
The arrow function passed to
Clock
would not have the correct this. This is confusing, because in every other situation where we use classes, the arrow function has the same context as the instance of the class. But due to how decorators are configured / transpiled, thethis
is actually the surrounding context aroundMyClass
, because decorators are statically applied.class MyClass { @tracked locale = 'en-US'; @use(Clock( static context here, not instance ) declare data: number; }
So... that's why I want to recommend
property = use(this, Foo)
by default.class MyClass { @tracked locale = 'en-US'; data = use(this, (Clock( instance access )); }
-
#925
e320cf8
Thanks @NullVoxPopuli! - Fix situation where, when composing with blueprint/factory-creted Resources, the owner was not passed to the tused
d resource.Example from the added testconst Now = resourceFactory((ms = 1000) => resource(({ on }) => { let now = cell(nowDate); let timer = setInterval(() => now.set(Date.now()), ms); on.cleanup(() => clearInterval(timer)); return () => now.current; }) ); const Stopwatch = resourceFactory((ms = 500) => resource(({ use }) => { let time = use(Now(ms)); return () => format(time); }) ); await render(<template><time>{{Stopwatch 250}}</time></template>);
The owner is part of the hooks API for
resource
and an error is thrown when it is undefined - regardless if used.const Demo = resource(({ on, use, owner }) => { // ... });
-
#866
e1e4f66
Thanks @NullVoxPopuli! - Add the ability to compose function resources. This is enabled only for function resources as class-based resources could already compose.how function resources compose
let formatter = new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "numeric", second: "numeric", hour12: false, }); let format = (time) => formatter.format(time.current); // representing the current time. // This could be rendered directly as {{Now}} // but Date does not serialize nicely for humans (Date.now() is a number) const Now = resource(({ on }) => { let now = cell(Date.now()); let timer = setInterval(() => now.set(Date.now()), 1000); on.cleanup(() => clearInterval(timer)); return () => now.current; }); const Clock = resource(({ use }) => { let time = use(Now); return () => format(time); }); // Rendered, Clock is always the formatted time <template> <time>{{ Clock }}</time> </template>;
- #829
ff776b1
Thanks @NullVoxPopuli! - Move ember-async-data to "dependencies" because users are not required to import from that package ever"
-
#715
e8155b2
Thanks @NullVoxPopuli! - Drop support for TypeScript < 4.8 in order to support Glint. -
#778
901ae9a
Thanks @NullVoxPopuli! - Themap
utility resource has changed its first type-argument for better inference.The utility already supported inference, so this change should not impact too many folks.
Migration and Reasoning
When explicit type-arguments were specified,
class Demo { // previously a = map<Element>(this, { data: () => [ /* ... list of Element(s) ... */ ], map: (element) => { /* some transform */ }, }); // now a = map<Element[]>(this, { data: () => [ /* ... list of Element(s) ... */ ], map: (element) => { /* some transform */ }, }); }
This is advantageous, because with
@tsconfig/ember
, the optionnoUncheckedIndexedAccess
is enabled by default. This is a great strictness / quality option to have enabled, as arrays in javascript are mutable, and we can't guarantee that they don't change between index-accesses.However the
map
utility resource explicitly disallows the indicies to get out of sync with the sourcedata
.But!, with
noUncheckedIndexedAccess
, you can only infer so much before TS goes the safe route, and makes the returned typeX | undefined
.For example, in these type-tests:
import { map } from "ember-resources/util/map"; import { expectType } from "ts-expect"; const constArray = [1, 2, 3]; b = map(this, { data: () => constArray, map: (element) => { expectType<number>(element); return element; }, }); // index-access here is *safely* `| undefined`, due to `constArray` being mutable. expectType<number | undefined>(b[0]); expectType<number | undefined>(b.values()[0]); // but when we use a const as const array, we define a tuple, // and can correctly infer and return real values via index access const tupleArray = [1, 2, 3] as const; c = map(this, { data: () => tupleArray, map: (element) => { expectType<number>(element); return element; }, }); // No `| undefined` here expectType<number>(c[0]); expectType<number>(c.values()[0]);
-
#815
54e2b50
Thanks @NullVoxPopuli! - TheRemoteData
resource now has the same state changes and semantics astrackedFunction
.Breaking Changes:
isResolved
is only true when the request succeeds. During migration, you may useisFinished
for previous behavior.
-
#779
a471d9b
Thanks @NullVoxPopuli! -trackedFunction
has a new API and thus a major version release is required.Work by @lolmaus
tl;dr: the breaking changes:
- no more manual initial value
isResolved
is only true on success
other changes:
trackedFunction
is a wrapper aroundember-async-data
'sTrackedAsyncData
ember-async-data
will need to be installed in the consumer's app to continue usingtrackedFunction
This keeps installs minimal for folks using ember-resources and are not usingtrackedFunction
- behavior is otherwise the same
NOTE:
trackedFunction
is an example utility of how to use auto-tracking with function invocation, and abstract away the various states involved with async behavior. Now that the heavy lifting is done byember-async-data
,trackedFunction
is now more of an example of how to integrated existing tracked utilities in to resources.Migration
Previously, the state's
isResolved
property ontrackedFunction
wastrue
on both success and error.now,
isFinished
can be used instead.isResolved
is now only true when the function runs to completion without error, aligning with the semantics of promises.class Demo { foo = trackedFunction(this, async () => { /* ... */ }); <template> {{this.foo.isFinished}} = {{this.foo.isResolved}} or {{this.foo.isError}} </template> }
Previously,
trackedFunction
could take an initial value for its second argument.class Demo { foo = trackedFunction(this, "initial value", async () => { /* ... */ }); }
This has been removed, as initial value can be better maintained and made more explicit in user-space. For example:
class Demo { foo = trackedFunction(this, async () => { /* ... */ }); get value() { return this.foo.value ?? "initial value"; } }
Or, in a template:
Or, in gjs/strict mode:
const withDefault = (value) => value ?? 'initial value'; class Demo extends Component { foo = trackedFunction(this, async () => { /* ... */ }); <template> {{withDefault this.foo.value}} </template> }
-
#785
66cee0e
Thanks @NullVoxPopuli! - The import pathember-resources/util/function-resource
has been removed, as all the relevent exports have been available fromember-resources
since v5.
-
#797
18adb86
Thanks @NullVoxPopuli! - Add link() and @link, importable fromember-resources/link
.NOTE: for existing users of
ember-resources
, this addition has no impact on your bundle.Example property usage
import { link } from 'ember-resources/link'; class MyClass { ... } export default class Demo extends Component { // This usage does now allow passing args to `MyClass` @link(MyClass) myInstance; }
Example inline usage
import Component from "@glimmer/component"; import { cached } from "@glimmer/tracking"; import { link } from "ember-resources/link"; export default class Demo extends Component { // To pass args to `MyClass`, you must use this form // NOTE though, that `instance` is linked to the `Demo`s lifecycle. // So if @foo is changing frequently, memory pressure will increase rapidly // until the `Demo` instance is destroyed. // // Resources are a better fit for this use case, as they won't add to memory pressure. @cached get myFunction() { let instance = new MyClass(this.args.foo); return link(instance, this); } }
This abstracts away the following boilerplate:
import { getOwner, setOwner } from "@ember/owner"; import { associateDestroyableChild } from "@ember/destroyable"; class MyClass { /* ... */ } export default class Demo extends Component { @cached get myInstance() { let instance = new MyClass(); associateDestroyableChild(this, instance); let owner = getOwner(this); if (owner) { setOwner(instance, owner); } return instance; } }
-
#778
f841a98
Thanks @NullVoxPopuli! - Use strictest possible settings with TypeScript so that consumers can't be stricter than this library -
#776
a99793e
Thanks @NullVoxPopuli! - Glint is now supported starting with 1.0.0-beta.3 -
#818
feeb2db
Thanks @NullVoxPopuli! - RemoteData now checks the response's Content-Type header to decide whether to convert to JSON or Text -
#794
8989bbb
Thanks @NullVoxPopuli! - New Utils: UpdateFrequency and FrameRateNOTE: for existing users of
ember-resources
, this addition has no impact on your bundle.FrameRate
Utility that uses requestAnimationFrame to report how many frames per second the current monitor is rendering at.
The result is rounded to two decimal places.
import { FramRate } from "ember-resources/util/fps"; <template>{{ FrameRate }}</template>;
UpdateFrequency
Utility that will report the frequency of updates to tracked data.
import { UpdateFrequency } from 'ember-resources/util/fps'; export default class Demo extends Component { @tracked someProp; @use updateFrequency = UpdateFrequency(() => this.someProp); <template> {{this.updateFrequency}} </template> }
NOTE: the function passed to UpdateFrequency may not set tracked data.
-
#769
abaad4a
Thanks @GreatWizard! - fix typo in map error message when checking if every datum is an object -
#828
24b540e
Thanks @NullVoxPopuli! - ember-async-data@v1 is out, so since we're just now using it, that can be the minimum version. NOTE:ember-async-data
's minimum ember-source is 4.8, so while things might work with earlier ember-source's it's not guaranteed. -
#826
50ad1ba
Thanks @NullVoxPopuli! - When using RemoteData, isError should be true when the http status code is >= 400. Resolves #825". Previously, when you had a JSON response with 404 status code,isError
would be false instead of true. -
#865
6df54b1
Thanks @NullVoxPopuli! - Add the last v4 LTS, ember-source v4.12, to the test matrix -
#806
00e8f2f
Thanks @sergey-zhidkov! -trackedTask
must return correct last value.Fixes the issue described at #793 If the task was called multiple times and the last returned value was null or undefined, then trackedTask will return the previous value instead of the current one.
-
#838
acbf03d
Thanks @NullVoxPopuli! - Fixes #835 - resolves regression introduced by PR: #808 which aimed to correctly return the previous task instance's value if the current task hasn't finished yet. The regression described by #835 was that if a task in cancelled (e.g.: dropped), it is considered finished, and that canceled task's value would be used instead of the last compuleted task. In normal ember-concurrency APIs, this is abstracted over via the.lastSuccessful
property on theTaskProperty
. The goal of the.value
ontrackedTask
is to mimic the property chain:taskProperty.lastSuccessful?.value
. -
#830
0767c08
Thanks @NullVoxPopuli! - Support TS 5.0 -
#868
b6f78c9
Thanks @NullVoxPopuli! - Test against ember-concurrency@v3, and add it as an allowed peerDepnedency
- #838
acbf03d
Thanks @NullVoxPopuli! - Fixes #835 - resolves regression introduced by PR: #808 which aimed to correctly return the previous task instance's value if the current task hasn't finished yet. The regression described by #835 was that if a task in cancelled (e.g.: dropped), it is considered finished, and that canceled task's value would be used instead of the last compuleted task. In normal ember-concurrency APIs, this is abstracted over via the.lastSuccessful
property on theTaskProperty
. The goal of the.value
ontrackedTask
is to mimic the property chain:taskProperty.lastSuccessful?.value
.
-
#828
24b540e
Thanks @NullVoxPopuli! - ember-async-data@v1 is out, so since we're just now using it, that can be the minimum version. NOTE:ember-async-data
's minimum ember-source is 4.8, so while things might work with earlier ember-source's it's not guaranteed. -
#826
50ad1ba
Thanks @NullVoxPopuli! - When using RemoteData, isError should be true when the http status code is >= 400. Resolves #825". Previously, when you had a JSON response with 404 status code,isError
would be false instead of true. -
#830
0767c08
Thanks @NullVoxPopuli! - Support TS 5.0
- #818
feeb2db
Thanks @NullVoxPopuli! - RemoteData now checks the response's Content-Type header to decide whether to convert to JSON or Text
-
#815
54e2b50
Thanks @NullVoxPopuli! - TheRemoteData
resource now has the same state changes and semantics astrackedFunction
.Breaking Changes:
isResolved
is only true when the request succeeds. During migration, you may useisFinished
for previous behavior.
-
#797
18adb86
Thanks @NullVoxPopuli! - Add link() and @link, importable fromember-resources/link
.NOTE: for existing users of
ember-resources
, this addition has no impact on your bundle.Example property usage
import { link } from 'ember-resources/link'; class MyClass { ... } export default class Demo extends Component { // This usage does now allow passing args to `MyClass` @link(MyClass) myInstance; }
Example inline usage
import Component from "@glimmer/component"; import { cached } from "@glimmer/tracking"; import { link } from "ember-resources/link"; export default class Demo extends Component { // To pass args to `MyClass`, you must use this form // NOTE though, that `instance` is linked to the `Demo`s lifecycle. // So if @foo is changing frequently, memory pressure will increase rapidly // until the `Demo` instance is destroyed. // // Resources are a better fit for this use case, as they won't add to memory pressure. @cached get myFunction() { let instance = new MyClass(this.args.foo); return link(instance, this); } }
This abstracts away the following boilerplate:
import { getOwner, setOwner } from "@ember/owner"; import { associateDestroyableChild } from "@ember/destroyable"; class MyClass { /* ... */ } export default class Demo extends Component { @cached get myInstance() { let instance = new MyClass(); associateDestroyableChild(this, instance); let owner = getOwner(this); if (owner) { setOwner(instance, owner); } return instance; } }
- #785
66cee0e
Thanks @NullVoxPopuli! - The import pathember-resources/util/function-resource
has been removed, as all the relevent exports have been available fromember-resources
since v5.
-
#794
8989bbb
Thanks @NullVoxPopuli! - New Utils: UpdateFrequency and FrameRateNOTE: for existing users of
ember-resources
, this addition has no impact on your bundle.FrameRate
Utility that uses requestAnimationFrame to report how many frames per second the current monitor is rendering at.
The result is rounded to two decimal places.
import { FramRate } from "ember-resources/util/fps"; <template>{{ FrameRate }}</template>;
UpdateFrequency
Utility that will report the frequency of updates to tracked data.
import { UpdateFrequency } from 'ember-resources/util/fps'; export default class Demo extends Component { @tracked someProp; @use updateFrequency = UpdateFrequency(() => this.someProp); <template> {{this.updateFrequency}} </template> }
NOTE: the function passed to UpdateFrequency may not set tracked data.
-
#806
00e8f2f
Thanks @sergey-zhidkov! -trackedTask
must return correct last value.Fixes the issue described at #793 If the task was called multiple times and the last returned value was null or undefined, then trackedTask will return the previous value instead of the current one.
-
#715
e8155b2
Thanks @NullVoxPopuli! - Drop support for TypeScript < 4.8 in order to support Glint. -
#778
901ae9a
Thanks @NullVoxPopuli! - Themap
utility resource has changed its first type-argument for better inference.The utility already supported inference, so this change should not impact too many folks.
Migration and Reasoning
When explicit type-arguments were specified,
class Demo { // previously a = map<Element>(this, { data: () => [ /* ... list of Element(s) ... */ ], map: (element) => { /* some transform */ }, }); // now a = map<Element[]>(this, { data: () => [ /* ... list of Element(s) ... */ ], map: (element) => { /* some transform */ }, }); }
This is advantageous, because with
@tsconfig/ember
, the optionnoUncheckedIndexedAccess
is enabled by default. This is a great strictness / quality option to have enabled, as arrays in javascript are mutable, and we can't guarantee that they don't change between index-accesses.However the
map
utility resource explicitly disallows the indicies to get out of sync with the sourcedata
.But!, with
noUncheckedIndexedAccess
, you can only infer so much before TS goes the safe route, and makes the returned typeX | undefined
.For example, in these type-tests:
import { map } from "ember-resources/util/map"; import { expectType } from "ts-expect"; const constArray = [1, 2, 3]; b = map(this, { data: () => constArray, map: (element) => { expectType<number>(element); return element; }, }); // index-access here is *safely* `| undefined`, due to `constArray` being mutable. expectType<number | undefined>(b[0]); expectType<number | undefined>(b.values()[0]); // but when we use a const as const array, we define a tuple, // and can correctly infer and return real values via index access const tupleArray = [1, 2, 3] as const; c = map(this, { data: () => tupleArray, map: (element) => { expectType<number>(element); return element; }, }); // No `| undefined` here expectType<number>(c[0]); expectType<number>(c.values()[0]);
-
#779
a471d9b
Thanks @NullVoxPopuli! -trackedFunction
has a new API and thus a major version release is required.Work by @lolmaus
tl;dr: the breaking changes:
- no more manual initial value
isResolved
is only true on success
other changes:
trackedFunction
is a wrapper aroundember-async-data
'sTrackedAsyncData
ember-async-data
will need to be installed in the consumer's app to continue usingtrackedFunction
This keeps installs minimal for folks using ember-resources and are not usingtrackedFunction
- behavior is otherwise the same
NOTE:
trackedFunction
is an example utility of how to use auto-tracking with function invocation, and abstract away the various states involved with async behavior. Now that the heavy lifting is done byember-async-data
,trackedFunction
is now more of an example of how to integrated existing tracked utilities in to resources.Migration
Previously, the state's
isResolved
property ontrackedFunction
wastrue
on both success and error.now,
isFinished
can be used instead.isResolved
is now only true when the function runs to completion without error, aligning with the semantics of promises.class Demo { foo = trackedFunction(this, async () => { /* ... */ }); <template> {{this.foo.isFinished}} = {{this.foo.isResolved}} or {{this.foo.isError}} </template> }
Previously,
trackedFunction
could take an initial value for its second argument.class Demo { foo = trackedFunction(this, "initial value", async () => { /* ... */ }); }
This has been removed, as initial value can be better maintained and made more explicit in user-space. For example:
class Demo { foo = trackedFunction(this, async () => { /* ... */ }); get value() { return this.foo.value ?? "initial value"; } }
Or, in a template:
Or, in gjs/strict mode:
const withDefault = (value) => value ?? 'initial value'; class Demo extends Component { foo = trackedFunction(this, async () => { /* ... */ }); <template> {{withDefault this.foo.value}} </template> }
-
#778
f841a98
Thanks @NullVoxPopuli! - Use strictest possible settings with TypeScript so that consumers can't be stricter than this library -
#776
a99793e
Thanks @NullVoxPopuli! - Glint is now supported starting with 1.0.0-beta.3
- #769
abaad4a
Thanks @GreatWizard! - fix typo in map error message when checking if every datum is an object
-
#742
dd7234a
Thanks @NullVoxPopuli! - When using theresourceFactory
(blueprint in Starbeam terms), there was an issue where a returnedresource
would not get torn down when the surrounding context of theresourceFactory
would get torn down.For example, in this situation, which has been added as the second example on this blog post,
const poll = resourceFactory((fn, interval) => { return resource(({ on }) => { let x = setInterval(fn, interval); on.cleanup(() => clearInterval(x)); }); });
usage would be:
So, when this was in an
if
statement, or in a component or route, or any content that could be torn down, theon.cleanup
callback would not be called.This fix addresses the issue and the
on.cleanup
callback is now called.NOTE: this approach to using resources is equivelent to this 0-dependency solution to polling:
import Component from "@glimmer/component"; import type RouterService from "@ember/routing/router-service"; import { helper } from "@ember/component/helper"; import { service } from "@ember/service"; const intervals = new WeakMap(); export default class Demo extends Component { @service declare router: RouterService; poll = helper(function ([fn, interval]: [(...args: unknown[]) => unknown, number]) { if (!intervals.has(this)) { registerDestructor(this, () => clearInterval(intervals.get(this))); } clearInterval(intervals.get(this); intervals.set(this, setInterval(fn, interval)); }); refreshData = () => this.router.refresh(); }
-
#684
bd723d1
Thanks @NullVoxPopuli! - Improve contribution resistance by removing semantic-release/commits and switching to Changesets for managing automatic release.The release automation and human intervention is just the right mix of both to make everything painless for all parties.
This means:
- contributors don't need to "adhere to the commit convention" - which was linted for and had no autofix
- a preview PR will be created so folks can see what all is going in to a release
- releases can be bundled, meaning not every commit going in to
main
needs to be releasable- this allows for simultaneous batches of breaking changes, and would have prevented some early churn in this package's history
- and most importantly, changelogs are meant for humans (not machines), and Changeset allows for human-focused changelogs
I'll be moving all of my addons to Changesets and away from semantic-release.
-
b137837
Thanks @NullVoxPopuli! - TypeScript 4.8 and 4.9 Support added
5.6.0 (2022-11-02)
- trackedFunction: add a retry method (8244049)
5.5.0 (2022-10-27)
- cell: add update method to Cell class (b0ce96c)
5.4.0 (2022-09-10)
- owner is now available to function-based resources (410bbf4)
5.3.2 (2022-09-08)
- Resource: class-based resource had no inference on the thunk (e3900f7)
5.3.1 (2022-08-31)
- util, keepLatest: improve isEmpty internal util logic (3b9d753)
5.3.0 (2022-08-28)
- strict-mode, gts: improve type support for glint + gts and strict mode (793a0f6)
- @use: now works with class-based resources (0803f1f)
5.2.2 (2022-08-27)
- cell: improve typings of the cell utility (5e3229d)
5.2.1 (2022-08-04)
- keepLatest: use consistent condition name (1f177cc)
5.2.0 (2022-08-04)
- new util -- keepLatest (3e3d02c)
5.1.1 (2022-07-30)
- resourceFactory: reactivity now works when args to a resource change (7c647ff)
5.1.0 (2022-07-29)
- util: add cell util (bad3c1e)
5.0.2 (2022-07-02)
- package: widen peer range for @glint/template (e98c906)
5.0.1 (2022-06-23)
- package: @glint/template can't be an 'optional' peerDependency - it is required (65b4600)
5.0.0 (2022-06-22)
- cleanup: remove deprecated code (d602bff)
- cleanup: remove support for ember-concurrency@v1 (33521be)
- package: glint support, minimum version requirements (f78c8b2)
- types, internal: add type tests, try to re-widen typescript range to bring back support for TS 4.5+ (bc33140)
- package: glint requires minimum versions to be bumped
- minimum ember is now
[email protected]
. This is LTS and the most feature complete version of the 3.x series. 3.24, the previous LTS, is no longer supported by the ember team and will not be receiving security patches. Since resources are a fairly new concept, and since Glint support is a priority, supporting earlier than 3.28 is not needed. - @glimmer/tracking must now be at least 1.1.2
- Additional peer dependencies
- @glint/template
- @glimmer/component
- ember-modifier
- @glint/template
Resource.of
has been removed. It was wholley redundant since.from
exists.Resource.from
is more concise and provides better type inference.
- cleanup: all code marked for removal in v4 (for v5) has been removed. See: https://github.com/NullVoxPopuli/ember-resources/blob/main/MIGRATIONS.md for more information
- cleanup: drop support for ember-concurrency@v1
- ember-concurrency (if using the tracked task) must now be at least v2
- ember-concurrency@v1 may still work, but any bug reports using ember-concurrency@v1 will be closed. ember-concurrency@v2 was released in February of 2021.
4.10.0 (2022-06-19)
- function-resource: support encapsulated tracked state (9800c14)
4.9.1 (2022-06-18)
- function-resource: lifecycle fixes (eb7c6b6)
4.9.0 (2022-06-11)
- util: add debounce example util (357e266)
4.8.2 (2022-05-21)
- Resource: fix an issue where certain usages would not entagle / update correctly (83a459c)
4.8.1 (2022-05-20)
- RemoteData, function-resource: wrapped template usage (3975e65)
4.8.0 (2022-05-14)
- add
remoteData
andRemoteData
utils (f613791)
4.7.1 (2022-05-01)
- add deprecations for the deprecated APIs (5b07081)
4.7.0 (2022-05-01)
- add trackedFunction and function-resource (3b6ebaf)
4.6.4 (2022-04-22)
- package, types: remove space in version field in typesVersion. Remove main entry (1b1b0ea)
4.6.3 (2022-04-21)
- docs, Resource: there is no second arg passed to the constructor of Resource (b21f386)
4.6.2 (2022-04-20)
- types: certain typescript scenarios need explicit typesVersions entries (1346b0e)
4.6.1 (2022-04-12)
- build: remove minification from built assets (3bb54c7)
4.6.0 (2022-04-10)
- bundle: minify built assets. core bundle is 827 bytes (34113ae)
4.5.0 (2022-04-09)
- docs: pin @types/eslint so docs can build (bc10593)
- Move @ember/test-waiters to peerDependencies (c6db46b)
- add replacement APIs under new import paths (0025d3b)
- docs, types: fix types with the map resource. update docs (4cce0c5)
4.5.0 (2022-04-09)
- docs: pin @types/eslint so docs can build (bc10593)
- Move @ember/test-waiters to peerDependencies (c6db46b)
- add replacement APIs under new import paths (0025d3b)
- docs, types: fix types with the map resource. update docs (4cce0c5)
4.4.0 (2022-02-24)
- add declaration maps (eff33e4)
4.3.5 (2022-02-24)
- types: export TaskInstance and TaskIsh for ts-consumers (96b8d64)
4.3.4 (2022-02-24)
@ember/test-waiters
must be a peer dependency (01866c7), closes /github.com/NullVoxPopuli/ember-resources/issues/403#issuecomment-1048404119
4.3.3 (2022-02-23)
- types field in package.json now correctly points at the new file (f3ab39c)
4.3.2 (2022-02-22)
- package: remove type:module for embroider compat (635404c)
4.3.1 (2022-02-05)
- useTask: provide better ember-concurrency@v1 support (eb7387e)
4.3.0 (2022-02-03)
- readme: async-data example (74e0682)
4.2.0 (2022-01-31)
4.1.3 (2021-12-21)
- deps: update dependency @embroider/addon-shim to v0.48.1 (b7342c4)
4.1.2 (2021-12-06)
- types: compat with TS 4.5.1 (88c9db9)
4.1.1 (2021-12-05)
- types: better ember-concurrency@v1 support in typescript (91c8b20)
4.1.0 (2021-12-05)
- add trackedFunction (4d7a89b)
4.0.1 (2021-11-06)
- useTask: re-test against ember-concurrency@v1 (0bf0122)
4.0.0 (2021-11-01)
- readme: declare ember-auto-import compatibility (2701891)
- readme: ember-auto-import compatibility was not declared.
If any projects that previously used ember-auto-import@1, this addon will no longer work for those projects until those projects upgrade to either ember-auto-import@v2 or embroider.
This breaking change is to communicate the accidental compatibility breaking with older projects. The last available version projects without ember-auto-import@v2 can use is v3.2.2.
I'm declaring this an accidental breakage soley because compatibility was not previosuly declared and any compatibliity with older projects may as well have been "accidental".
For projects that already were using ember-auto-import@v2, there is no breaking change. There is no behavioral difference in this addon's features.
However, embroider and ember-auto-import@v2 users will no longer have ember-resources count against their build times as V2 Addons are pre-built during publish.
If you have any questions, feel free to open an issue at: https://github.com/NullVoxPopuli/ember-resources/issues
3.2.4 (2021-11-01)
- internal: use correct config for the tooling lints (7e6e8a4)
3.2.3 (2021-10-31)
- readme: specify v2 format (3f6bb1b)
3.2.2 (2021-10-19)
- deps: update dependency ember-cli-htmlbars to v6 (07465ab)
3.2.1 (2021-09-05)
3.2.0 (2021-08-29)
- useFunction, typescript: you may now specify a return type without specifying the args type (fe0acff)
- readme: document and test how would would compose useFunction (cbc99c0)
- useHelper: can now reactively invoke helpers from JS (b51f10f)
3.1.3 (2021-08-18)
- deps: update dependency @ember/test-waiters to v3 (47571ee)
3.1.2 (2021-08-03)
- types: loosen the args type on the lifecycle resource (56f96b0)
3.1.1 (2021-08-01)
- 108: ensure that Args can be ommitted from Resources when unknown is ok (34c07ff)
- issue#108: loosen the constraint on what named arguments are (dff5be3), closes issue#108
3.1.0 (2021-07-31)
- resource: Resource without lifecycle hooks (ae0656f)
3.0.1 (2021-07-25)
3.0.0 (2021-07-20)
- functions: all useFunction functions are now async (01c6ffd)
- functions: all functions async due to an issue that came up during production builds, where minification would optimize away the async/await when the function was a one liner, like:
async () => {
return await ...
}
the async
keyword was a clue to the FunctionRunner
to go down a
different code branch (before running the function), but when the above
example function was minified, it became:
() => { return ... }
which then made the FunctionRunner
go down the sync path, resulting
in the value
being a promise, rather than the resolved value of the
promise.
2.0.1 (2021-07-14)
- deps: update dependency @ember/test-waiters to ^2.4.5 (010dae3)
2.0.0 (2021-07-10)
- useFunction now supports an initialValue param (6ba9e26)
- useFunction is no longer an alias of useResource
1.3.1 (2021-07-09)
- readme: Correct example import of
useResource
(5f99b22)
1.3.0 (2021-06-25)
- readme: table of contents links now work (00a397f)
- types, docs: document types and how to test with resources (8545bb6)
1.2.5 (2021-06-24)
- async functions: properly entangle for the value and prevent infinite re-rendering (ad268fe)
1.2.4 (2021-06-24)
- types: add type visibility to the FunctionRunner to keep private (e051be9)
- when an async function resolves, auto-tracking should do stuff (6504660)
1.2.3 (2021-06-23)
- lifecycle: support resources without a setup method (d11e6fc)
1.2.2 (2021-06-17)
- deps: update dependency ember-cli-typescript to ^4.2.1 (7a987a0)
1.2.1 (2021-06-17)
- deps: update dependency ember-cli-typescript to ^4.2.0 (ad65662)
1.2.0 (2021-06-06)
- readme: useTask is no longer coming soon -- it's here (d9e85b6)
- add useTask (8637477)
1.1.0 (2021-06-06)
- make addon not private (oops) (97eb257)
- embroider support (330e4c2)