Skip to content

Commit 74a9539

Browse files
committed
chore: move signal impl to separate file
1 parent 4c769dd commit 74a9539

File tree

8 files changed

+113
-97
lines changed

8 files changed

+113
-97
lines changed

packages/qwik/src/core/shared/shared-serialization.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { _EFFECT_BACK_REF, NEEDS_COMPUTATION } from '../signal/flags';
1111
import {
1212
ComputedSignalImpl,
1313
SerializerSignalImpl,
14-
SignalImpl,
1514
WrappedSignal,
1615
isSerializerObj,
1716
type SerializerArg,
@@ -59,6 +58,7 @@ import {
5958
type EffectSubscription,
6059
} from '../signal/types';
6160
import { SubscriptionData, type NodePropData } from '../signal/subscription-data';
61+
import { SignalImpl } from '../signal/impl/signal-impl';
6262

6363
const deserializedProxyMap = new WeakMap<object, unknown[]>();
6464

packages/qwik/src/core/shared/shared-serialization.unit.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { $, component$, noSerialize } from '@qwik.dev/core';
22
import { describe, expect, it, vi } from 'vitest';
33
import { _fnSignal, _wrapProp } from '../internal';
4-
import { type SignalImpl } from '../signal/signal';
4+
import { type SignalImpl } from '../signal/impl/signal-impl';
55
import {
66
createComputed$,
77
createSerializer$,
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { qError, QError } from '../../shared/error/error';
2+
import { assertTrue } from '../../shared/error/assert';
3+
import type { Container } from '../../shared/types';
4+
import { addQrlToSerializationCtx, triggerEffects } from '../signal';
5+
import { ensureContainsBackRef } from '../signal';
6+
import { tryGetInvokeContext } from '../../use/use-core';
7+
import { ensureContainsSubscription } from '../signal';
8+
import type { Signal } from '../signal.public';
9+
import { SignalFlags, type EffectSubscription } from '../types';
10+
import { pad, qwikDebugToString } from '../../debug';
11+
import { qDev } from '../../shared/utils/qdev';
12+
import { isDev } from '@qwik.dev/core/build';
13+
14+
const DEBUG = false;
15+
// eslint-disable-next-line no-console
16+
const log = (...args: any[]) => console.log('SIGNAL', ...args.map(qwikDebugToString));
17+
18+
export class SignalImpl<T = any> implements Signal<T> {
19+
$untrackedValue$: T;
20+
21+
/** Store a list of effects which are dependent on this signal. */
22+
$effects$: null | Set<EffectSubscription> = null;
23+
24+
$container$: Container | null = null;
25+
26+
constructor(container: Container | null, value: T) {
27+
this.$container$ = container;
28+
this.$untrackedValue$ = value;
29+
DEBUG && log('new', this);
30+
}
31+
32+
get untrackedValue() {
33+
return this.$untrackedValue$;
34+
}
35+
36+
// TODO: should we disallow setting the value directly?
37+
set untrackedValue(value: T) {
38+
this.$untrackedValue$ = value;
39+
}
40+
41+
get value() {
42+
const ctx = tryGetInvokeContext();
43+
if (ctx) {
44+
if (this.$container$ === null) {
45+
if (!ctx.$container$) {
46+
return this.untrackedValue;
47+
}
48+
// Grab the container now we have access to it
49+
this.$container$ = ctx.$container$;
50+
} else {
51+
assertTrue(
52+
!ctx.$container$ || ctx.$container$ === this.$container$,
53+
'Do not use signals across containers'
54+
);
55+
}
56+
const effectSubscriber = ctx.$effectSubscriber$;
57+
if (effectSubscriber) {
58+
const effects = (this.$effects$ ||= new Set());
59+
// Let's make sure that we have a reference to this effect.
60+
// Adding reference is essentially adding a subscription, so if the signal
61+
// changes we know who to notify.
62+
ensureContainsSubscription(effects, effectSubscriber);
63+
// But when effect is scheduled in needs to be able to know which signals
64+
// to unsubscribe from. So we need to store the reference from the effect back
65+
// to this signal.
66+
ensureContainsBackRef(effectSubscriber, this);
67+
addQrlToSerializationCtx(effectSubscriber, this.$container$);
68+
DEBUG && log('read->sub', pad('\n' + this.toString(), ' '));
69+
}
70+
}
71+
return this.untrackedValue;
72+
}
73+
set value(value) {
74+
if (value !== this.$untrackedValue$) {
75+
DEBUG &&
76+
log('Signal.set', this.$untrackedValue$, '->', value, pad('\n' + this.toString(), ' '));
77+
this.$untrackedValue$ = value;
78+
triggerEffects(this.$container$, this, this.$effects$);
79+
}
80+
}
81+
82+
// prevent accidental use as value
83+
valueOf() {
84+
if (qDev) {
85+
throw qError(QError.cannotCoerceSignal);
86+
}
87+
}
88+
89+
toString() {
90+
if (isDev) {
91+
return (
92+
`[${this.constructor.name}${(this as any).$flags$ & SignalFlags.INVALID ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
93+
(Array.from(this.$effects$ || [])
94+
.map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' '))
95+
.join('\n') || '')
96+
);
97+
} else {
98+
return this.constructor.name;
99+
}
100+
}
101+
toJSON() {
102+
return { value: this.$untrackedValue$ };
103+
}
104+
}

packages/qwik/src/core/signal/signal-api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { QRLInternal } from '../shared/qrl/qrl-class';
22
import type { QRL } from '../shared/qrl/qrl.public';
3+
import { SignalImpl } from './impl/signal-impl';
34
import {
45
ComputedSignalImpl,
56
SerializerSignalImpl,
6-
SignalImpl,
77
throwIfQRLNotResolved,
88
type SerializerArg,
99
} from './signal';

packages/qwik/src/core/signal/signal-cleanup.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { WrappedSignal, SignalImpl } from './signal';
1+
import { WrappedSignal } from './signal';
22
import { StoreHandler, getStoreHandler } from './store';
33
import type { Container } from '../shared/types';
44
import { ensureMaterialized, vnode_isElementVNode, vnode_isVNode } from '../client/vnode';
@@ -9,6 +9,7 @@ import {
99
type EffectProperty,
1010
type EffectSubscription,
1111
} from './types';
12+
import { SignalImpl } from './impl/signal-impl';
1213

1314
/** Class for back reference to the EffectSubscription */
1415
export abstract class BackRef {

packages/qwik/src/core/signal/signal.ts

Lines changed: 2 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
* - It needs to store a function which needs to re-run.
1212
* - It is `Readonly` because it is computed.
1313
*/
14-
import { isDev } from '@qwik.dev/core/build';
1514
import { isDomContainer } from '../client/dom-container';
1615
import { pad, qwikDebugToString } from '../debug';
1716
import type { OnRenderFn } from '../shared/component.public';
18-
import { assertDefined, assertFalse, assertTrue } from '../shared/error/assert';
17+
import { assertDefined, assertFalse } from '../shared/error/assert';
1918
import { QError, qError } from '../shared/error/error';
2019
import type { Props } from '../shared/jsx/jsx-runtime';
2120
import { type QRLInternal } from '../shared/qrl/qrl-class';
@@ -24,12 +23,12 @@ import type { Container, HostElement } from '../shared/types';
2423
import { ChoreType } from '../shared/util-chore-type';
2524
import { ELEMENT_PROPS, OnRenderProp } from '../shared/utils/markers';
2625
import { isPromise } from '../shared/utils/promises';
27-
import { qDev } from '../shared/utils/qdev';
2826
import { SerializerSymbol } from '../shared/utils/serialize-utils';
2927
import type { ISsrNode, SSRContainer } from '../ssr/ssr-types';
3028
import { trackSignal, tryGetInvokeContext } from '../use/use-core';
3129
import { TaskFlags, isTask } from '../use/use-task';
3230
import { NEEDS_COMPUTATION, _EFFECT_BACK_REF } from './flags';
31+
import { SignalImpl } from './impl/signal-impl';
3332
import { type BackRef } from './signal-cleanup';
3433
import type { Signal } from './signal.public';
3534
import type { TargetType } from './store';
@@ -66,94 +65,6 @@ export const isSignal = (value: any): value is Signal<unknown> => {
6665
return value instanceof SignalImpl;
6766
};
6867

69-
export class SignalImpl<T = any> implements Signal<T> {
70-
$untrackedValue$: T;
71-
72-
/** Store a list of effects which are dependent on this signal. */
73-
$effects$: null | Set<EffectSubscription> = null;
74-
75-
$container$: Container | null = null;
76-
77-
constructor(container: Container | null, value: T) {
78-
this.$container$ = container;
79-
this.$untrackedValue$ = value;
80-
DEBUG && log('new', this);
81-
}
82-
83-
get untrackedValue() {
84-
return this.$untrackedValue$;
85-
}
86-
87-
// TODO: should we disallow setting the value directly?
88-
set untrackedValue(value: T) {
89-
this.$untrackedValue$ = value;
90-
}
91-
92-
get value() {
93-
const ctx = tryGetInvokeContext();
94-
if (ctx) {
95-
if (this.$container$ === null) {
96-
if (!ctx.$container$) {
97-
return this.untrackedValue;
98-
}
99-
// Grab the container now we have access to it
100-
this.$container$ = ctx.$container$;
101-
} else {
102-
assertTrue(
103-
!ctx.$container$ || ctx.$container$ === this.$container$,
104-
'Do not use signals across containers'
105-
);
106-
}
107-
const effectSubscriber = ctx.$effectSubscriber$;
108-
if (effectSubscriber) {
109-
const effects = (this.$effects$ ||= new Set());
110-
// Let's make sure that we have a reference to this effect.
111-
// Adding reference is essentially adding a subscription, so if the signal
112-
// changes we know who to notify.
113-
ensureContainsSubscription(effects, effectSubscriber);
114-
// But when effect is scheduled in needs to be able to know which signals
115-
// to unsubscribe from. So we need to store the reference from the effect back
116-
// to this signal.
117-
ensureContainsBackRef(effectSubscriber, this);
118-
addQrlToSerializationCtx(effectSubscriber, this.$container$);
119-
DEBUG && log('read->sub', pad('\n' + this.toString(), ' '));
120-
}
121-
}
122-
return this.untrackedValue;
123-
}
124-
set value(value) {
125-
if (value !== this.$untrackedValue$) {
126-
DEBUG &&
127-
log('Signal.set', this.$untrackedValue$, '->', value, pad('\n' + this.toString(), ' '));
128-
this.$untrackedValue$ = value;
129-
triggerEffects(this.$container$, this, this.$effects$);
130-
}
131-
}
132-
133-
// prevent accidental use as value
134-
valueOf() {
135-
if (qDev) {
136-
throw qError(QError.cannotCoerceSignal);
137-
}
138-
}
139-
140-
toString() {
141-
if (isDev) {
142-
return (
143-
`[${this.constructor.name}${(this as any).$flags$ & SignalFlags.INVALID ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
144-
(Array.from(this.$effects$ || [])
145-
.map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' '))
146-
.join('\n') || '')
147-
);
148-
} else {
149-
return this.constructor.name;
150-
}
151-
}
152-
toJSON() {
153-
return { value: this.$untrackedValue$ };
154-
}
155-
}
156-
15768
export const ensureContainsSubscription = (
15869
array: Set<EffectSubscription>,
15970
effectSubscription: EffectSubscription

packages/qwik/src/core/signal/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { VNode } from '../client/types';
22
import type { ISsrNode } from '../ssr/ssr-types';
33
import type { Task } from '../use/use-task';
4-
import type { SignalImpl } from './signal';
54
import type { SubscriptionData } from './subscription-data';
65
import type { ReadonlySignal } from './signal.public';
76
import type { TargetType } from './store';
7+
import type { SignalImpl } from './impl/signal-impl';
88

99
export interface InternalReadonlySignal<T = unknown> extends ReadonlySignal<T> {
1010
readonly untrackedValue: T;

packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { type NormalizedQwikPluginOptions, parseId, QWIK_HANDLERS_ID } from './p
1313
import type { QwikViteDevResponse } from './vite';
1414
import { VITE_ERROR_OVERLAY_STYLES } from './vite-error';
1515
import { formatError } from './vite-utils';
16-
import { SYNC_QRL } from 'packages/qwik/src/server/qwik-copy';
16+
import { SYNC_QRL } from 'packages/qwik/src/core/shared/qrl/qrl-utils';
1717

1818
function getOrigin(req: IncomingMessage) {
1919
const { PROTOCOL_HEADER, HOST_HEADER } = process.env;

0 commit comments

Comments
 (0)