vike-react 0.6.5 → 0.6.7

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.
@@ -1,7 +1,7 @@
1
1
  export { ClientOnly };
2
2
  import React, { lazy, useEffect, useState, startTransition } from 'react';
3
3
  function ClientOnly({ load, children, fallback, deps = [], }) {
4
- // TODO/next-major: remove this file/export
4
+ // TO-DO/next-major: remove this file/export
5
5
  console.warn('[vike-react][warning] <ClientOnly> is deprecated: use clientOnly() instead https://vike.dev/clientOnly');
6
6
  const [Component, setComponent] = useState(null);
7
7
  useEffect(() => {
package/dist/config.js CHANGED
@@ -101,7 +101,7 @@ const config = {
101
101
  cumulative: true,
102
102
  env: { client: true, server: true },
103
103
  },
104
- // TODO/next-major: move to +react.js > strictMode ?
104
+ // TO-DO/next-major: move to +react.js > strictMode ?
105
105
  reactStrictMode: {
106
106
  env: { client: true, server: true },
107
107
  },
@@ -1,8 +1,8 @@
1
1
  export { usePageContext };
2
- export { PageContextProvider };
2
+ export { VikeReactProviderPageContext };
3
3
  import React from 'react';
4
4
  import type { PageContext } from 'vike/types';
5
- declare function PageContextProvider({ pageContext, children }: {
5
+ declare function VikeReactProviderPageContext({ pageContext, children, }: {
6
6
  pageContext: PageContext;
7
7
  children: React.ReactNode;
8
8
  }): React.JSX.Element;
@@ -1,11 +1,11 @@
1
1
  export { usePageContext };
2
- export { PageContextProvider };
2
+ export { VikeReactProviderPageContext };
3
3
  import React, { useContext } from 'react';
4
4
  import { getGlobalObject } from '../utils/getGlobalObject.js';
5
- const globalObject = getGlobalObject('PageContextProvider.ts', {
5
+ const globalObject = getGlobalObject('usePageContext.tsx', {
6
6
  reactContext: React.createContext(undefined),
7
7
  });
8
- function PageContextProvider({ pageContext, children }) {
8
+ function VikeReactProviderPageContext({ pageContext, children, }) {
9
9
  const { reactContext } = globalObject;
10
10
  return React.createElement(reactContext.Provider, { value: pageContext }, children);
11
11
  }
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- // TODO/next-major: remove this file/export
1
+ // TO-DO/next-major: remove this file/export
2
2
  console.warn("[vike-react][warning][deprecation] Replace `import vikeReact from 'vike-react'` with `import vikeReact from 'vike-react/config'` (typically in your /pages/+config.js)");
3
3
  export { default } from './config.js';
@@ -1,6 +1,6 @@
1
1
  declare const _default: {
2
- component: typeof LoadingComponent;
2
+ component: typeof VikeReactLoadingComponent;
3
3
  };
4
4
  export default _default;
5
5
  import React from 'react';
6
- declare function LoadingComponent(): React.JSX.Element;
6
+ declare function VikeReactLoadingComponent(): React.JSX.Element;
@@ -1,21 +1,27 @@
1
1
  export default {
2
- component: LoadingComponent,
2
+ component: VikeReactLoadingComponent,
3
3
  };
4
4
  import React from 'react';
5
- /* We can't import it here: https://github.com/vikejs/vike/issues/2460
6
- * - We import it inside onRenderClient.js instead.
7
- * - We'll be able to do it if Vite + Rolldown always transpiles the server-side.
8
- import './Loading.css'
9
- */
10
- function LoadingComponent() {
11
- return (React.createElement("div", { style: {
12
- width: '100%',
13
- height: '100%',
14
- maxHeight: '100%',
15
- background: 'linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%)',
16
- borderRadius: '5px',
17
- backgroundSize: '200% 100%',
18
- animation: '1.3s vike-react-shine linear infinite',
19
- aspectRatio: '2.5/1',
20
- } }));
5
+ function VikeReactLoadingComponent() {
6
+ return (React.createElement(React.Fragment, null,
7
+ React.createElement("div", { style: {
8
+ width: '100%',
9
+ height: '100%',
10
+ maxHeight: '100%',
11
+ background: 'linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%)',
12
+ borderRadius: '5px',
13
+ backgroundSize: '200% 100%',
14
+ animation: '1.3s vike-react-loading linear infinite',
15
+ aspectRatio: '2.5/1',
16
+ } }),
17
+ React.createElement("style", { href: "vike-react-loading",
18
+ // https://react.dev/reference/react-dom/components/style#special-rendering-behavior
19
+ // https://github.com/vikejs/vike-react/pull/184#discussion_r2348075206
20
+ precedence: "default" }, `
21
+ @keyframes vike-react-loading {
22
+ to {
23
+ background-position-x: -200%;
24
+ }
25
+ }
26
+ `)));
21
27
  }
@@ -4,4 +4,5 @@ import type { PageContext } from 'vike/types';
4
4
  declare function getPageElement(pageContext: PageContext): {
5
5
  page: React.JSX.Element;
6
6
  renderPromise: Promise<void>;
7
+ renderPromiseReject: (err: unknown) => void;
7
8
  };
@@ -1,6 +1,6 @@
1
1
  export { getPageElement };
2
2
  import React, { Suspense, useEffect } from 'react';
3
- import { PageContextProvider } from '../hooks/usePageContext.js';
3
+ import { VikeReactProviderPageContext } from '../hooks/usePageContext.js';
4
4
  function getPageElement(pageContext) {
5
5
  const { Page, config: { Loading }, } = pageContext;
6
6
  let page = Page ? React.createElement(Page, null) : null;
@@ -20,16 +20,20 @@ function getPageElement(pageContext) {
20
20
  page = React.createElement(Wrap, null, page);
21
21
  page = addSuspense(page);
22
22
  });
23
- page = React.createElement(PageContextProvider, { pageContext: pageContext }, page);
23
+ page = React.createElement(VikeReactProviderPageContext, { pageContext: pageContext }, page);
24
24
  let renderPromiseResolve;
25
- let renderPromise = new Promise((r) => (renderPromiseResolve = r));
26
- page = React.createElement(RenderPromiseProvider, { renderPromiseResolve: renderPromiseResolve }, page);
25
+ let renderPromiseReject;
26
+ let renderPromise = new Promise((resolve, reject) => {
27
+ renderPromiseResolve = resolve;
28
+ renderPromiseReject = reject;
29
+ });
30
+ page = (React.createElement(VikeReactProviderRenderPromise, { renderPromiseResolve: renderPromiseResolve }, page));
27
31
  if (pageContext.config.reactStrictMode !== false) {
28
32
  page = React.createElement(React.StrictMode, null, page);
29
33
  }
30
- return { page, renderPromise };
34
+ return { page, renderPromise, renderPromiseReject };
31
35
  }
32
- function RenderPromiseProvider({ children, renderPromiseResolve, }) {
36
+ function VikeReactProviderRenderPromise({ children, renderPromiseResolve, }) {
33
37
  useEffect(renderPromiseResolve);
34
38
  return children;
35
39
  }
@@ -1,4 +1,4 @@
1
1
  export { onRenderClient };
2
- import type { OnRenderClientAsync } from 'vike/types';
3
- import './Loading.css';
4
- declare const onRenderClient: OnRenderClientAsync;
2
+ import type { PageContextClient } from 'vike/types';
3
+ import type { PageContextInternal } from '../types/PageContext.js';
4
+ declare function onRenderClient(pageContext: PageContextClient & PageContextInternal): Promise<void>;
@@ -6,36 +6,53 @@ import { getPageElement } from './getPageElement.js';
6
6
  import { callCumulativeHooks } from '../utils/callCumulativeHooks.js';
7
7
  import { applyHeadSettings } from './applyHeadSettings.js';
8
8
  import { resolveReactOptions } from './resolveReactOptions.js';
9
- import './Loading.css'; // See comment inside Loading.tsx
10
- let root;
11
- const onRenderClient = async (pageContext) => {
9
+ import { getGlobalObject } from '../utils/getGlobalObject.js';
10
+ import { isObject } from '../utils/isObject.js';
11
+ const globalObject = getGlobalObject('onRenderClient.tsx', {});
12
+ async function onRenderClient(pageContext) {
12
13
  pageContext._headAlreadySet = pageContext.isHydration;
13
14
  // Use case:
14
15
  // - Store hydration https://github.com/vikejs/vike-react/issues/110
15
16
  await callCumulativeHooks(pageContext.config.onBeforeRenderClient, pageContext);
16
- const { page, renderPromise } = getPageElement(pageContext);
17
+ const { page, renderPromise, renderPromiseReject } = getPageElement(pageContext);
17
18
  pageContext.page = page;
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.
19
- // - https://react-dev-git-fork-rickhanlonii-rh-root-options-fbopensource.vercel.app/reference/react-dom/client/createRoot#show-a-dialog-for-uncaught-errors
20
- // - https://react-dev-git-fork-rickhanlonii-rh-root-options-fbopensource.vercel.app/reference/react-dom/client/hydrateRoot#show-a-dialog-for-uncaught-errors
21
- const onUncaughtError = (_error, _errorInfo) => { };
19
+ // Local callback for current page
20
+ globalObject.onUncaughtErrorLocal = (err) => {
21
+ renderPromiseReject(err);
22
+ };
22
23
  const container = document.getElementById('root');
23
24
  const { hydrateRootOptions, createRootOptions } = resolveReactOptions(pageContext);
24
25
  if (pageContext.isHydration &&
25
26
  // Whether the page was [Server-Side Rendered](https://vike.dev/ssr).
26
27
  container.innerHTML !== '') {
27
28
  // First render while using SSR, i.e. [hydration](https://vike.dev/hydration)
28
- root = ReactDOM.hydrateRoot(container, page, hydrateRootOptions);
29
+ globalObject.root = ReactDOM.hydrateRoot(container, page, {
30
+ ...hydrateRootOptions,
31
+ // onUncaughtError is the right callback: https://gist.github.com/brillout/b9516e83a7a4517f4dbd0ef50e9dd716
32
+ onUncaughtError(...args) {
33
+ onUncaughtErrorGlobal.call(this, args, hydrateRootOptions);
34
+ },
35
+ });
29
36
  }
30
37
  else {
31
- if (!root) {
38
+ if (!globalObject.root) {
32
39
  // First render without SSR
33
- root = ReactDOM.createRoot(container, createRootOptions);
40
+ globalObject.root = ReactDOM.createRoot(container, {
41
+ ...createRootOptions,
42
+ onUncaughtError(...args) {
43
+ onUncaughtErrorGlobal.call(this, args, createRootOptions);
44
+ },
45
+ });
34
46
  }
35
- root.render(page);
47
+ globalObject.root.render(page);
48
+ }
49
+ pageContext.root = globalObject.root;
50
+ try {
51
+ await renderPromise;
52
+ }
53
+ finally {
54
+ delete globalObject.onUncaughtErrorLocal;
36
55
  }
37
- pageContext.root = root;
38
- await renderPromise;
39
56
  if (!pageContext.isHydration) {
40
57
  pageContext._headAlreadySet = true;
41
58
  applyHead(pageContext);
@@ -44,9 +61,48 @@ const onRenderClient = async (pageContext) => {
44
61
  // - Custom user settings: https://vike.dev/head-tags#custom-settings
45
62
  // - Testing tools: https://github.com/vikejs/vike-react/issues/95
46
63
  await callCumulativeHooks(pageContext.config.onAfterRenderClient, pageContext);
47
- };
64
+ }
48
65
  function applyHead(pageContext) {
49
66
  const title = getHeadSetting('title', pageContext);
50
67
  const lang = getHeadSetting('lang', pageContext);
51
68
  applyHeadSettings(title, lang);
52
69
  }
70
+ // Global callback, attached once upon hydration.
71
+ function onUncaughtErrorGlobal(args, userOptions) {
72
+ const [errorOriginal, errorInfo] = args;
73
+ const errorEnhanced = getErrorEnhanced(errorOriginal, errorInfo);
74
+ console.error(errorEnhanced);
75
+ // Used by Vike:
76
+ // https://github.com/vikejs/vike/blob/8ce2cbda756892f0ff083256291515b5a45fe319/packages/vike/client/runtime-client-routing/renderPageClientSide.ts#L838-L844
77
+ if (isObject(errorEnhanced))
78
+ errorEnhanced.isAlreadyLogged = true;
79
+ globalObject.onUncaughtErrorLocal?.(errorEnhanced);
80
+ userOptions?.onUncaughtError?.call(this, errorEnhanced, errorInfo);
81
+ }
82
+ function getErrorEnhanced(errorOriginal, errorInfo) {
83
+ if (!errorInfo?.componentStack || !isObject(errorOriginal))
84
+ return errorOriginal;
85
+ const errorOiginalStackLines = String(errorOriginal.stack).split('\n');
86
+ const cutoff = errorOiginalStackLines.findIndex((l) => l.includes('node_modules') && l.includes('react'));
87
+ if (cutoff === -1)
88
+ return errorOriginal;
89
+ const stackEnhanced = [
90
+ ...errorOiginalStackLines.slice(0, cutoff),
91
+ ...errorInfo.componentStack.split('\n').filter(Boolean),
92
+ ...errorOiginalStackLines.slice(cutoff),
93
+ ].join('\n');
94
+ const errorEnhanced = structuredClone(errorOriginal);
95
+ errorEnhanced.stack = stackEnhanced;
96
+ // https://gist.github.com/brillout/066293a687ab7cf695e62ad867bc6a9c
97
+ Object.defineProperty(errorEnhanced, 'getOriginalError', {
98
+ value: () => errorOriginal,
99
+ enumerable: true,
100
+ });
101
+ /* Not needed. Let's skip this to save client-side KBs.
102
+ Object.defineProperty(errorOriginal, 'getEnhancedError', {
103
+ value: () => errorEnhanced,
104
+ enumerable: true,
105
+ })
106
+ //*/
107
+ return errorEnhanced;
108
+ }
@@ -1,6 +1,8 @@
1
1
  export { onRenderHtml };
2
2
  import { renderToStream } from 'react-streaming/server';
3
- import type { OnRenderHtmlAsync } from 'vike/types';
4
- declare const onRenderHtml: OnRenderHtmlAsync;
3
+ import { escapeInject } from 'vike/server';
4
+ import type { PageContextServer } from 'vike/types';
5
+ import type { PageContextInternal } from '../types/PageContext.js';
6
+ declare function onRenderHtml(pageContext: PageContextServer & PageContextInternal): Promise<ReturnType<typeof escapeInject>>;
5
7
  export type PageHtmlStream = Awaited<ReturnType<typeof renderToStream>>;
6
8
  export type Viewport = 'responsive' | number | null;
@@ -4,7 +4,7 @@ import React from 'react';
4
4
  import { renderToString, renderToStaticMarkup } from 'react-dom/server';
5
5
  import { renderToStream } from 'react-streaming/server';
6
6
  import { dangerouslySkipEscape, escapeInject } from 'vike/server';
7
- import { PageContextProvider } from '../hooks/usePageContext.js';
7
+ import { VikeReactProviderPageContext } from '../hooks/usePageContext.js';
8
8
  import { getHeadSetting } from './getHeadSetting.js';
9
9
  import { getPageElement } from './getPageElement.js';
10
10
  import { isReactElement } from '../utils/isReactElement.js';
@@ -16,7 +16,7 @@ import { isNotNullish } from '../utils/isNotNullish.js';
16
16
  import { isObject } from '../utils/isObject.js';
17
17
  import { isType } from '../utils/isType.js';
18
18
  addEcosystemStamp();
19
- const onRenderHtml = async (pageContext) => {
19
+ async function onRenderHtml(pageContext) {
20
20
  await renderPageToHtml(pageContext);
21
21
  const headHtml = getHeadHtml(pageContext);
22
22
  const { bodyHtmlBegin, bodyHtmlEnd } = await getBodyHtmlBoundary(pageContext);
@@ -47,7 +47,7 @@ const onRenderHtml = async (pageContext) => {
47
47
  ${bodyHtmlEnd}
48
48
  </body>
49
49
  </html>`;
50
- };
50
+ }
51
51
  async function renderPageToHtml(pageContext) {
52
52
  if (pageContext.Page)
53
53
  pageContext.page = getPageElement(pageContext).page;
@@ -69,7 +69,7 @@ async function renderPageToHtml(pageContext) {
69
69
  undefined
70
70
  : streamSetting.type === 'web',
71
71
  userAgent: pageContext.headers?.['user-agent'] ||
72
- // TODO/eventually: remove old way of acccessing the User Agent header.
72
+ // TO-DO/eventually: remove old way of acccessing the User Agent header.
73
73
  // @ts-ignore
74
74
  pageContext.userAgent,
75
75
  disable:
@@ -128,7 +128,7 @@ function getHeadElementHtml(Head, pageContext) {
128
128
  headElement = Head;
129
129
  }
130
130
  else {
131
- headElement = (React.createElement(PageContextProvider, { pageContext: pageContext },
131
+ headElement = (React.createElement(VikeReactProviderPageContext, { pageContext: pageContext },
132
132
  React.createElement(Head, null)));
133
133
  }
134
134
  if (pageContext.config.reactStrictMode !== false) {
@@ -182,7 +182,7 @@ async function getBodyHtmlBoundary(pageContext) {
182
182
  }
183
183
  function resolveStreamSetting(pageContext) {
184
184
  const { stream,
185
- // TODO/eventually: remove +streamIsRequired
185
+ // TO-DO/eventually: remove +streamIsRequired
186
186
  // - Let's remove it once following last vike-react-{query,apollo} releases using +streamIsRequired can be considered old versions.
187
187
  // - Last vike-react-query version that uses +streamIsRequired was 0.1.3
188
188
  // - Last vike-react-apollo version that uses +streamIsRequired was 0.1.1
@@ -1 +1 @@
1
- export declare function getGlobalObject<T extends Record<string, unknown> = never>(key: `${string}.ts`, defaultValue: T): T;
1
+ export declare function getGlobalObject<T extends Record<string, unknown> = never>(key: `${string}.ts` | `${string}.tsx`, defaultValue: T): T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike-react",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
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.4.3"
30
+ "react-streaming": "^0.4.5"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "react": ">=19",
@@ -38,14 +38,14 @@
38
38
  "@biomejs/biome": "^1.9.4",
39
39
  "@brillout/release-me": "^0.4.8",
40
40
  "@types/node": "^24.0.8",
41
- "@types/react": "^19.0.10",
42
- "@types/react-dom": "^19.0.4",
43
- "react": "^19.0.0",
44
- "react-dom": "^19.0.0",
41
+ "@types/react": "^19.1.13",
42
+ "@types/react-dom": "^19.1.9",
43
+ "react": "^19.1.1",
44
+ "react-dom": "^19.1.1",
45
45
  "rimraf": "^5.0.5",
46
- "typescript": "^5.8.3",
47
- "vike": "^0.4.235",
48
- "vite": "^6.2.5"
46
+ "typescript": "^5.9.2",
47
+ "vike": "^0.4.241",
48
+ "vite": "^7.1.7"
49
49
  },
50
50
  "typesVersions": {
51
51
  "*": {
@@ -95,8 +95,7 @@
95
95
  ],
96
96
  "scripts": {
97
97
  "dev": "tsc --watch",
98
- "build": "rimraf dist/ && tsc && pnpm run build:css",
99
- "build:css": "cp src/integration/Loading.css dist/integration/Loading.css",
98
+ "build": "rimraf dist/ && tsc",
100
99
  "release": "release-me patch",
101
100
  "release:minor": "release-me minor",
102
101
  "release:commit": "release-me commit"
@@ -1,10 +0,0 @@
1
- /*
2
- This CSS is loaded for all vike-react users, even if they don't use the <Loading> component because it's imported not directly but over depednency injection, see:
3
- https://github.com/vikejs/vike/discussions/2340
4
- */
5
-
6
- @keyframes vike-react-shine {
7
- to {
8
- background-position-x: -200%;
9
- }
10
- }