Skip to content

Commit

Permalink
Merge branch 'build/v2' of https://github.com/QwikDev/qwik into fix_t…
Browse files Browse the repository at this point in the history
…est_slot
  • Loading branch information
wuls committed Jun 28, 2024
2 parents e1ff2f1 + 7840f17 commit 149d0a8
Show file tree
Hide file tree
Showing 39 changed files with 651 additions and 308 deletions.
17 changes: 5 additions & 12 deletions packages/qwik/src/core/components/prefetch.unit.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect, it } from 'vitest';
import { PrefetchServiceWorker, PrefetchGraph } from './prefetch';
import { renderToString2 as renderToString } from '../../server/v2-ssr-render2';
import { cleanupAttrs } from '../../testing/element-fixture';

describe('PrefetchServiceWorker', () => {
describe('render', () => {
Expand All @@ -12,9 +13,7 @@ describe('PrefetchServiceWorker', () => {
const output = await renderToString(<PrefetchServiceWorker nonce="1234" />, {
containerTagName: 'div',
});
expect(output.html).to.contain(
'<script q:key="prefetch-service-worker" : q:container="html" nonce="1234">'
);
expect(cleanupAttrs(output.html)).to.contain('<script q:container="html" nonce="1234">');
});
it('should render script with a scope', async () => {
const output = await renderToString(
Expand Down Expand Up @@ -103,18 +102,14 @@ describe('PrefetchGraph', () => {
const output = await renderToString(<PrefetchGraph nonce="1234" />, {
containerTagName: 'div',
});
expect(output.html).to.contain(
'<script q:key="prefetch-graph" : q:container="html" nonce="1234">'
);
expect(cleanupAttrs(output.html)).to.contain('<script q:container="html" nonce="1234">');
});

it('should render with a nonce', async () => {
const output = await renderToString(<PrefetchServiceWorker nonce="1234" />, {
containerTagName: 'div',
});
expect(output.html).to.contain(
'<script q:key="prefetch-service-worker" : q:container="html" nonce="1234">'
);
expect(cleanupAttrs(output.html)).to.contain('<script q:container="html" nonce="1234">');
});
it('should render script with a scope', async () => {
const output = await renderToString(
Expand Down Expand Up @@ -203,9 +198,7 @@ describe('PrefetchGraph', () => {
const output = await renderToString(<PrefetchGraph nonce="1234" />, {
containerTagName: 'div',
});
expect(output.html).to.contain(
'<script q:key="prefetch-graph" : q:container="html" nonce="1234">'
);
expect(cleanupAttrs(output.html)).to.contain('<script q:container="html" nonce="1234">');
});
});
});
3 changes: 3 additions & 0 deletions packages/qwik/src/core/state/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { trackSignal } from '../use/use-core';
import {
TaskFlags,
isComputedTask,
isResourceTask,
isSubscriberDescriptor,
isTask,
type SubscriberEffect,
Expand Down Expand Up @@ -489,6 +490,8 @@ export class LocalSubscriptionManager {
if (isTask(host)) {
if (isComputedTask(host)) {
scheduler(ChoreType.COMPUTED, host);
} else if (isResourceTask(host)) {
scheduler(ChoreType.RESOURCE, host);
} else {
const task = host as Task;
scheduler(
Expand Down
11 changes: 3 additions & 8 deletions packages/qwik/src/core/state/signal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertEqual } from '../error/assert';
import { tryGetInvokeContext } from '../use/use-core';
import { logWarn } from '../util/log';
import { ComputedEvent, RenderEvent, ResourceEvent } from '../util/markers';
import { ComputedEvent, RenderEvent } from '../util/markers';
import { qDev, qSerialize } from '../util/qdev';
import { isObject } from '../util/types';
import {
Expand Down Expand Up @@ -113,17 +113,12 @@ export class SignalImpl<T> extends SignalBase implements Signal<T> {
if (invokeCtx.$event$ === RenderEvent) {
logWarn(
'State mutation inside render function. Use useTask$() instead.',
invokeCtx.$hostElement$
String(invokeCtx.$hostElement$)
);
} else if (invokeCtx.$event$ === ComputedEvent) {
logWarn(
'State mutation inside useComputed$() is an antipattern. Use useTask$() instead',
invokeCtx.$hostElement$
);
} else if (invokeCtx.$event$ === ResourceEvent) {
logWarn(
'State mutation inside useResource$() is an antipattern. Use useTask$() instead',
invokeCtx.$hostElement$
String(invokeCtx.$hostElement$)
);
}
}
Expand Down
9 changes: 2 additions & 7 deletions packages/qwik/src/core/state/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { assertEqual, assertNumber, assertTrue } from '../error/assert';
import { QError_immutableProps, qError } from '../error/error';
import { tryGetInvokeContext } from '../use/use-core';
import { logError, logWarn } from '../util/log';
import { ComputedEvent, RenderEvent, ResourceEvent } from '../util/markers';
import { ComputedEvent, RenderEvent } from '../util/markers';
import { qDev, qSerialize } from '../util/qdev';
import { isArray, isObject, isSerializableObject } from '../util/types';
import {
Expand Down Expand Up @@ -233,12 +233,7 @@ export class ReadWriteProxyHandler implements ProxyHandler<TargetType> {
} else if (invokeCtx.$event$ === ComputedEvent) {
logWarn(
'State mutation inside useComputed$() is an antipattern. Use useTask$() instead',
invokeCtx.$hostElement$
);
} else if (invokeCtx.$event$ === ResourceEvent) {
logWarn(
'State mutation inside useResource$() is an antipattern. Use useTask$() instead',
invokeCtx.$hostElement$
String(invokeCtx.$hostElement$)
);
}
}
Expand Down
96 changes: 49 additions & 47 deletions packages/qwik/src/core/use/use-resource.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isServerPlatform } from '../platform/platform';
import { assertQrl } from '../qrl/qrl-class';
import { dollar, type QRL } from '../qrl/qrl.public';
import { Fragment, jsx } from '../render/jsx/jsx-runtime';
import { Fragment, _jsxSorted } from '../render/jsx/jsx-runtime';
import { untrack, useBindInvokeContext } from './use-core';
import {
Task,
Expand All @@ -21,7 +21,14 @@ import { createProxy, type StoreTracker } from '../state/store';
import { isPromise } from '../util/promises';
import { isObject } from '../util/types';
import { useSequentialScope } from './use-sequential-scope';
import { EMPTY_ARRAY } from '../util/flyweight';
import type { fixMeAny } from '../../server/qwik-types';

const DEBUG: boolean = false;

function debugLog(...arg: any) {
// eslint-disable-next-line no-console
console.log(arg.join(', '));
}

/**
* Options to pass to `useResource$()`
Expand Down Expand Up @@ -99,14 +106,14 @@ export const useResourceQrl = <T>(
qrl: QRL<ResourceFn<T>>,
opts?: ResourceOptions
): ResourceReturn<T> => {
const { val, set, i, iCtx, elCtx } = useSequentialScope<ResourceReturn<T>>();
const { val, set, i, iCtx } = useSequentialScope<ResourceReturn<T>>();
if (val != null) {
return val;
}
assertQrl(qrl);

const containerState = iCtx.$container2$ || iCtx.$renderCtx$.$static$.$containerState$;
const resource = createResourceReturn<T>(containerState, opts);
const container = iCtx.$container2$;
const resource = createResourceReturn<T>(container, opts);
const el = iCtx.$hostElement$;
const task = new Task(
TaskFlags.DIRTY | TaskFlags.RESOURCE,
Expand All @@ -116,14 +123,7 @@ export const useResourceQrl = <T>(
resource,
null
) as ResourceDescriptor<any>;
const previousWait = Promise.all(iCtx.$waitOn$ ? iCtx.$waitOn$.slice() : EMPTY_ARRAY);
runResource(task, containerState, iCtx.$renderCtx$, previousWait);
if (!iCtx.$container2$) {
if (!elCtx.$tasks$) {
elCtx.$tasks$ = [];
}
elCtx.$tasks$.push(task);
}
runResource(task, container, iCtx.$hostElement$ as fixMeAny);
set(resource);

return resource;
Expand Down Expand Up @@ -255,48 +255,48 @@ export interface ResourceProps<T> {
*/
// </docs>
export const Resource = <T>(props: ResourceProps<T>): JSXOutput => {
const isBrowser = !isServerPlatform();
// Resource path
return _jsxSorted(Fragment, null, null, getResourceValueAsPromise(props), 0, null);
};

function getResourceValueAsPromise<T>(props: ResourceProps<T>): Promise<JSXOutput> | JSXOutput {
const resource = props.value as ResourceReturnInternal<T> | Promise<T> | Signal<T>;
let promise: Promise<T> | undefined;
if (isResourceReturn(resource)) {
const isBrowser = !isServerPlatform();
if (isBrowser) {
if (props.onRejected) {
resource.value.catch(() => {});
if (resource._state === 'rejected') {
return props.onRejected(resource._error!);
}
}
if (props.onPending) {
const state = resource._state;
if (state === 'resolved') {
return props.onResolved(resource._resolved!);
} else if (state === 'pending') {
return props.onPending();
} else if (state === 'rejected') {
throw resource._error;
}
}
if (untrack(() => resource._resolved) !== undefined) {
return props.onResolved(resource._resolved!);
const state = resource._state;
DEBUG && debugLog(`RESOURCE_CMP.${state}`, 'VALUE: ' + untrack(() => resource._resolved));

if (state === 'pending' && props.onPending) {
return Promise.resolve(props.onPending());
} else if (state === 'rejected' && props.onRejected) {
return Promise.resolve(resource._error!).then(props.onRejected);
} else {
// resolved, pending without onPending prop or rejected with onRejected prop
return Promise.resolve(resource._resolved as T).then(props.onResolved);
}
}
promise = resource.value;
return resource.value.then(
useBindInvokeContext(props.onResolved),
useBindInvokeContext(props.onRejected)
);
} else if (isPromise(resource)) {
promise = resource;
return resource.then(
useBindInvokeContext(props.onResolved),
useBindInvokeContext(props.onRejected)
);
} else if (isSignal(resource)) {
promise = Promise.resolve(resource.value);
return Promise.resolve(resource.value).then(
useBindInvokeContext(props.onResolved),
useBindInvokeContext(props.onRejected)
);
} else {
return props.onResolved(resource as T);
}

// Resource path
return jsx(Fragment, {
children: promise.then(
return Promise.resolve(resource as T).then(
useBindInvokeContext(props.onResolved),
useBindInvokeContext(props.onRejected)
),
});
};
);
}
}

export const _createResourceReturn = <T>(opts?: ResourceOptions): ResourceReturnInternal<T> => {
const resource: ResourceReturnInternal<T> = {
Expand All @@ -318,7 +318,7 @@ export const createResourceReturn = <T>(
initialPromise?: Promise<T>
): ResourceReturnInternal<T> => {
const result = _createResourceReturn<T>(opts);
result.value = initialPromise as any;
result.value = initialPromise as Promise<T>;
const resource = createProxy(result, containerState, undefined);
return resource;
};
Expand All @@ -331,6 +331,7 @@ export const isResourceReturn = (obj: any): obj is ResourceReturn<unknown> => {
return isObject(obj) && (getProxyTarget(obj as any) || obj).__brand === 'resource';
};

// TODO: to remove - serializers v1
export const serializeResource = (
resource: ResourceReturnInternal<unknown>,
getObjId: GetObjID
Expand All @@ -345,9 +346,10 @@ export const serializeResource = (
}
};

// TODO: to remove - serializers v1
export const parseResourceReturn = <T>(data: string): ResourceReturnInternal<T> => {
const [first, id] = data.split(' ');
const result = _createResourceReturn<T>(undefined);
const result = _createResourceReturn<T>();
result.value = Promise.resolve() as any;
if (first === '0') {
result._state = 'resolved';
Expand Down
8 changes: 3 additions & 5 deletions packages/qwik/src/core/use/use-sequential-scope.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { verifySerializable } from '../state/common';
import { getContext, type QContext } from '../state/context';
import { ELEMENT_SEQ } from '../util/markers';
import { ELEMENT_SEQ, ELEMENT_SEQ_IDX } from '../util/markers';
import { qDev, qSerialize } from '../util/qdev';
import type { fixMeAny, HostElement } from '../v2/shared/types';
import { useInvokeContext, type RenderInvokeContext } from './use-core';
Expand Down Expand Up @@ -31,11 +31,11 @@ export const useSequentialScope = <T>(): SequentialScope<T> => {
seq = [];
iCtx.$container2$.setHostProp(host, ELEMENT_SEQ, seq);
}
let seqIdx = iCtx.$container2$.getHostProp<number>(host, SEQ_IDX_LOCAL);
let seqIdx = iCtx.$container2$.getHostProp<number>(host, ELEMENT_SEQ_IDX);
if (seqIdx === null) {
seqIdx = 0;
}
iCtx.$container2$.setHostProp(host, SEQ_IDX_LOCAL, seqIdx + 1);
iCtx.$container2$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
while (seq.length <= seqIdx) {
seq.push(undefined);
}
Expand Down Expand Up @@ -73,5 +73,3 @@ export const useSequentialScope = <T>(): SequentialScope<T> => {
};
}
};

export const SEQ_IDX_LOCAL = 'q:seqIdx';
Loading

0 comments on commit 149d0a8

Please sign in to comment.