Repository navigation
feat(core): async useComputed$ - #8807
Conversation
🦋 Changeset detectedLatest commit: 3672ae5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Pull request overview
This PR extends Qwik core’s computed signals to support async compute functions, deprecating useAsync$/createAsync$ and moving the async-signal machinery (pending/error state, jobs, polling, cleanup, serialization behavior) into ComputedSignalImpl. It also updates Qwik Router loader signals to use ComputedSignal, refreshes docs and API outputs to reflect the new async useComputed$ behavior, and updates e2e snapshots/budgets accordingly.
Changes:
- Add async support to
useComputed$/createComputed$and unify async-signal behavior intoComputedSignalImpl(with.pending,.error,.promise(), polling, etc.). - Deprecate
useAsync$/createAsync$and migrate router loaders and docs examples fromAsyncSignal/.loadingtoComputedSignal/.pending. - Update serialization/resume paths and SSG snapshot/budget expectations for the new signal engine behavior.
Reviewed changes
Copilot reviewed 69 out of 69 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/qwik/src/core/use/use-resource.ts | Switch ResourceCtx to extend ComputeCtx. |
| packages/qwik/src/core/use/use-computed.ts | Update computed hook types/docs for async compute functions and ComputeCtx. |
| packages/qwik/src/core/use/use-async.ts | Deprecate useAsync$ and switch ctx type to ComputeCtx. |
| packages/qwik/src/core/tests/use-resource.spec.tsx | Adjust resource test timing to accommodate new scheduling behavior. |
| packages/qwik/src/core/tests/use-computed.spec.tsx | Replace “promise disallowed” test with async-computed behavior tests. |
| packages/qwik/src/core/tests/use-async.spec.tsx | Update tests for .pending/internal field renames and new typing shape. |
| packages/qwik/src/core/ssr/ssr-render-jsx.ts | Treat computed signals as the relevant async/polling signal type for eager resume. |
| packages/qwik/src/core/shared/serdes/serialize.ts | Serialize async-mode computeds based on flags (not instanceof), and handle errored async mode. |
| packages/qwik/src/core/shared/serdes/serdes.unit.ts | Update serialization unit snapshots/expectations for new async-mode computed serialization. |
| packages/qwik/src/core/shared/serdes/inflate.ts | Update inflate logic to use $untrackedPending$ instead of $untrackedLoading$. |
| packages/qwik/src/core/shared/error/error.ts | Clear Q29 text since async computed is now supported. |
| packages/qwik/src/core/reactive-primitives/types.ts | Introduce ComputeCtx, expand ComputedOptions<T> to include async-signal options, add new async flags. |
| packages/qwik/src/core/reactive-primitives/signal.public.ts | Unify async API onto ComputedSignal (pending, error, promise, etc.), deprecate AsyncSignal as an alias. |
| packages/qwik/src/core/reactive-primitives/signal-api.ts | Update createComputedSignal signature to accept ComputedFn<T> and typed ComputedOptions<T>. |
| packages/qwik/src/core/reactive-primitives/internal-api.ts | Update signal-impl checks from AsyncSignalImpl to ComputedSignalImpl. |
| packages/qwik/src/core/reactive-primitives/impl/computed-signal-impl.ts | Core change: embed async engine state/behavior in ComputedSignalImpl and add async-computed execution semantics. |
| packages/qwik/src/core/reactive-primitives/impl/async-signal.unit.tsx | Update unit tests to stop depending on AsyncCtx typing and reflect new ctx shape. |
| packages/qwik/src/core/reactive-primitives/impl/async-signal-impl.ts | Reduce AsyncSignalImpl to a thin wrapper configuring flags/options; move engine logic to ComputedSignalImpl. |
| packages/qwik/src/core/reactive-primitives/impl/async-computed.unit.tsx | New unit coverage for async computed behavior: pending/error, tracking rules, previous/info, cleanup, options. |
| packages/qwik/src/core/reactive-primitives/cleanup.ts | Ensure cleanup removes pending/error subscriptions for computeds carrying async state. |
| packages/qwik/src/core/qwik.core.api.md | Update extracted core API docs for async useComputed$, deprecated async APIs, and new signal surface. |
| packages/qwik/src/core/client/vnode-diff.ts | Update cleanup logic to treat async-mode computeds as destroyable (similar to previous async-signal cleanup). |
| packages/qwik-router/src/runtime/src/types.ts | Refine action option typing (introduce ActionOptions and expand constructor overloads). |
| packages/qwik-router/src/runtime/src/server-functions.unit.ts | Add a type-level regression for routeAction$ invalidate typing without validators. |
| packages/qwik-router/src/runtime/src/route-loaders.ts | Switch loader signals from createAsync$ to async createComputed$ and update injected-value tracking notes. |
| packages/qwik-router/src/runtime/src/qwik-router.runtime.api.md | Update router API docs to reference ComputedSignal and new ActionOptions. |
| packages/qwik-router/src/runtime/src/qwik-router-component.tsx | Switch runtime loader state to ComputedSignal and update pending-trigger reads. |
| packages/qwik-router/src/runtime/src/index.ts | Export ActionOptions. |
| packages/qwik-router/src/runtime/src/head.ts | Update head resolution types to use ComputedSignal. |
| packages/qwik-router/ARCHITECTURE.md | Update documentation to refer to .untrackedPending for loader signal triggering. |
| packages/docs/src/routes/tutorial/reactivity/resource/solution/app.tsx | Migrate tutorial solution from useAsync$ to async useComputed$ and .pending. |
| packages/docs/src/routes/tutorial/reactivity/resource/problem/app.tsx | Migrate tutorial problem from useAsync$ to async useComputed$ and .pending. |
| packages/docs/src/routes/tutorial/reactivity/resource/index.mdx | Update tutorial copy/snippets from useAsync$ to async useComputed$. |
| packages/docs/src/routes/tutorial/introduction/resource/solution/app.tsx | Migrate intro tutorial solution to async useComputed$ and .pending. |
| packages/docs/src/routes/tutorial/introduction/resource/problem/app.tsx | Migrate intro tutorial problem to async useComputed$ and .pending. |
| packages/docs/src/routes/tutorial/introduction/resource/index.mdx | Update intro tutorial narrative/examples to async useComputed$ and .pending. |
| packages/docs/src/routes/examples/apps/reactivity/auto-complete/app.tsx | Update example from useAsync$ to async useComputed$. |
| packages/docs/src/routes/examples/apps/partial/hackernews-index/app.tsx | Update example from useAsync$ to async useComputed$ and .pending. |
| packages/docs/src/routes/docs/upgrade/index.mdx | Update upgrade guide to explain async useComputed$ and migration away from useAsync$. |
| packages/docs/src/routes/docs/labs/suspense/index.mdx | Update Suspense docs to use async useComputed$ and .pending. |
| packages/docs/src/routes/docs/errors/index.mdx | Mark Q29 as no longer used; update clientOnly SSR guidance to .pending. |
| packages/docs/src/routes/docs/(qwikrouter)/route-loader/index.mdx | Update route loader docs to ComputedSignal + .pending terminology. |
| packages/docs/src/routes/docs/(qwikrouter)/guides/best-practices/index.mdx | Update best-practices guidance to use async useComputed$ instead of useAsync$. |
| packages/docs/src/routes/docs/(qwik)/getting-started/index.mdx | Add/describe invalidate option in action examples. |
| packages/docs/src/routes/docs/(qwik)/core/tasks/index.mdx | Update guidance from useAsync$ to async useComputed$. |
| packages/docs/src/routes/docs/(qwik)/core/state/index.mdx | Replace useAsync$ section with “async computed values” guidance and migration note. |
| packages/docs/src/routes/docs/(qwik)/core/overview/index.mdx | Update overview bullets to reflect async useComputed$ and remove useAsync$. |
| packages/docs/src/routes/demo/state/async-joke/index.tsx | Migrate demo from useAsync$ to async useComputed$. |
| packages/docs/src/routes/demo/getting-started/06-styling/index.tsx | Update demo action example to include invalidate. |
| packages/docs/src/routes/demo/getting-started/05-tasks/index.tsx | Update demo action example to include invalidate. |
| packages/docs/src/routes/demo/getting-started/04-state/index.tsx | Update demo action example to include invalidate. |
| packages/docs/src/routes/demo/getting-started/03-posting-data/index.tsx | Update demo action example to include invalidate. |
| packages/docs/src/routes/demo/component/suspense-async/index.tsx | Update suspense demo from useAsync$ to async useComputed$. |
| packages/docs/src/routes/api/qwik/api.json | Update generated API JSON for deprecated async APIs and expanded computed signal API surface. |
| packages/docs/src/routes/api/qwik-router/index.mdx | Update generated router API docs to ActionOptions and ComputedSignal loader signal shape. |
| packages/docs/src/routes/api/qwik-router/api.json | Update generated router API JSON to include ActionOptions and new loader-signal pick set. |
| e2e/qwik-e2e/tests/qwikrouter/ssg-snapshot.e2e.ts | Bump core brotli budget to account for computed async engine move. |
| e2e/qwik-e2e/tests/qwikrouter/nav.e2e.ts | Strengthen nav assertions to ensure loader-driven content is visible after navigation. |
| e2e/qwik-e2e/apps/qwikrouter-ssg-snapshot/expected.state.txt | Update SSG serialized state golden to match new signal engine serialization layout. |
| e2e/qwik-e2e/apps/qwikrouter-ssg-snapshot/expected.ssg.html | Update SSG HTML golden to match new preload list/output. |
| .ruler/skills/qwik-e2e-verification/SKILL.md | Document SSG snapshot suite traps and regeneration behavior. |
| .ruler/skills/qwik-core-development/references/core-notes.md | Update core notes to reflect async engine move and new invariants (flags vs class identity). |
| .codex/skills/qwik-e2e-verification/SKILL.md | Regenerated skill output mirroring the updated .ruler source. |
| .codex/skills/qwik-core-development/references/core-notes.md | Regenerated skill output mirroring the updated .ruler source. |
| .claude/skills/qwik-e2e-verification/SKILL.md | Regenerated skill output mirroring the updated .ruler source. |
| .claude/skills/qwik-core-development/references/core-notes.md | Regenerated skill output mirroring the updated .ruler source. |
| .changeset/route-action-invalidate-types.md | Changeset for router type-level fix around action invalidation typing. |
| .changeset/async-computed.md | Changeset for core feature: async useComputed$ and async API deprecations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@qwik.dev/core
@qwik.dev/router
eslint-plugin-qwik
create-qwik
@qwik.dev/optimizer
@qwik.dev/devtools
commit: |
built with Refined Cloudflare Pages Action⚡ Cloudflare Pages Deployment
|
There was a problem hiding this comment.
I dont quite like that. The implementation is really loooong, even if someone is not using features, they need to download all the code, can we do it more tree shakeable? 🤔
There was a problem hiding this comment.
It's 200 brotli bytes more for the router e2e build hmmm.
There was a problem hiding this comment.
Well, we can't determine if the result is a Promise at build time, and making the async machinery lazy loaded dependent on that requires overhauling the core build and that's definitely a different PR.
useComputed$ now accepts async functions again. Reactive reads before the first `await` are auto-tracked, and later reads need the ComputeCtx track(). The AsyncSignal engine moves into ComputedSignalImpl.
Add a qwik-e2e-verification note on the two independent SSG snapshot assertion types (serialized goldens vs bundle-size budgets) and the update-does-not-fix-budgets / exit-1 traps. Regenerate committed skill outputs.
- reading .error triggers the compute if needed - synchronous throws also populate .error
|
@copilot resolve the merge conflicts in this pull request |
Resolved the merge conflict in
Both sets of checks are preserved in the merged result. |
also move the use-async tests to use-computed.
feat(core): async useComputed$
feat(core): async useComputed$
This PR deprecates
useAsync$and instead moves all async the machinery to ComputedSignal.This means that the synchronous part of the compute function gets reactive-tracked automatically, and after the first await,
track()needs to be used.