Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core): schedule QRLs instead of direct execution #7269

Open
wants to merge 25 commits into
base: build/v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f6a850a
fix(serde): catch rejections to prevent console errors
wmertens Jan 21, 2025
8367034
fix(testing): provide proper ctx for trigger()
wmertens Jan 20, 2025
1cedb93
refactor(build): separate the qwik insights module
wmertens Jan 19, 2025
3c0f6c1
chore(optimizer): remove _hW export
wmertens Jan 17, 2025
27020fa
refactor(core): schedule tasks via core qrl
wmertens Jan 19, 2025
770ddb2
chore(core): remove unused qrl refSymbol
wmertens Jan 19, 2025
a052f8f
fix(core): schedule qrls instead of direct call
wmertens Jan 19, 2025
ec7e9b2
fix(scheduler+ssr): correct order and draining
wmertens Jan 21, 2025
3e78fae
refactor(scheduler): remove COMPONENT_SSR type
Varixo Jan 25, 2025
7474c71
fix(scheduler): dont await for RUN_QRL chore
Varixo Jan 25, 2025
728d5b7
fix(scheduler): scheduling wait for all on server
Varixo Jan 26, 2025
141d15c
wip: await all run qrls in wait_for_all
wmertens Jan 26, 2025
3a62e98
wip
wmertens Jan 28, 2025
d70cf12
wip 2
wmertens Jan 28, 2025
40c3505
found it, no more uncaught exception
wmertens Jan 28, 2025
614c41b
fix use-task tests
Varixo Jan 29, 2025
35b34d1
fix unit tests
wmertens Jan 29, 2025
9ae2c49
fixup _task types
wmertens Jan 30, 2025
431c2cd
fix(core): canSerialize self-references
wmertens Jan 30, 2025
3f0f2a3
fixup qrl run error handling
wmertens Jan 30, 2025
64eb10e
wip failing component rerender after signal
wmertens Jan 30, 2025
22fd83b
fixup force schedule already executed equal chore
wmertens Jan 30, 2025
808acdf
fix: RUN_QRL host object
Varixo Jan 30, 2025
26564a1
don't await for qrls
Varixo Jan 31, 2025
514496b
fix adding event attribute name for csr
Varixo Feb 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/heavy-radios-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik.dev/core': patch
---

FIX: QRLs are now scheduled instead of directly executed by qwik-loader, so that they are executed in the right order.
5 changes: 5 additions & 0 deletions .changeset/olive-cameras-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik.dev/core': patch
---

CHORE: replace the `_hW` export in segments with a shared export `_task` in core. This opens up using QRLs from core.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ jobs:
pnpm install --frozen-lockfile

- name: 'build: qwik'
run: pnpm build --qwik --set-dist-tag="${{ needs.changes.outputs.disttag }}"
run: pnpm build --qwik --insights --set-dist-tag="${{ needs.changes.outputs.disttag }}"

- name: Print Qwik Dist Build
continue-on-error: true
Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,20 +172,20 @@
"build.clean": "rm -rf packages/qwik/dist/ && rm -rf packages/qwik-router/lib/ && rm -rf packages/docs/dist/ && rm -rf packages/insights/dist/",
"build.cli": "tsx --require ./scripts/runBefore.ts scripts/index.ts --cli --dev",
"build.cli.prod": "tsx --require ./scripts/runBefore.ts scripts/index.ts --cli",
"build.core": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --qwikrouter --api --platform-binding",
"build.core": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --qwik --insights --qwikrouter --api --platform-binding",
"build.eslint": "tsx --require ./scripts/runBefore.ts scripts/index.ts --eslint",
"build.full": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --tsc-docs --qwik --supabaseauthhelpers --api --eslint --qwikrouter --qwikworker --qwikreact --cli --platform-binding --wasm",
"build.local": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --tsc-docs --qwik --supabaseauthhelpers --api --eslint --qwikrouter --qwikworker --qwikreact --cli --platform-binding-wasm-copy",
"build.only_javascript": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --api",
"build.full": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --tsc-docs --qwik --insights --supabaseauthhelpers --api --eslint --qwikrouter --qwikworker --qwikreact --cli --platform-binding --wasm",
"build.local": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --tsc-docs --qwik --insights --supabaseauthhelpers --api --eslint --qwikrouter --qwikworker --qwikreact --cli --platform-binding-wasm-copy",
"build.only_javascript": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --qwik --api",
"build.packages.docs": "pnpm -C ./packages/docs/ run build",
"build.packages.insights": "pnpm -C ./packages/insights/ run build",
"build.platform": "tsx --require ./scripts/runBefore.ts scripts/index.ts --platform-binding",
"build.platform.copy": "tsx --require ./scripts/runBefore.ts scripts/index.ts --platform-binding-wasm-copy",
"build.qwik-router": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --qwikrouter",
"build.validate": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --api --eslint --qwikrouter --platform-binding --wasm --validate",
"build.vite": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --api --qwikrouter --eslint --platform-binding-wasm-copy",
"build.validate": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --qwik --api --eslint --qwikrouter --platform-binding --wasm --validate",
"build.vite": "tsx --require ./scripts/runBefore.ts scripts/index.ts --tsc --qwik --insights --api --qwikrouter --eslint --platform-binding-wasm-copy",
"build.wasm": "tsx --require ./scripts/runBefore.ts scripts/index.ts --wasm",
"build.watch": "tsx --require ./scripts/runBefore.ts scripts/index.ts --build --qwikrouter --watch --dev --platform-binding",
"build.watch": "tsx --require ./scripts/runBefore.ts scripts/index.ts --qwik --qwikrouter --watch --dev --platform-binding",
"change": "changeset",
"cli": "pnpm build.cli && node packages/create-qwik/dist/create-qwik.cjs && tsx --require ./scripts/runBefore.ts scripts/validate-cli.ts --copy-local-qwik-dist",
"cli.qwik": "pnpm build.cli && node packages/qwik/dist/qwik-cli.cjs",
Expand Down
30 changes: 1 addition & 29 deletions packages/docs/src/routes/api/qwik/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -277,20 +277,6 @@
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts",
"mdFile": "core.domattributes.md"
},
{
"name": "EagernessOptions",
"id": "eagernessoptions",
"hierarchy": [
{
"name": "EagernessOptions",
"id": "eagernessoptions"
}
],
"kind": "TypeAlias",
"content": "```typescript\nexport type EagernessOptions = 'visible' | 'load' | 'idle';\n```",
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task.ts",
"mdFile": "core.eagernessoptions.md"
},
{
"name": "Element",
"id": "qwikjsx-element",
Expand Down Expand Up @@ -2125,24 +2111,10 @@
}
],
"kind": "Function",
"content": "Reruns the `taskFn` when the observed inputs change.\n\nUse `useTask` to observe changes on a set of inputs, and then re-execute the `taskFn` when those inputs change.\n\nThe `taskFn` only executes if the observed inputs change. To observe the inputs, use the `obs` function to wrap property reads. This creates subscriptions that will trigger the `taskFn` to rerun.\n\n\n```typescript\nuseTask$: (qrl: import(\"./use-task\").TaskFn, opts?: import(\"./use-task\").UseTaskOptions | undefined) => void\n```\n\n\n<table><thead><tr><th>\n\nParameter\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\nqrl\n\n\n</td><td>\n\nimport(\"./use-task\").[TaskFn](#taskfn)\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\nopts\n\n\n</td><td>\n\nimport(\"./use-task\").[UseTaskOptions](#usetaskoptions) \\| undefined\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n</tbody></table>\n**Returns:**\n\nvoid",
"content": "Reruns the `taskFn` when the observed inputs change.\n\nUse `useTask` to observe changes on a set of inputs, and then re-execute the `taskFn` when those inputs change.\n\nThe `taskFn` only executes if the observed inputs change. To observe the inputs, use the `obs` function to wrap property reads. This creates subscriptions that will trigger the `taskFn` to rerun.\n\n\n```typescript\nuseTask$: (qrl: import(\"./use-task\").TaskFn) => void\n```\n\n\n<table><thead><tr><th>\n\nParameter\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\nqrl\n\n\n</td><td>\n\nimport(\"./use-task\").[TaskFn](#taskfn)\n\n\n</td><td>\n\n\n</td></tr>\n</tbody></table>\n**Returns:**\n\nvoid",
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task-dollar.ts",
"mdFile": "core.usetask_.md"
},
{
"name": "UseTaskOptions",
"id": "usetaskoptions",
"hierarchy": [
{
"name": "UseTaskOptions",
"id": "usetaskoptions"
}
],
"kind": "Interface",
"content": "```typescript\nexport interface UseTaskOptions \n```\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[eagerness?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[EagernessOptions](#eagernessoptions)\n\n\n</td><td>\n\n_(Optional)_ - `visible`<!-- -->: run the effect when the element is visible. - `load`<!-- -->: eagerly run the effect when the application resumes.\n\n\n</td></tr>\n</tbody></table>",
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task.ts",
"mdFile": "core.usetaskoptions.md"
},
{
"name": "useVisibleTask$",
"id": "usevisibletask_",
Expand Down
65 changes: 1 addition & 64 deletions packages/docs/src/routes/api/qwik/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -873,14 +873,6 @@ _(Optional)_

[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts)

## EagernessOptions

```typescript
export type EagernessOptions = "visible" | "load" | "idle";
```

[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task.ts)

## Element

```typescript
Expand Down Expand Up @@ -5252,7 +5244,7 @@ Use `useTask` to observe changes on a set of inputs, and then re-execute the `ta
The `taskFn` only executes if the observed inputs change. To observe the inputs, use the `obs` function to wrap property reads. This creates subscriptions that will trigger the `taskFn` to rerun.

```typescript
useTask$: (qrl: import("./use-task").TaskFn, opts?: import("./use-task").UseTaskOptions | undefined) => void
useTask$: (qrl: import("./use-task").TaskFn) => void
```

<table><thead><tr><th>
Expand All @@ -5278,19 +5270,6 @@ import("./use-task").[TaskFn](#taskfn)

</td><td>

</td></tr>
<tr><td>

opts

</td><td>

import("./use-task").[UseTaskOptions](#usetaskoptions) \| undefined

</td><td>

_(Optional)_

</td></tr>
</tbody></table>
**Returns:**
Expand All @@ -5299,48 +5278,6 @@ void

[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task-dollar.ts)

## UseTaskOptions

```typescript
export interface UseTaskOptions
```

<table><thead><tr><th>

Property

</th><th>

Modifiers

</th><th>

Type

</th><th>

Description

</th></tr></thead>
<tbody><tr><td>

[eagerness?](#)

</td><td>

</td><td>

[EagernessOptions](#eagernessoptions)

</td><td>

_(Optional)_ - `visible`: run the effect when the element is visible. - `load`: eagerly run the effect when the application resumes.

</td></tr>
</tbody></table>

[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task.ts)

## useVisibleTask$

```tsx
Expand Down
9 changes: 9 additions & 0 deletions packages/qwik/handlers.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* This re-exports the QRL handlers so that they can be used as QRLs.
*
* In vite dev mode, this file is referenced directly. This ensures that the correct path to core is
* used so that there's only one instance of Qwik.
*
* Make sure that these handlers are listed in manifest.ts
*/
export { _run, _task } from '@qwik.dev/core';
2 changes: 2 additions & 0 deletions packages/qwik/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"./cli": {
"require": "./dist/cli.cjs"
},
"./handlers.mjs": "./handlers.mjs",
"./internal": {
"types": "./core-internal.d.ts",
"import": {
Expand Down Expand Up @@ -144,6 +145,7 @@
"bindings",
"build.d.ts",
"cli.d.ts",
"handlers.mjs",
"jsx-dev-runtime.d.ts",
"jsx-runtime.d.ts",
"loader.d.ts",
Expand Down
31 changes: 9 additions & 22 deletions packages/qwik/src/core/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,6 @@ class DomContainer extends _SharedContainer implements ClientContainer {
export { DomContainer }
export { DomContainer as _DomContainer }

// @public (undocumented)
export type EagernessOptions = 'visible' | 'load' | 'idle';

// @internal (undocumented)
export class _EffectData {
constructor(data: NodePropData);
Expand Down Expand Up @@ -316,9 +313,6 @@ function h<TYPE extends string | FunctionComponent<PROPS>, PROPS extends {} = {}
export { h as createElement }
export { h }

// @internal
export const _hW: () => void;

// @internal @deprecated (undocumented)
export const _IMMUTABLE: unique symbol;

Expand Down Expand Up @@ -808,6 +802,9 @@ export type ResourceReturn<T> = ResourcePending<T> | ResourceResolved<T> | Resou
// @internal (undocumented)
export const _restProps: (props: Record<string, any>, omit: string[], target?: {}) => {};

// @internal
export const _run: (...args: unknown[]) => ValueOrPromise<void>;

// @internal
export function _serialize(data: unknown[]): Promise<string>;

Expand Down Expand Up @@ -997,6 +994,9 @@ export interface SyncQRL<TYPE extends Function = any> extends QRL<TYPE> {
resolved: TYPE;
}

// @internal
export const _task: (_event: Event, element: Element) => void;

// @public (undocumented)
export interface TaskCtx {
// (undocumented)
Expand Down Expand Up @@ -1137,17 +1137,12 @@ export interface UseStylesScoped {
export const useStylesScopedQrl: (styles: QRL<string>) => UseStylesScoped;

// @public
export const useTask$: (qrl: TaskFn, opts?: UseTaskOptions | undefined) => void;

// @public (undocumented)
export interface UseTaskOptions {
eagerness?: EagernessOptions;
}
export const useTask$: (qrl: TaskFn) => void;

// Warning: (ae-internal-missing-underscore) The name "useTaskQrl" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal (undocumented)
export const useTaskQrl: (qrl: QRL<TaskFn>, opts?: UseTaskOptions) => void;
export const useTaskQrl: (qrl: QRL<TaskFn>) => void;

// @public
export const useVisibleTask$: (qrl: TaskFn, opts?: OnVisibleTaskOptions | undefined) => void;
Expand Down Expand Up @@ -1234,17 +1229,9 @@ export const _waitUntilRendered: (elm: Element) => Promise<void>;
//
// @internal (undocumented)
export function _walkJSX(ssr: SSRContainer, value: JSXOutput, options: {
allowPromises: true;
currentStyleScoped: string | null;
parentComponentFrame: ISsrComponentFrame | null;
}): ValueOrPromise<void>;

// @internal (undocumented)
export function _walkJSX(ssr: SSRContainer, value: JSXOutput, options: {
allowPromises: false;
currentStyleScoped: string | null;
parentComponentFrame: ISsrComponentFrame | null;
}): false;
}): Promise<void>;

// @internal (undocumented)
export const _weakSerialize: <T extends object>(input: T) => Partial<T>;
Expand Down
22 changes: 11 additions & 11 deletions packages/qwik/src/core/client/dom-container.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
/** @file Public APIs for the SSR */

import { assertTrue } from '../shared/error/assert';
import { QError, qError } from '../shared/error/error';
import { ERROR_CONTEXT, isRecoverable } from '../shared/error/error-handling';
import { getPlatform } from '../shared/platform/platform';
import type { QRL } from '../shared/qrl/qrl.public';
import { ERROR_CONTEXT, isRecoverable } from '../shared/error/error-handling';
import type { ContextId } from '../use/use-context';
import { ChoreType } from '../shared/scheduler';
import { _SharedContainer } from '../shared/shared-container';
import { inflateQRL, parseQRL, wrapDeserializerProxy } from '../shared/shared-serialization';
import { QContainerValue, type HostElement, type ObjToProxyMap } from '../shared/types';
import { EMPTY_ARRAY } from '../shared/utils/flyweight';
import {
ELEMENT_PROPS,
ELEMENT_SEQ,
ELEMENT_SEQ_IDX,
getQFuncs,
OnRenderProp,
Q_PROPS_SEPARATOR,
QBaseAttr,
QContainerAttr,
QContainerSelector,
Expand All @@ -23,19 +25,18 @@ import {
QStyle,
QStyleSelector,
QSubscribers,
Q_PROPS_SEPARATOR,
USE_ON_LOCAL_SEQ_IDX,
getQFuncs,
} from '../shared/utils/markers';
import { isPromise } from '../shared/utils/promises';
import { isSlotProp } from '../shared/utils/prop';
import { qDev } from '../shared/utils/qdev';
import { ChoreType } from '../shared/scheduler';
import {
convertScopedStyleIdsToArray,
convertStyleIdsToString,
} from '../shared/utils/scoped-styles';
import { _SharedContainer } from '../shared/shared-container';
import { inflateQRL, parseQRL, wrapDeserializerProxy } from '../shared/shared-serialization';
import { QContainerValue, type HostElement, type ObjToProxyMap } from '../shared/types';
import type { ContextId } from '../use/use-context';
import { processVNodeData } from './process-vnode-data';
import {
VNodeFlags,
Expand Down Expand Up @@ -65,7 +66,6 @@ import {
vnode_setProp,
type VNodeJournal,
} from './vnode';
import { QError, qError } from '../shared/error/error';

/** @public */
export function getDomContainer(element: Element | VNode): IClientContainer {
Expand Down Expand Up @@ -190,7 +190,7 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
}

handleError(err: any, host: HostElement): void {
if (qDev) {
if (qDev && host) {
// Clean vdom
if (typeof document !== 'undefined') {
const vHost = host as VirtualVNode;
Expand All @@ -215,7 +215,7 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
throw err;
}
}
const errorStore = this.resolveContext(host, ERROR_CONTEXT);
const errorStore = host && this.resolveContext(host, ERROR_CONTEXT);
if (!errorStore) {
throw err;
}
Expand Down
27 changes: 27 additions & 0 deletions packages/qwik/src/core/client/queue-qrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { QError, qError } from '../shared/error/error';
import type { QRLInternal } from '../shared/qrl/qrl-class';
import { ChoreType } from '../shared/scheduler';
import { getInvokeContext } from '../use/use-core';
import { useLexicalScope } from '../use/use-lexical-scope.public';
import { _getQContainerElement, getDomContainer } from './dom-container';
import type { ElementVNode } from './types';

/**
* This is called by qwik-loader to schedule a QRL. It has to be synchronous.
*
* @internal
*/
export const queueQRL = (...args: unknown[]) => {
// This will already check container
const [runQrl] = useLexicalScope<[QRLInternal<(...args: unknown[]) => unknown>]>();
const context = getInvokeContext();
const hostElement = context.$hostElement$ as ElementVNode;
const container = getDomContainer(hostElement);

const scheduler = container.$scheduler$;
if (!scheduler) {
throw qError(QError.schedulerNotFound);
}

return scheduler(ChoreType.RUN_QRL, hostElement, runQrl, args);
};
Loading
Loading