From 6f31c7700eb611f001411cd90f2411e006ad5082 Mon Sep 17 00:00:00 2001 From: Varixo Date: Sun, 18 Aug 2024 20:53:52 +0200 Subject: [PATCH] fix scoped style id --- packages/qwik/src/core/use/use-core.ts | 11 ++++++----- packages/qwik/src/core/use/use-task.ts | 4 ++-- packages/qwik/src/core/v2/client/vnode-diff.ts | 5 +++-- .../src/core/v2/shared/component-execution.ts | 2 +- packages/qwik/src/core/v2/shared/scheduler.ts | 10 ++++++++-- .../qwik/src/core/v2/shared/shared-container.ts | 16 +++++++++------- .../src/core/v2/shared/shared-serialization.ts | 3 ++- packages/qwik/src/core/v2/signal/v2-signal.ts | 16 ++++++++++++---- .../qwik/src/core/v2/signal/v2-signal.unit.tsx | 2 +- .../src/core/v2/tests/use-styles-scoped.spec.tsx | 2 +- packages/qwik/src/server/v2-ssr-container.ts | 2 +- 11 files changed, 46 insertions(+), 27 deletions(-) diff --git a/packages/qwik/src/core/use/use-core.ts b/packages/qwik/src/core/use/use-core.ts index f662ef6a59c..0395f35bb8f 100644 --- a/packages/qwik/src/core/use/use-core.ts +++ b/packages/qwik/src/core/use/use-core.ts @@ -25,7 +25,7 @@ import type { Container2 } from '../v2/shared/types'; import { vnode_getNode, vnode_isElementVNode, vnode_isVNode } from '../v2/client/vnode'; import { _getQContainerElement } from '../v2/client/dom-container'; import type { ContainerElement } from '../v2/client/types'; -import type { Effect, EffectSubscriptions } from '../v2/signal/v2-signal'; +import type { EffectSubscriptions, EffectSubscriptionsProp } from '../v2/signal/v2-signal'; declare const document: QwikDocument; @@ -253,14 +253,15 @@ export const trackSignal = (signal: Signal, sub: Subscriber): T => { */ export const trackSignal2 = ( fn: () => T, - subscriber: Effect, - property: string, - container: Container2 + subscriber: EffectSubscriptions[EffectSubscriptionsProp.EFFECT], + property: EffectSubscriptions[EffectSubscriptionsProp.PROPERTY], + container: Container2, + data: EffectSubscriptions[EffectSubscriptionsProp.DATA] = null ): T => { const previousSubscriber = trackInvocation.$effectSubscriber$; const previousContainer = trackInvocation.$container2$; try { - trackInvocation.$effectSubscriber$ = [subscriber, property]; + trackInvocation.$effectSubscriber$ = [subscriber, property, data]; trackInvocation.$container2$ = container; return invoke(trackInvocation, fn); } finally { diff --git a/packages/qwik/src/core/use/use-task.ts b/packages/qwik/src/core/use/use-task.ts index 0b7a92e7b9d..4b6a8e00c0a 100644 --- a/packages/qwik/src/core/use/use-task.ts +++ b/packages/qwik/src/core/use/use-task.ts @@ -355,7 +355,7 @@ export const runTask2 = (task: Task, container: Container2, host: HostElement) = const track: Tracker = (obj: (() => unknown) | object | Signal, prop?: string) => { const ctx = newInvokeContext(); - ctx.$effectSubscriber$ = [task, EffectProperty.COMPONENT]; + ctx.$effectSubscriber$ = [task, EffectProperty.COMPONENT, null]; ctx.$container2$ = container; return invoke(ctx, () => { if (isFunction(obj)) { @@ -577,7 +577,7 @@ export const runResource = ( const track: Tracker = (obj: (() => unknown) | object | Signal, prop?: string) => { const ctx = newInvokeContext(); - ctx.$effectSubscriber$ = [task, EffectProperty.COMPONENT]; + ctx.$effectSubscriber$ = [task, EffectProperty.COMPONENT, null]; ctx.$container2$ = container; return invoke(ctx, () => { if (isFunction(obj)) { diff --git a/packages/qwik/src/core/v2/client/vnode-diff.ts b/packages/qwik/src/core/v2/client/vnode-diff.ts index 722832b620d..83969766aef 100644 --- a/packages/qwik/src/core/v2/client/vnode-diff.ts +++ b/packages/qwik/src/core/v2/client/vnode-diff.ts @@ -625,9 +625,10 @@ export const vnode_diff = ( if (isSignal2(value)) { value = trackSignal2( () => (value as Signal2).value, - vNewNode as fixMeAny, + vNewNode as ElementVNode, key, - container + container, + scopedStyleIdPrefix ); } diff --git a/packages/qwik/src/core/v2/shared/component-execution.ts b/packages/qwik/src/core/v2/shared/component-execution.ts index 31ea0484ba4..c7ff8c76a1b 100644 --- a/packages/qwik/src/core/v2/shared/component-execution.ts +++ b/packages/qwik/src/core/v2/shared/component-execution.ts @@ -56,7 +56,7 @@ export const executeComponent2 = ( undefined, RenderEvent ); - iCtx.$effectSubscriber$ = [subscriptionHost, EffectProperty.COMPONENT]; + iCtx.$effectSubscriber$ = [subscriptionHost, EffectProperty.COMPONENT, null]; iCtx.$container2$ = container; let componentFn: (props: unknown) => ValueOrPromise; container.ensureProjectionResolved(renderHost); diff --git a/packages/qwik/src/core/v2/shared/scheduler.ts b/packages/qwik/src/core/v2/shared/scheduler.ts index f891230b1c1..ffbf70bd904 100644 --- a/packages/qwik/src/core/v2/shared/scheduler.ts +++ b/packages/qwik/src/core/v2/shared/scheduler.ts @@ -141,6 +141,11 @@ export interface Chore { $returnValue$: any; } +export interface NodePropPayload { + value: string; + scopedStyleIdPrefix: string | null; +} + export type Scheduler = ReturnType; export const createScheduler = ( @@ -339,13 +344,14 @@ export const createScheduler = ( break; case ChoreType.NODE_PROP: const virtualNode = chore.$host$ as VirtualVNode; - let value = chore.$payload$ as any; + const payload = chore.$payload$ as NodePropPayload; + let value = payload.value; if (isSignal2(value)) { value = value.value as any; } const journal = (container as DomContainer).$journal$; const property = chore.$idx$ as string; - value = serializeAttribute(property, value); + value = serializeAttribute(property, value, payload.scopedStyleIdPrefix); vnode_setAttr(journal, virtualNode, property, value); break; case ChoreType.QRL_RESOLVE: { diff --git a/packages/qwik/src/core/v2/shared/shared-container.ts b/packages/qwik/src/core/v2/shared/shared-container.ts index 657134f268d..a8ec2d9e536 100644 --- a/packages/qwik/src/core/v2/shared/shared-container.ts +++ b/packages/qwik/src/core/v2/shared/shared-container.ts @@ -1,15 +1,12 @@ import type { ObjToProxyMap } from '../../container/container'; import type { JSXOutput } from '../../render/jsx/types/jsx-node'; -import { - createSubscriptionManager, - type SubscriptionManager -} from '../../state/common'; +import { createSubscriptionManager, type SubscriptionManager } from '../../state/common'; import type { Signal } from '../../state/signal'; import type { ContextId } from '../../use/use-context'; import { trackSignal2 } from '../../use/use-core'; import type { ValueOrPromise } from '../../util/types'; import { version } from '../../version'; -import type { Effect } from '../signal/v2-signal'; +import type { EffectSubscriptions, EffectSubscriptionsProp } from '../signal/v2-signal'; import type { StreamWriter, SymbolToChunkResolver } from '../ssr/ssr-types'; import type { Scheduler } from './scheduler'; import { createScheduler } from './scheduler'; @@ -47,8 +44,13 @@ export abstract class _SharedContainer implements Container2 { this.$scheduler$ = createScheduler(this, scheduleDrain, journalFlush); } - trackSignalValue(signal: Signal, subscriber: Effect, property: string): T { - return trackSignal2(() => signal.value, subscriber, property, this); + trackSignalValue( + signal: Signal, + subscriber: EffectSubscriptions[EffectSubscriptionsProp.EFFECT], + property: EffectSubscriptions[EffectSubscriptionsProp.PROPERTY], + data: EffectSubscriptions[EffectSubscriptionsProp.DATA] + ): T { + return trackSignal2(() => signal.value, subscriber, property, this, data); } serializationCtxFactory( diff --git a/packages/qwik/src/core/v2/shared/shared-serialization.ts b/packages/qwik/src/core/v2/shared/shared-serialization.ts index f1bd478f3c2..9a7db92642e 100644 --- a/packages/qwik/src/core/v2/shared/shared-serialization.ts +++ b/packages/qwik/src/core/v2/shared/shared-serialization.ts @@ -1039,7 +1039,8 @@ function serializeEffectSubs( const effectSubscription = effects[i]; const effect = effectSubscription[EffectSubscriptionsProp.EFFECT]; const prop = effectSubscription[EffectSubscriptionsProp.PROPERTY]; - data += ';' + addRoot(effect) + ' ' + prop; + const additionalData = effectSubscription[EffectSubscriptionsProp.DATA]; + data += ';' + addRoot(effect) + ' ' + prop + ' ' + addRoot(additionalData); for (let j = EffectSubscriptionsProp.FIRST_BACK_REF; j < effectSubscription.length; j++) { data += ' ' + addRoot(effectSubscription[j]); } diff --git a/packages/qwik/src/core/v2/signal/v2-signal.ts b/packages/qwik/src/core/v2/signal/v2-signal.ts index aa391d9d218..5ba164b0c1c 100644 --- a/packages/qwik/src/core/v2/signal/v2-signal.ts +++ b/packages/qwik/src/core/v2/signal/v2-signal.ts @@ -23,7 +23,7 @@ import { isPromise } from '../../util/promises'; import { qDev } from '../../util/qdev'; import type { VNode } from '../client/types'; import { vnode_getProp, vnode_isVirtualVNode, vnode_isVNode, vnode_setProp } from '../client/vnode'; -import { ChoreType } from '../shared/scheduler'; +import { ChoreType, type NodePropPayload } from '../shared/scheduler'; import type { Container2, HostElement, fixMeAny } from '../shared/types'; import type { ISsrNode } from '../ssr/ssr-types'; import type { Signal2 as ISignal2 } from './v2-signal.public'; @@ -119,6 +119,7 @@ export type Effect = Task | VNode | ISsrNode | Signal2; export type EffectSubscriptions = [ Effect, // EffectSubscriptionsProp.EFFECT string, // EffectSubscriptionsProp.PROPERTY + any | null, // EffectSubscriptionsProp.DATA ...// NOTE even thought this is shown as `...(string|Signal2)` // it is a list of strings followed by a list of signals (not intermingled) ( @@ -130,7 +131,8 @@ export type EffectSubscriptions = [ export const enum EffectSubscriptionsProp { EFFECT = 0, PROPERTY = 1, - FIRST_BACK_REF = 2, + DATA = 2, + FIRST_BACK_REF = 3, } export const enum EffectProperty { COMPONENT = ':', @@ -322,7 +324,13 @@ export const triggerEffects = ( container.$scheduler$.schedule(ChoreType.NODE_DIFF, host, target, signal as fixMeAny); } else { const host: HostElement = effect as any; - container.$scheduler$.schedule(ChoreType.NODE_PROP, host, property, signal as fixMeAny); + const scopedStyleIdPrefix: string | null = + effectSubscriptions[EffectSubscriptionsProp.DATA]; + const payload: NodePropPayload = { + value: signal, + scopedStyleIdPrefix, + }; + container.$scheduler$.schedule(ChoreType.NODE_PROP, host, property, payload); } }; effects.forEach(scheduleEffect); @@ -396,7 +404,7 @@ export class ComputedSignal2 extends Signal2 { const ctx = tryGetInvokeContext(); assertDefined(computeQrl, 'Signal is marked as dirty, but no compute function is provided.'); const previousEffectSubscription = ctx?.$effectSubscriber$; - ctx && (ctx.$effectSubscriber$ = [this, EffectProperty.VNODE]); + ctx && (ctx.$effectSubscriber$ = [this, EffectProperty.VNODE, null]); assertTrue( !!computeQrl.resolved, 'Computed signals must run sync. Expected the QRL to be resolved at this point.' diff --git a/packages/qwik/src/core/v2/signal/v2-signal.unit.tsx b/packages/qwik/src/core/v2/signal/v2-signal.unit.tsx index 935e68342f7..fb77f3da372 100644 --- a/packages/qwik/src/core/v2/signal/v2-signal.unit.tsx +++ b/packages/qwik/src/core/v2/signal/v2-signal.unit.tsx @@ -163,7 +163,7 @@ describe('v2-signal', () => { } else { const ctx = newInvokeContext(); ctx.$container2$ = container; - const subscriber: EffectSubscriptions = [task, EffectProperty.COMPONENT, ctx]; + const subscriber: EffectSubscriptions = [task, EffectProperty.COMPONENT, null, ctx]; ctx.$effectSubscriber$ = subscriber; return invoke(ctx, qrl.getFn(ctx)); } diff --git a/packages/qwik/src/core/v2/tests/use-styles-scoped.spec.tsx b/packages/qwik/src/core/v2/tests/use-styles-scoped.spec.tsx index 3ed3f11d036..287f7577aa1 100644 --- a/packages/qwik/src/core/v2/tests/use-styles-scoped.spec.tsx +++ b/packages/qwik/src/core/v2/tests/use-styles-scoped.spec.tsx @@ -60,7 +60,7 @@ describe.each([ ); }); - it('should render style', async () => { + it('should render object style', async () => { (globalThis as any).rawStyleId = ''; const StyledComponent = component$(() => { diff --git a/packages/qwik/src/server/v2-ssr-container.ts b/packages/qwik/src/server/v2-ssr-container.ts index f9dd484c42e..9372b8d33f3 100644 --- a/packages/qwik/src/server/v2-ssr-container.ts +++ b/packages/qwik/src/server/v2-ssr-container.ts @@ -1054,7 +1054,7 @@ class SSRContainer extends _SharedContainer implements ISSRContainer { if (isSignal(value)) { const lastNode = this.getLastNode(); - value = this.trackSignalValue(value, lastNode, key); + value = this.trackSignalValue(value, lastNode, key, styleScopedId); } if (key === dangerouslySetInnerHTML) {