Skip to content

Commit 1e2eb0b

Browse files
author
Gyles Fohl
committed
fix(react): avoid bundling hydrate module into client graph
1 parent 27cab4e commit 1e2eb0b

6 files changed

Lines changed: 34 additions & 27 deletions

File tree

example-project/component-library-react/src/components.server.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const MyButton: StencilReactComponent<MyButtonElement, MyButtonEvents, Co
6363
target: 'target',
6464
type: 'type'
6565
},
66-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
66+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
6767
clientModule: clientComponents.MyButton as StencilReactComponent<MyButtonElement, MyButtonEvents, Components.MyButton>,
6868
serializeShadowRoot,
6969
getTagTransformer
@@ -91,7 +91,7 @@ export const MyButtonScoped: StencilReactComponent<MyButtonScopedElement, MyButt
9191
target: 'target',
9292
type: 'type'
9393
},
94-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
94+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
9595
clientModule: clientComponents.MyButtonScoped as StencilReactComponent<MyButtonScopedElement, MyButtonScopedEvents, Components.MyButtonScoped>,
9696
serializeShadowRoot,
9797
getTagTransformer
@@ -117,7 +117,7 @@ export const MyCheckbox: StencilReactComponent<MyCheckboxElement, MyCheckboxEven
117117
justify: 'justify',
118118
alignment: 'alignment'
119119
},
120-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
120+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
121121
clientModule: clientComponents.MyCheckbox as StencilReactComponent<MyCheckboxElement, MyCheckboxEvents, Components.MyCheckbox>,
122122
serializeShadowRoot,
123123
getTagTransformer
@@ -128,7 +128,7 @@ export type MyComplexPropsEvents = NonNullable<unknown>;
128128
export const MyComplexProps: StencilReactComponent<MyComplexPropsElement, MyComplexPropsEvents, Components.MyComplexProps> = /*@__PURE__*/ createComponent<MyComplexPropsElement, MyComplexPropsEvents, Components.MyComplexProps>({
129129
tagName: 'my-complex-props',
130130
properties: { grault: 'grault' },
131-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
131+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
132132
clientModule: clientComponents.MyComplexProps as StencilReactComponent<MyComplexPropsElement, MyComplexPropsEvents, Components.MyComplexProps>,
133133
serializeShadowRoot,
134134
getTagTransformer
@@ -139,7 +139,7 @@ export type MyComplexPropsScopedEvents = NonNullable<unknown>;
139139
export const MyComplexPropsScoped: StencilReactComponent<MyComplexPropsScopedElement, MyComplexPropsScopedEvents, Components.MyComplexPropsScoped> = /*@__PURE__*/ createComponent<MyComplexPropsScopedElement, MyComplexPropsScopedEvents, Components.MyComplexPropsScoped>({
140140
tagName: 'my-complex-props-scoped',
141141
properties: { grault: 'grault' },
142-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
142+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
143143
clientModule: clientComponents.MyComplexPropsScoped as StencilReactComponent<MyComplexPropsScopedElement, MyComplexPropsScopedEvents, Components.MyComplexPropsScoped>,
144144
serializeShadowRoot,
145145
getTagTransformer
@@ -154,7 +154,7 @@ export const MyComponent: StencilReactComponent<MyComponentElement, MyComponentE
154154
middleName: 'middle-name',
155155
last: 'last'
156156
},
157-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
157+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
158158
clientModule: clientComponents.MyComponent as StencilReactComponent<MyComponentElement, MyComponentEvents, Components.MyComponent>,
159159
serializeShadowRoot,
160160
getTagTransformer
@@ -165,7 +165,7 @@ export type MyComponentDelegatesFocusEvents = NonNullable<unknown>;
165165
export const MyComponentDelegatesFocus: StencilReactComponent<MyComponentDelegatesFocusElement, MyComponentDelegatesFocusEvents, Components.MyComponentDelegatesFocus> = /*@__PURE__*/ createComponent<MyComponentDelegatesFocusElement, MyComponentDelegatesFocusEvents, Components.MyComponentDelegatesFocus>({
166166
tagName: 'my-component-delegates-focus',
167167
properties: {},
168-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
168+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
169169
clientModule: clientComponents.MyComponentDelegatesFocus as StencilReactComponent<MyComponentDelegatesFocusElement, MyComponentDelegatesFocusEvents, Components.MyComponentDelegatesFocus>,
170170
serializeShadowRoot,
171171
getTagTransformer
@@ -180,7 +180,7 @@ export const MyComponentScoped: StencilReactComponent<MyComponentScopedElement,
180180
middleName: 'middle-name',
181181
last: 'last'
182182
},
183-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
183+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
184184
clientModule: clientComponents.MyComponentScoped as StencilReactComponent<MyComponentScopedElement, MyComponentScopedEvents, Components.MyComponentScoped>,
185185
serializeShadowRoot,
186186
getTagTransformer
@@ -191,7 +191,7 @@ export type MyCounterEvents = { onCount: EventName<MyCounterCustomEvent<number>>
191191
export const MyCounter: StencilReactComponent<MyCounterElement, MyCounterEvents, Components.MyCounter> = /*@__PURE__*/ createComponent<MyCounterElement, MyCounterEvents, Components.MyCounter>({
192192
tagName: 'my-counter',
193193
properties: { startValue: 'start-value' },
194-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
194+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
195195
clientModule: clientComponents.MyCounter as StencilReactComponent<MyCounterElement, MyCounterEvents, Components.MyCounter>,
196196
serializeShadowRoot,
197197
getTagTransformer
@@ -234,7 +234,7 @@ export const MyInput: StencilReactComponent<MyInputElement, MyInputEvents, Compo
234234
type: 'type',
235235
value: 'value'
236236
},
237-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
237+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
238238
clientModule: clientComponents.MyInput as StencilReactComponent<MyInputElement, MyInputEvents, Components.MyInput>,
239239
serializeShadowRoot,
240240
getTagTransformer
@@ -277,7 +277,7 @@ export const MyInputScoped: StencilReactComponent<MyInputScopedElement, MyInputS
277277
type: 'type',
278278
value: 'value'
279279
},
280-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
280+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
281281
clientModule: clientComponents.MyInputScoped as StencilReactComponent<MyInputScopedElement, MyInputScopedEvents, Components.MyInputScoped>,
282282
serializeShadowRoot,
283283
getTagTransformer
@@ -288,7 +288,7 @@ export type MyListEvents = NonNullable<unknown>;
288288
export const MyList: StencilReactComponent<MyListElement, MyListEvents, Components.MyList> = /*@__PURE__*/ createComponent<MyListElement, MyListEvents, Components.MyList>({
289289
tagName: 'my-list',
290290
properties: {},
291-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
291+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
292292
clientModule: clientComponents.MyList as StencilReactComponent<MyListElement, MyListEvents, Components.MyList>,
293293
serializeShadowRoot,
294294
getTagTransformer
@@ -299,7 +299,7 @@ export type MyListItemEvents = NonNullable<unknown>;
299299
export const MyListItem: StencilReactComponent<MyListItemElement, MyListItemEvents, Components.MyListItem> = /*@__PURE__*/ createComponent<MyListItemElement, MyListItemEvents, Components.MyListItem>({
300300
tagName: 'my-list-item',
301301
properties: {},
302-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
302+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
303303
clientModule: clientComponents.MyListItem as StencilReactComponent<MyListItemElement, MyListItemEvents, Components.MyListItem>,
304304
serializeShadowRoot,
305305
getTagTransformer
@@ -310,7 +310,7 @@ export type MyListItemScopedEvents = NonNullable<unknown>;
310310
export const MyListItemScoped: StencilReactComponent<MyListItemScopedElement, MyListItemScopedEvents, Components.MyListItemScoped> = /*@__PURE__*/ createComponent<MyListItemScopedElement, MyListItemScopedEvents, Components.MyListItemScoped>({
311311
tagName: 'my-list-item-scoped',
312312
properties: {},
313-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
313+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
314314
clientModule: clientComponents.MyListItemScoped as StencilReactComponent<MyListItemScopedElement, MyListItemScopedEvents, Components.MyListItemScoped>,
315315
serializeShadowRoot,
316316
getTagTransformer
@@ -321,7 +321,7 @@ export type MyListScopedEvents = NonNullable<unknown>;
321321
export const MyListScoped: StencilReactComponent<MyListScopedElement, MyListScopedEvents, Components.MyListScoped> = /*@__PURE__*/ createComponent<MyListScopedElement, MyListScopedEvents, Components.MyListScoped>({
322322
tagName: 'my-list-scoped',
323323
properties: {},
324-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
324+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
325325
clientModule: clientComponents.MyListScoped as StencilReactComponent<MyListScopedElement, MyListScopedEvents, Components.MyListScoped>,
326326
serializeShadowRoot,
327327
getTagTransformer
@@ -346,7 +346,7 @@ export const MyPopover: StencilReactComponent<MyPopoverElement, MyPopoverEvents,
346346
translucent: 'translucent',
347347
animated: 'animated'
348348
},
349-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
349+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
350350
clientModule: clientComponents.MyPopover as StencilReactComponent<MyPopoverElement, MyPopoverEvents, Components.MyPopover>,
351351
serializeShadowRoot,
352352
getTagTransformer
@@ -368,7 +368,7 @@ export const MyRadio: StencilReactComponent<MyRadioElement, MyRadioEvents, Compo
368368
justify: 'justify',
369369
alignment: 'alignment'
370370
},
371-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
371+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
372372
clientModule: clientComponents.MyRadio as StencilReactComponent<MyRadioElement, MyRadioEvents, Components.MyRadio>,
373373
serializeShadowRoot,
374374
getTagTransformer
@@ -384,7 +384,7 @@ export const MyRadioGroup: StencilReactComponent<MyRadioGroupElement, MyRadioGro
384384
name: 'name',
385385
value: 'value'
386386
},
387-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
387+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
388388
clientModule: clientComponents.MyRadioGroup as StencilReactComponent<MyRadioGroupElement, MyRadioGroupEvents, Components.MyRadioGroup>,
389389
serializeShadowRoot,
390390
getTagTransformer
@@ -412,7 +412,7 @@ export const MyRange: StencilReactComponent<MyRangeElement, MyRangeEvents, Compo
412412
disabled: 'disabled',
413413
value: 'value'
414414
},
415-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
415+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
416416
clientModule: clientComponents.MyRange as StencilReactComponent<MyRangeElement, MyRangeEvents, Components.MyRange>,
417417
serializeShadowRoot,
418418
getTagTransformer
@@ -423,7 +423,7 @@ export type MyToggleEvents = NonNullable<unknown>;
423423
export const MyToggle: StencilReactComponent<MyToggleElement, MyToggleEvents, Components.MyToggle> = /*@__PURE__*/ createComponent<MyToggleElement, MyToggleEvents, Components.MyToggle>({
424424
tagName: 'my-toggle',
425425
properties: {},
426-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
426+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
427427
clientModule: clientComponents.MyToggle as StencilReactComponent<MyToggleElement, MyToggleEvents, Components.MyToggle>,
428428
serializeShadowRoot,
429429
getTagTransformer
@@ -434,7 +434,7 @@ export type MyToggleContentEvents = NonNullable<unknown>;
434434
export const MyToggleContent: StencilReactComponent<MyToggleContentElement, MyToggleContentEvents, Components.MyToggleContent> = /*@__PURE__*/ createComponent<MyToggleContentElement, MyToggleContentEvents, Components.MyToggleContent>({
435435
tagName: 'my-toggle-content',
436436
properties: { visible: 'visible' },
437-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
437+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
438438
clientModule: clientComponents.MyToggleContent as StencilReactComponent<MyToggleContentElement, MyToggleContentEvents, Components.MyToggleContent>,
439439
serializeShadowRoot,
440440
getTagTransformer
@@ -445,7 +445,7 @@ export type MyTransformTestEvents = NonNullable<unknown>;
445445
export const MyTransformTest: StencilReactComponent<MyTransformTestElement, MyTransformTestEvents, Components.MyTransformTest> = /*@__PURE__*/ createComponent<MyTransformTestElement, MyTransformTestEvents, Components.MyTransformTest>({
446446
tagName: 'my-transform-test',
447447
properties: { message: 'message' },
448-
hydrateModule: import('component-library/hydrate') as Promise<HydrateModule>,
448+
hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise<HydrateModule>) : undefined,
449449
clientModule: clientComponents.MyTransformTest as StencilReactComponent<MyTransformTestElement, MyTransformTestEvents, Components.MyTransformTest>,
450450
serializeShadowRoot,
451451
getTagTransformer

example-project/next-15-runtime-based/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"type": "module",
55
"scripts": {
66
"build": "next build",
7-
"start": "next dev -p 3002",
7+
"dev": "next dev -p 3002",
8+
"start": "next start -p 3001",
89
"lint": "next lint",
910
"prettier": "prettier --write --print-width 80 \"*.mjs\" \"*.json\" \"src/**/*.tsx\" \"*.ts\"",
1011
"test": "wdio run ./wdio.conf.ts"

packages/react/src/create-component-wrappers.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ export const MyComponent: StencilReactComponent<MyComponentElement, MyComponentE
283283
.toContain(`export const MyComponent: StencilReactComponent<MyComponentElement, MyComponentEvents, Components.MyComponent> = /*@__PURE__*/ createComponent<MyComponentElement, MyComponentEvents, Components.MyComponent>({
284284
tagName: 'my-component',
285285
properties: { hasMaxLength: 'max-length' },
286-
hydrateModule: import('my-package/hydrate') as Promise<HydrateModule>,
286+
hydrateModule: typeof window === 'undefined' ? (import('my-package/hydrate') as Promise<HydrateModule>) : undefined,
287287
clientModule: clientComponents.MyComponent as StencilReactComponent<MyComponentElement, MyComponentEvents, Components.MyComponent>,
288288
serializeShadowRoot
289289
});

packages/react/src/create-stencil-react-components.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ describe('createStencilReactComponents', () => {
263263
);
264264
expect(result).toContain(`tagName: 'my-component',
265265
properties: { value: 'value' },
266-
hydrateModule: import('my-package/hydrate') as Promise<HydrateModule>,
266+
hydrateModule: typeof window === 'undefined' ? (import('my-package/hydrate') as Promise<HydrateModule>) : undefined,
267267
clientModule: clientComponents.MyComponent as StencilReactComponent<MyComponentElement, MyComponentEvents, Components.MyComponent>,
268268
serializeShadowRoot`);
269269
});

packages/react/src/create-stencil-react-components.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ import type { Components } from "${stencilPackageName}/${customElementsDir}";
204204
.filter((prop) => Boolean(prop.attribute))
205205
.map((e) => `${e.name}: '${e.attribute}'`)
206206
.join(',\n')}},
207-
hydrateModule: import('${hydrateModule}') as Promise<HydrateModule>,
207+
hydrateModule: typeof window === 'undefined' ? (import('${hydrateModule}') as Promise<HydrateModule>) : undefined,
208208
clientModule: clientComponents.${reactTagName} as StencilReactComponent<${componentElement}, ${componentEventNamesType}, Components.${reactTagName}>,
209209
serializeShadowRoot${getTagTransformerParam}
210210
})`;

packages/react/src/runtime/ssr.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ type CreateComponentForSSROptions<
457457
E extends EventNames = {},
458458
C = Omit<I, keyof HTMLElement>,
459459
> = Omit<CreateComponentForServerSideRenderingOptions, 'renderToString' | 'serializeProperty' | 'transformTag'> & {
460-
hydrateModule: Promise<HydrateModule>;
460+
hydrateModule: Promise<HydrateModule> | undefined;
461461
transformTag?: (tag: string) => string;
462462
getTagTransformer?: () => ((tag: string) => string) | undefined;
463463
clientModule?: StencilReactComponent<I, E, C>;
@@ -498,6 +498,12 @@ export const createComponent = <I extends HTMLElement, E extends EventNames = {}
498498
* bundling them in the runtime and serving them in the browser.
499499
*/
500500
return (async (props: WebComponentProps<I>) => {
501+
if (!options.hydrateModule) {
502+
throw new Error(
503+
'`hydrateModule` is required when rendering a Stencil component on the server. ' +
504+
'This indicates a misconfiguration of the Stencil React output target.'
505+
);
506+
}
501507
let firstTime = false;
502508
if (!hydrateModuleCache) {
503509
hydrateModuleCache = await options.hydrateModule;

0 commit comments

Comments
 (0)