vike-react 0.5.11 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,4 +8,4 @@ declare function ClientOnly<T>({ load, children, fallback, deps, }: {
8
8
  children: (Component: React.ComponentType<T>) => ReactNode;
9
9
  fallback: ReactNode;
10
10
  deps?: Parameters<typeof useEffect>[1];
11
- }): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
11
+ }): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
@@ -1,4 +1,5 @@
1
1
  export { Head };
2
+ import type React from 'react';
2
3
  /**
3
4
  * Add arbitrary `<head>` tags.
4
5
  *
package/dist/config.d.ts CHANGED
@@ -145,6 +145,10 @@ declare const config: {
145
145
  client: true;
146
146
  };
147
147
  };
148
+ react: {
149
+ cumulative: true;
150
+ env: {};
151
+ };
148
152
  };
149
153
  };
150
154
  import './types/Config.js';
package/dist/config.js CHANGED
@@ -106,6 +106,10 @@ const config = {
106
106
  Loading: {
107
107
  env: { server: true, client: true },
108
108
  },
109
+ react: {
110
+ cumulative: true,
111
+ env: {},
112
+ },
109
113
  },
110
114
  };
111
115
  // @eject-remove start
@@ -1,9 +1,10 @@
1
1
  export { useConfig };
2
2
  import { usePageContext } from '../usePageContext.js';
3
3
  import { getPageContext } from 'vike/getPageContext';
4
- import { useStream } from 'react-streaming';
4
+ import { useStreamOptional } from 'react-streaming';
5
5
  import { objectKeys } from '../../utils/objectKeys.js';
6
6
  import { includes } from '../../utils/includes.js';
7
+ import { assert } from '../../utils/assert.js';
7
8
  import { configsCumulative } from './configsCumulative.js';
8
9
  /**
9
10
  * Set configurations inside components and Vike hooks.
@@ -17,12 +18,13 @@ function useConfig() {
17
18
  return (config) => setPageContextConfigFromHook(config, pageContext);
18
19
  // Component
19
20
  pageContext = usePageContext();
20
- const stream = useStream();
21
+ const stream = useStreamOptional();
21
22
  return (config) => {
22
23
  if (!pageContext._headAlreadySet) {
23
24
  setPageContextConfigFromHook(config, pageContext);
24
25
  }
25
26
  else {
27
+ assert(stream);
26
28
  // <head> already sent to the browser => send DOM-manipulating scripts during HTML streaming
27
29
  apply(config, stream);
28
30
  }
@@ -6,6 +6,7 @@ import { getPageElement } from './getPageElement.js';
6
6
  import './styles.css';
7
7
  import { callCumulativeHooks } from '../utils/callCumulativeHooks.js';
8
8
  import { applyHeadSettings } from './applyHeadSettings.js';
9
+ import { resolveReactOptions } from './resolveReactOptions.js';
9
10
  let root;
10
11
  const onRenderClient = async (pageContext) => {
11
12
  pageContext._headAlreadySet = pageContext.isHydration;
@@ -14,27 +15,22 @@ const onRenderClient = async (pageContext) => {
14
15
  await callCumulativeHooks(pageContext.config.onBeforeRenderClient, pageContext);
15
16
  const { page, renderPromise } = getPageElement(pageContext);
16
17
  pageContext.page = page;
17
- // TODO: implement this? So that, upon errors, onRenderClient() throws an error and Vike can render the error. As of April 2024 it isn't released yet.
18
+ // TODO: implement this? So that, upon errors, onRenderClient() throws an error and Vike can render the error page. As of April 2024 it isn't released yet.
18
19
  // - https://react-dev-git-fork-rickhanlonii-rh-root-options-fbopensource.vercel.app/reference/react-dom/client/createRoot#show-a-dialog-for-uncaught-errors
19
20
  // - https://react-dev-git-fork-rickhanlonii-rh-root-options-fbopensource.vercel.app/reference/react-dom/client/hydrateRoot#show-a-dialog-for-uncaught-errors
20
21
  const onUncaughtError = (_error, _errorInfo) => { };
21
22
  const container = document.getElementById('root');
23
+ const { hydrateRootOptions, createRootOptions } = resolveReactOptions(pageContext);
22
24
  if (pageContext.isHydration &&
23
25
  // Whether the page was [Server-Side Rendered](https://vike.dev/ssr).
24
26
  container.innerHTML !== '') {
25
27
  // First render while using SSR, i.e. [hydration](https://vike.dev/hydration)
26
- root = ReactDOM.hydrateRoot(container, page, {
27
- // @ts-expect-error
28
- onUncaughtError,
29
- });
28
+ root = ReactDOM.hydrateRoot(container, page, hydrateRootOptions);
30
29
  }
31
30
  else {
32
31
  if (!root) {
33
32
  // First render without SSR
34
- root = ReactDOM.createRoot(container, {
35
- // @ts-expect-error
36
- onUncaughtError,
37
- });
33
+ root = ReactDOM.createRoot(container, createRootOptions);
38
34
  }
39
35
  root.render(page);
40
36
  }
@@ -10,6 +10,7 @@ import { getPageElement } from './getPageElement.js';
10
10
  import { isReactElement } from '../utils/isReactElement.js';
11
11
  import { getTagAttributesString } from '../utils/getTagAttributesString.js';
12
12
  import { callCumulativeHooks } from '../utils/callCumulativeHooks.js';
13
+ import { resolveReactOptions } from './resolveReactOptions.js';
13
14
  addEcosystemStamp();
14
15
  const onRenderHtml = async (pageContext) => {
15
16
  const pageHtml = await getPageHtml(pageContext);
@@ -36,11 +37,12 @@ async function getPageHtml(pageContext) {
36
37
  pageContext.page = getPageElement(pageContext).page;
37
38
  // https://github.com/vikejs/vike-react/issues/87#issuecomment-2488742744
38
39
  await callCumulativeHooks(pageContext.config.onBeforeRenderHtml, pageContext);
40
+ const { renderToStringOptions } = resolveReactOptions(pageContext);
39
41
  let pageHtml = '';
40
42
  if (pageContext.page) {
41
43
  const { stream, streamIsRequired } = pageContext.config;
42
44
  if (!stream && !streamIsRequired) {
43
- const pageHtmlString = renderToString(pageContext.page);
45
+ const pageHtmlString = renderToString(pageContext.page, renderToStringOptions);
44
46
  pageContext.pageHtmlString = pageHtmlString;
45
47
  pageHtml = dangerouslySkipEscape(pageHtmlString);
46
48
  }
@@ -0,0 +1,4 @@
1
+ export { resolveReactOptions };
2
+ import type { PageContext } from 'vike/types';
3
+ import type { ReactOptions } from '../types/Config.js';
4
+ declare function resolveReactOptions(pageContext: PageContext): ReactOptions;
@@ -0,0 +1,32 @@
1
+ export { resolveReactOptions };
2
+ import { isCallable } from '../utils/isCallable.js';
3
+ import { objectEntries } from '../utils/objectEntries.js';
4
+ function resolveReactOptions(pageContext) {
5
+ const optionsAcc = {};
6
+ (pageContext.config.react ?? []).forEach((valUnresolved) => {
7
+ const optionList = isCallable(valUnresolved) ? valUnresolved(pageContext) : valUnresolved;
8
+ if (!optionList)
9
+ return;
10
+ objectEntries(optionList).forEach(([fnName, options]) => {
11
+ if (!options)
12
+ return;
13
+ optionsAcc[fnName] ?? (optionsAcc[fnName] = {});
14
+ objectEntries(options).forEach(([key, val]) => {
15
+ var _a;
16
+ if (!isCallable(val)) {
17
+ // @ts-ignore
18
+ (_a = optionsAcc[fnName])[key] ?? (_a[key] = val);
19
+ }
20
+ else {
21
+ const valPrevious = optionsAcc[fnName][key];
22
+ // @ts-ignore
23
+ optionsAcc[fnName][key] = (...args) => {
24
+ valPrevious?.(...args);
25
+ val(...args);
26
+ };
27
+ }
28
+ });
29
+ });
30
+ });
31
+ return optionsAcc;
32
+ }
@@ -2,6 +2,9 @@ import type { ImportString, PageContextServer, PageContext, PageContextClient }
2
2
  import type { TagAttributes } from '../utils/getTagAttributesString.js';
3
3
  import type { Viewport } from '../integration/onRenderHtml.js';
4
4
  import type { ConfigsCumulative } from '../hooks/useConfig/configsCumulative.js';
5
+ import type React from 'react';
6
+ import type { HydrationOptions, RootOptions } from 'react-dom/client';
7
+ import type { ServerOptions } from 'react-dom/server';
5
8
  declare global {
6
9
  namespace Vike {
7
10
  interface Config {
@@ -186,6 +189,12 @@ declare global {
186
189
  * https://vike.dev/Loading
187
190
  */
188
191
  Loading?: Loading | ImportString;
192
+ /**
193
+ * Options passed to React functions such as `createRoot()` or `hydrateRoot()`.
194
+ *
195
+ * https://vike.dev/react-setting
196
+ */
197
+ react?: ReactOptions | ((pageContext: PageContext) => ReactOptions) | ImportString;
189
198
  }
190
199
  interface ConfigResolved {
191
200
  Wrapper?: Wrapper[];
@@ -199,6 +208,7 @@ declare global {
199
208
  onAfterRenderHtml?: Function[];
200
209
  onBeforeRenderClient?: Function[];
201
210
  onAfterRenderClient?: Function[];
211
+ react?: Exclude<Config['react'], ImportString>[];
202
212
  }
203
213
  }
204
214
  }
@@ -218,4 +228,9 @@ type PickWithoutGetter<T, K extends keyof T> = {
218
228
  };
219
229
  export type ConfigFromHook = PickWithoutGetter<Vike.Config, 'Head' | 'title' | 'description' | 'image' | 'favicon' | 'lang' | 'viewport' | 'bodyAttributes' | 'htmlAttributes'>;
220
230
  export type ConfigFromHookResolved = Omit<ConfigFromHook, ConfigsCumulative> & Pick<Vike.ConfigResolved, ConfigsCumulative>;
231
+ export type ReactOptions = {
232
+ hydrateRootOptions?: HydrationOptions;
233
+ createRootOptions?: RootOptions;
234
+ renderToStringOptions?: ServerOptions;
235
+ };
221
236
  export {};
@@ -1,2 +1,2 @@
1
1
  export { callCumulativeHooks };
2
- declare function callCumulativeHooks(values: undefined | unknown[], pageContext: Record<string, any>): Promise<unknown[]>;
2
+ declare function callCumulativeHooks<T>(values: undefined | T[], pageContext: Record<string, any>): Promise<(undefined | null | Exclude<T, Function>)[]>;
@@ -1,10 +1,11 @@
1
1
  export { callCumulativeHooks };
2
2
  import { providePageContext } from 'vike/getPageContext';
3
+ import { isCallable } from './isCallable.js';
3
4
  async function callCumulativeHooks(values, pageContext) {
4
5
  if (!values)
5
6
  return [];
6
7
  const valuesPromises = values.map((val) => {
7
- if (typeof val === 'function') {
8
+ if (isCallable(val)) {
8
9
  providePageContext(pageContext);
9
10
  // Hook
10
11
  return val(pageContext);
@@ -1 +1 @@
1
- export declare function isCallable<T extends (...args: unknown[]) => unknown>(thing: T | unknown): thing is T;
1
+ export declare function isCallable<T extends (...args: any[]) => any>(thing: T | unknown): thing is T;
@@ -0,0 +1,2 @@
1
+ /** Same as Object.entries() but with type inference */
2
+ export declare function objectEntries<T extends object>(obj: T): [keyof T, T[keyof T]][];
@@ -0,0 +1,5 @@
1
+ // https://stackoverflow.com/questions/60141960/typescript-key-value-relation-preserving-object-entries-type/75337277#75337277
2
+ /** Same as Object.entries() but with type inference */
3
+ export function objectEntries(obj) {
4
+ return Object.entries(obj);
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike-react",
3
- "version": "0.5.11",
3
+ "version": "0.5.13",
4
4
  "repository": "https://github.com/vikejs/vike-react",
5
5
  "type": "module",
6
6
  "exports": {
@@ -27,7 +27,7 @@
27
27
  "./__internal/integration/Loading": "./dist/integration/Loading.js"
28
28
  },
29
29
  "dependencies": {
30
- "react-streaming": "^0.3.42"
30
+ "react-streaming": "^0.3.48"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "react": ">=18.0.0",
@@ -38,15 +38,14 @@
38
38
  "@biomejs/biome": "^1.6.4",
39
39
  "@brillout/release-me": "^0.4.2",
40
40
  "@types/node": "^20.11.17",
41
- "@types/react": "^18.2.55",
42
- "@types/react-dom": "^18.2.19",
43
- "react": "^18.3.1",
44
- "react-dom": "^18.3.1",
45
- "react-streaming": "^0.3.43",
41
+ "@types/react": "^19.0.8",
42
+ "@types/react-dom": "^19.0.3",
43
+ "react": "^19.0.0",
44
+ "react-dom": "^19.0.0",
46
45
  "rimraf": "^5.0.5",
47
- "typescript": "^5.5.4",
48
- "vike": "^0.4.203",
49
- "vite": "^5.4.0"
46
+ "typescript": "^5.7.3",
47
+ "vike": "^0.4.223",
48
+ "vite": "^6.1.0"
50
49
  },
51
50
  "typesVersions": {
52
51
  "*": {