Skip to content

Commit f640012

Browse files
authored
Merge pull request #7432 from QwikDev/v2-refactor-use-id
fix: change client side generated ID to start with build base
2 parents 4d5a0c5 + 1d54b16 commit f640012

File tree

11 files changed

+37
-27
lines changed

11 files changed

+37
-27
lines changed

.changeset/fair-cameras-boil.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik.dev/core': patch
3+
---
4+
5+
fix: change client side generated ID to start with build base and add convert first character to letter if it is starting from number

packages/qwik/src/core/api.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ export interface ClientContainer extends Container {
3636
// (undocumented)
3737
parseQRL<T = unknown>(qrl: string): QRL<T>;
3838
// (undocumented)
39-
qBase: string;
40-
// (undocumented)
4139
qContainer: string;
4240
// (undocumented)
4341
qManifestHash: string;
@@ -211,8 +209,6 @@ class DomContainer extends _SharedContainer implements ClientContainer {
211209
// (undocumented)
212210
parseQRL<T = unknown>(qrl: string): QRL<T>;
213211
// (undocumented)
214-
qBase: string;
215-
// (undocumented)
216212
qContainer: string;
217213
// (undocumented)
218214
qManifestHash: string;
@@ -846,6 +842,8 @@ export abstract class _SharedContainer implements Container {
846842
// (undocumented)
847843
abstract $appendStyle$(content: string, styleId: string, host: HostElement, scoped: boolean): void;
848844
// (undocumented)
845+
$buildBase$: string | null;
846+
// (undocumented)
849847
$currentUniqueId$: number;
850848
// (undocumented)
851849
readonly $getObjectById$: (id: number | string) => any;

packages/qwik/src/core/client/dom-container.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
USE_ON_LOCAL_SEQ_IDX,
3131
getQFuncs,
3232
QLocaleAttr,
33+
QManifestHashAttr,
3334
} from '../shared/utils/markers';
3435
import { isPromise } from '../shared/utils/promises';
3536
import { isSlotProp } from '../shared/utils/prop';
@@ -121,7 +122,6 @@ export const isDomContainer = (container: any): container is DomContainer => {
121122
export class DomContainer extends _SharedContainer implements IClientContainer {
122123
public element: ContainerElement;
123124
public qContainer: string;
124-
public qBase: string;
125125
public qManifestHash: string;
126126
public rootVNode: ElementVNode;
127127
public document: QDocument;
@@ -159,10 +159,9 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
159159
];
160160
this.document = element.ownerDocument as QDocument;
161161
this.element = element;
162-
this.qBase = element.getAttribute(QBaseAttr)!;
162+
this.$buildBase$ = element.getAttribute(QBaseAttr)!;
163163
this.$instanceHash$ = element.getAttribute(QInstanceAttr)!;
164-
// this.containerState = createContainerState(element, this.qBase);
165-
this.qManifestHash = element.getAttribute('q:manifest-hash')!;
164+
this.qManifestHash = element.getAttribute(QManifestHashAttr)!;
166165
this.rootVNode = vnode_newUnMaterializedElement(this.element);
167166
// These are here to initialize all properties at once for single class transition
168167
this.$rawStateData$ = null!;

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

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export interface ClientContainer extends Container {
1313
document: QDocument;
1414
element: ContainerElement;
1515
qContainer: string;
16-
qBase: string;
1716
$locale$: string;
1817
qManifestHash: string;
1918
rootVNode: ElementVNode;

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

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export abstract class _SharedContainer implements Container {
2121
$serverData$: Record<string, any>;
2222
$currentUniqueId$ = 0;
2323
$instanceHash$: string | null = null;
24+
$buildBase$: string | null = null;
2425

2526
constructor(
2627
scheduleDrain: () => void,

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

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface Container {
2222
readonly $getObjectById$: (id: number | string) => any;
2323
readonly $serverData$: Record<string, any>;
2424
$currentUniqueId$: number;
25+
$buildBase$: string | null;
2526

2627
handleError(err: any, $host$: HostElement): void;
2728
getParentHost(host: HostElement): HostElement | null;

packages/qwik/src/core/ssr/ssr-types.ts

-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ export interface SSRContainer extends Container {
6060
readonly prefetchResources: PrefetchResource[];
6161
readonly serializationCtx: SerializationContext;
6262
readonly symbolToChunkResolver: SymbolToChunkResolver;
63-
readonly buildBase: string;
6463
additionalHeadNodes: Array<JSXNodeInternal>;
6564
additionalBodyNodes: Array<JSXNodeInternal>;
6665
unclaimedProjectionComponentFrameQueue: ISsrComponentFrame[];

packages/qwik/src/core/tests/use-id.spec.tsx

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { component$, componentQrl, inlinedQrl, useId } from '@qwik.dev/core';
22
import { describe, expect, it } from 'vitest';
3-
import { domRender, ssrRenderToDom } from '../../testing/rendering.unit-util';
4-
import '../../testing/vdom-diff.unit-util';
3+
import { domRender, ssrRenderToDom } from '@qwik.dev/core/testing';
54

65
const debug = false; //true;
76
Error.stackTraceLimit = 100;
@@ -21,7 +20,7 @@ describe.each([
2120
inlinedQrl(() => {
2221
const id = useId();
2322
return <div id="cmp2">{id}</div>;
24-
}, 's_cmp2Hash')
23+
}, 's_2cmpHash')
2524
);
2625

2726
const Parent = component$(() => {
@@ -34,7 +33,12 @@ describe.each([
3433
});
3534

3635
const { document } = await render(<Parent />, { debug });
37-
expect(document.querySelector('#cmp1')?.textContent).toMatch(/^\w*-cmpHash-0*$/);
38-
expect(document.querySelector('#cmp2')?.textContent).toMatch(/^\w*-cmp2Hash-1*$/);
36+
if (render === ssrRenderToDom) {
37+
expect(document.querySelector('#cmp1')?.textContent).toMatch(/^\w{3}cmp0$/);
38+
expect(document.querySelector('#cmp2')?.textContent).toMatch(/^\w{3}2cm1$/);
39+
} else {
40+
expect(document.querySelector('#cmp1')?.textContent).toMatch(/^cmp0$/);
41+
expect(document.querySelector('#cmp2')?.textContent).toMatch(/^Ccm1$/);
42+
}
3943
});
4044
});

packages/qwik/src/core/use/use-id.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import type { QRL } from '..';
22
import { hashCode } from '../shared/utils/hash_code';
33
import { OnRenderProp } from '../shared/utils/markers';
4-
import { isDomContainer } from '../client/dom-container';
5-
import type { SSRContainer } from '../ssr/ssr-types';
64
import { useSequentialScope } from './use-sequential-scope';
75
import { getNextUniqueIndex } from '../shared/utils/unique-index-generator';
86

@@ -12,13 +10,20 @@ export const useId = (): string => {
1210
if (val != null) {
1311
return val;
1412
}
15-
const containerBase = isDomContainer(iCtx.$container$)
16-
? ''
17-
: (iCtx.$container$ as SSRContainer).buildBase || '';
18-
const base = containerBase ? hashCode(containerBase) : '';
13+
const containerBase = iCtx.$container$.$buildBase$ || '';
14+
const base = containerBase ? hashCode(containerBase).substring(0, 3) : '';
1915
const componentQrl = iCtx.$container$.getHostProp<QRL>(iCtx.$hostElement$, OnRenderProp);
20-
const hash = componentQrl?.getHash() || '';
16+
const hash = componentQrl?.getHash().substring(0, 3) || '';
2117
const counter = getNextUniqueIndex(iCtx.$container$) || '';
22-
const id = `${base}-${hash}-${counter}`; // If no base and no hash, then "--#"
18+
let id = `${base}${hash}${counter}`;
19+
20+
let firstChar = id.charCodeAt(0);
21+
// convert first char to letter if starts with a number, because CSS does not allow class names to start with a number
22+
if (firstChar >= 48 /* 0 */ && firstChar <= 57 /* 9 */) {
23+
// 48 is char code for '0', 65 is char code for 'A'
24+
// 65 - 48 = 17, so we add 17 to the char code of the first char to convert it to a letter
25+
firstChar += 17;
26+
id = String.fromCharCode(firstChar) + id.substring(1);
27+
}
2328
return set(id);
2429
};

packages/qwik/src/server/prefetch-implementation.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function prefetchUrlsEvent2(
5151
scriptAttrs.push('nonce', nonce);
5252
}
5353
container.openElement('script', null, scriptAttrs);
54-
container.writer.write(prefetchUrlsEventScript(container.buildBase, prefetchResources));
54+
container.writer.write(prefetchUrlsEventScript(container.$buildBase$ || '', prefetchResources));
5555
container.writer.write(
5656
`;document.dispatchEvent(new CustomEvent('qprefetch', {detail:{links: [location.pathname]}}))`
5757
);

packages/qwik/src/server/ssr-container.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ class SSRContainer extends _SharedContainer implements ISSRContainer {
176176
public tag: string;
177177
public writer: StreamWriter;
178178
public timing: RenderToStreamResult['timing'];
179-
public buildBase: string;
180179
public resolvedManifest: ResolvedManifest;
181180
public symbolToChunkResolver: SymbolToChunkResolver;
182181
public renderOptions: RenderOptions;
@@ -247,7 +246,7 @@ class SSRContainer extends _SharedContainer implements ISSRContainer {
247246
this.tag = opts.tagName;
248247
this.writer = opts.writer;
249248
this.timing = opts.timing;
250-
this.buildBase = opts.buildBase;
249+
this.$buildBase$ = opts.buildBase;
251250
this.resolvedManifest = opts.resolvedManifest;
252251
this.renderOptions = opts.renderOptions;
253252

@@ -325,7 +324,7 @@ class SSRContainer extends _SharedContainer implements ISSRContainer {
325324
containerAttributes[QRuntimeAttr] = '2';
326325
containerAttributes[QVersionAttr] = this.$version$ ?? 'dev';
327326
containerAttributes[QRenderAttr] = (qRender ? qRender + '-' : '') + (isDev ? 'ssr-dev' : 'ssr');
328-
containerAttributes[QBaseAttr] = this.buildBase || '';
327+
containerAttributes[QBaseAttr] = this.$buildBase$ || '';
329328
containerAttributes[QLocaleAttr] = this.$locale$;
330329
containerAttributes[QManifestHashAttr] = this.resolvedManifest.manifest.manifestHash;
331330
containerAttributes[QInstanceAttr] = this.$instanceHash$;

0 commit comments

Comments
 (0)