diff --git a/example-project/component-library-react/src/components.server.ts b/example-project/component-library-react/src/components.server.ts index d50c86b4..e78e16e4 100644 --- a/example-project/component-library-react/src/components.server.ts +++ b/example-project/component-library-react/src/components.server.ts @@ -63,7 +63,7 @@ export const MyButton: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyButton as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -91,7 +91,7 @@ export const MyButtonScoped: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyButtonScoped as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -117,7 +117,7 @@ export const MyCheckbox: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyCheckbox as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -128,7 +128,7 @@ export type MyComplexPropsEvents = NonNullable; export const MyComplexProps: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-complex-props', properties: { grault: 'grault' }, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyComplexProps as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -139,7 +139,7 @@ export type MyComplexPropsScopedEvents = NonNullable; export const MyComplexPropsScoped: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-complex-props-scoped', properties: { grault: 'grault' }, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyComplexPropsScoped as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -154,7 +154,7 @@ export const MyComponent: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyComponent as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -165,7 +165,7 @@ export type MyComponentDelegatesFocusEvents = NonNullable; export const MyComponentDelegatesFocus: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-component-delegates-focus', properties: {}, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyComponentDelegatesFocus as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -180,7 +180,7 @@ export const MyComponentScoped: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyComponentScoped as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -191,7 +191,7 @@ export type MyCounterEvents = { onCount: EventName> export const MyCounter: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-counter', properties: { startValue: 'start-value' }, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyCounter as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -234,7 +234,7 @@ export const MyInput: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyInput as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -277,7 +277,7 @@ export const MyInputScoped: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyInputScoped as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -288,7 +288,7 @@ export type MyListEvents = NonNullable; export const MyList: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-list', properties: {}, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyList as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -299,7 +299,7 @@ export type MyListItemEvents = NonNullable; export const MyListItem: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-list-item', properties: {}, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyListItem as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -310,7 +310,7 @@ export type MyListItemScopedEvents = NonNullable; export const MyListItemScoped: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-list-item-scoped', properties: {}, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyListItemScoped as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -321,7 +321,7 @@ export type MyListScopedEvents = NonNullable; export const MyListScoped: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-list-scoped', properties: {}, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyListScoped as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -346,7 +346,7 @@ export const MyPopover: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyPopover as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -368,7 +368,7 @@ export const MyRadio: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyRadio as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -384,7 +384,7 @@ export const MyRadioGroup: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyRadioGroup as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -412,7 +412,7 @@ export const MyRange: StencilReactComponent, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyRange as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -423,7 +423,7 @@ export type MyToggleEvents = NonNullable; export const MyToggle: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-toggle', properties: {}, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyToggle as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -434,7 +434,7 @@ export type MyToggleContentEvents = NonNullable; export const MyToggleContent: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-toggle-content', properties: { visible: 'visible' }, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyToggleContent as StencilReactComponent, serializeShadowRoot, getTagTransformer @@ -445,7 +445,7 @@ export type MyTransformTestEvents = NonNullable; export const MyTransformTest: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-transform-test', properties: { message: 'message' }, - hydrateModule: import('component-library/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('component-library/hydrate') as Promise) : undefined, clientModule: clientComponents.MyTransformTest as StencilReactComponent, serializeShadowRoot, getTagTransformer diff --git a/example-project/next-15-runtime-based/package.json b/example-project/next-15-runtime-based/package.json index 4207576b..c8fb2cbd 100644 --- a/example-project/next-15-runtime-based/package.json +++ b/example-project/next-15-runtime-based/package.json @@ -4,7 +4,8 @@ "type": "module", "scripts": { "build": "next build", - "start": "next dev -p 3002", + "dev": "next dev -p 3002", + "start": "next start -p 3001", "lint": "next lint", "prettier": "prettier --write --print-width 80 \"*.mjs\" \"*.json\" \"src/**/*.tsx\" \"*.ts\"", "test": "wdio run ./wdio.conf.ts" diff --git a/packages/react/src/create-component-wrappers.test.ts b/packages/react/src/create-component-wrappers.test.ts index c4132440..f4386ab0 100644 --- a/packages/react/src/create-component-wrappers.test.ts +++ b/packages/react/src/create-component-wrappers.test.ts @@ -283,7 +283,7 @@ export const MyComponent: StencilReactComponent = /*@__PURE__*/ createComponent({ tagName: 'my-component', properties: { hasMaxLength: 'max-length' }, - hydrateModule: import('my-package/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('my-package/hydrate') as Promise) : undefined, clientModule: clientComponents.MyComponent as StencilReactComponent, serializeShadowRoot }); diff --git a/packages/react/src/create-stencil-react-components.test.ts b/packages/react/src/create-stencil-react-components.test.ts index fec67fb5..1bb4c4f8 100644 --- a/packages/react/src/create-stencil-react-components.test.ts +++ b/packages/react/src/create-stencil-react-components.test.ts @@ -263,7 +263,7 @@ describe('createStencilReactComponents', () => { ); expect(result).toContain(`tagName: 'my-component', properties: { value: 'value' }, - hydrateModule: import('my-package/hydrate') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('my-package/hydrate') as Promise) : undefined, clientModule: clientComponents.MyComponent as StencilReactComponent, serializeShadowRoot`); }); diff --git a/packages/react/src/create-stencil-react-components.ts b/packages/react/src/create-stencil-react-components.ts index ef1594ae..2b592dcc 100644 --- a/packages/react/src/create-stencil-react-components.ts +++ b/packages/react/src/create-stencil-react-components.ts @@ -204,7 +204,7 @@ import type { Components } from "${stencilPackageName}/${customElementsDir}"; .filter((prop) => Boolean(prop.attribute)) .map((e) => `${e.name}: '${e.attribute}'`) .join(',\n')}}, - hydrateModule: import('${hydrateModule}') as Promise, + hydrateModule: typeof window === 'undefined' ? (import('${hydrateModule}') as Promise) : undefined, clientModule: clientComponents.${reactTagName} as StencilReactComponent<${componentElement}, ${componentEventNamesType}, Components.${reactTagName}>, serializeShadowRoot${getTagTransformerParam} })`; diff --git a/packages/react/src/runtime/ssr.tsx b/packages/react/src/runtime/ssr.tsx index b0d6b7b9..edba609a 100644 --- a/packages/react/src/runtime/ssr.tsx +++ b/packages/react/src/runtime/ssr.tsx @@ -457,7 +457,7 @@ type CreateComponentForSSROptions< E extends EventNames = {}, C = Omit, > = Omit & { - hydrateModule: Promise; + hydrateModule: Promise | undefined; transformTag?: (tag: string) => string; getTagTransformer?: () => ((tag: string) => string) | undefined; clientModule?: StencilReactComponent; @@ -498,6 +498,12 @@ export const createComponent = ) => { + if (!options.hydrateModule) { + throw new Error( + '`hydrateModule` is required when rendering a Stencil component on the server. ' + + 'This indicates a misconfiguration of the Stencil React output target.' + ); + } let firstTime = false; if (!hydrateModuleCache) { hydrateModuleCache = await options.hydrateModule;