diff --git a/examples/full/.test-dev.test.ts b/examples/full/.test-dev.test.ts
new file mode 100644
index 00000000..fbafdbbc
--- /dev/null
+++ b/examples/full/.test-dev.test.ts
@@ -0,0 +1,2 @@
+import { testRun } from './.testRun'
+testRun('pnpm run dev')
diff --git a/examples/full/.test-preview.test.ts b/examples/full/.test-preview.test.ts
new file mode 100644
index 00000000..6cd5bbe4
--- /dev/null
+++ b/examples/full/.test-preview.test.ts
@@ -0,0 +1,2 @@
+import { testRun } from './.testRun'
+testRun('pnpm run preview')
diff --git a/examples/full/.test.ts b/examples/full/.testRun.ts
similarity index 52%
rename from examples/full/.test.ts
rename to examples/full/.testRun.ts
index 3e5206a3..4e66d701 100644
--- a/examples/full/.test.ts
+++ b/examples/full/.testRun.ts
@@ -1,16 +1,19 @@
+export { testRun }
+
import { test, expect, run, fetchHtml, page, getServerUrl, autoRetry, partRegex } from '@brillout/test-e2e'
-runTest()
+let isProd: boolean
+
+function testRun(cmd: `pnpm run ${'dev' | 'preview'}`) {
+ run(cmd)
-function runTest() {
- run('pnpm run dev')
+ isProd = cmd !== 'pnpm run dev'
- const textLandingPage = 'Rendered to HTML.'
const title = 'My Vike + React App'
testUrl({
url: '/',
title,
- text: textLandingPage,
+ text: 'Rendered to HTML.',
counter: true
})
@@ -34,63 +37,86 @@ function runTest() {
counter: true
})
- {
- const url = '/without-ssr'
- const textNoSSR = 'This page is rendered only in the browser'
- const text = textNoSSR
- test(url + ' (HTML)', async () => {
- const html = await fetchHtml(url)
- // Isn't rendered to HTML
- expect(html).toContain('
')
- expect(html).not.toContain(text)
- expect(getTitle(html)).toBe(title)
- })
- test(url + ' (Hydration)', async () => {
- await page.goto(getServerUrl() + url)
- await testCounter()
- const body = await page.textContent('body')
- expect(body).toContain(text)
- })
- test('Switch between SSR and non-SSR page', async () => {
- let body: string | null
- const t1 = textNoSSR
- const t2 = textLandingPage
-
- body = await page.textContent('body')
- expect(body).toContain(t1)
- expect(body).not.toContain(t2)
- ensureWasClientSideRouted('/pages/without-ssr')
-
- await page.click('a:has-text("Welcome")')
- await testCounter()
- body = await page.textContent('body')
- expect(body).toContain(t2)
- expect(body).not.toContain(t1)
- ensureWasClientSideRouted('/pages/without-ssr')
+ const textNoSSR = 'This page is rendered only in the browser'
+ testUrl({
+ url: '/without-ssr',
+ title: 'No SSR',
+ text: textNoSSR,
+ counter: true,
+ noSSR: true
+ })
- await page.click('a:has-text("Without SSR")')
- await testCounter()
- body = await page.textContent('body')
- expect(body).toContain(t1)
- expect(body).not.toContain(t2)
- ensureWasClientSideRouted('/pages/without-ssr')
- })
- }
+ testNavigationBetweenWithSSRAndWithoutSSR()
}
-function testUrl({ url, title, text, counter }: { url: string; title: string; text: string; counter?: true }) {
+function testNavigationBetweenWithSSRAndWithoutSSR() {
+ const textWithSSR = 'Rendered to HTML.'
+ const textWithoutSSR = "It isn't rendered to HTML"
+
+ const url = '/without-ssr'
+ test(url + " isn't rendered to HTML", async () => {
+ const html = await fetchHtml(url)
+ expect(html).toContain('')
+ expect(html).not.toContain(textWithoutSSR)
+ await page.goto(getServerUrl() + url)
+ await testCounter()
+ const body = await page.textContent('body')
+ expect(body).toContain(textWithoutSSR)
+ })
+
+ test('Switch between SSR and non-SSR page', async () => {
+ let body: string | null
+ const t1 = textWithoutSSR
+ const t2 = textWithSSR
+
+ body = await page.textContent('body')
+ expect(body).toContain(t1)
+ expect(body).not.toContain(t2)
+ ensureWasClientSideRouted('/pages/without-ssr')
+
+ await page.click('a:has-text("Welcome")')
+ await testCounter()
+ body = await page.textContent('body')
+ expect(body).toContain(t2)
+ expect(body).not.toContain(t1)
+ ensureWasClientSideRouted('/pages/without-ssr')
+
+ await page.click('a:has-text("Without SSR")')
+ await testCounter()
+ body = await page.textContent('body')
+ expect(body).toContain(t1)
+ expect(body).not.toContain(t2)
+ ensureWasClientSideRouted('/pages/without-ssr')
+ })
+}
+
+function testUrl({
+ url,
+ title,
+ text,
+ counter,
+ noSSR
+}: { url: string; title: string; text: string; counter?: true; noSSR?: true }) {
test(url + ' (HTML)', async () => {
const html = await fetchHtml(url)
- expect(html).toContain(text)
+ if (!noSSR) {
+ expect(html).toContain(text)
+ }
expect(getTitle(html)).toBe(title)
+ const hash = /[a-zA-Z0-9_-]+/
+ if (!isProd) {
+ expect(html).toMatch(partRegex``)
+ } else {
+ expect(html).toMatch(partRegex``)
+ }
})
test(url + ' (Hydration)', async () => {
await page.goto(getServerUrl() + url)
- const body = await page.textContent('body')
- expect(body).toContain(text)
if (counter) {
await testCounter()
}
+ const body = await page.textContent('body')
+ expect(body).toContain(text)
})
}
diff --git a/examples/full/pages/streaming/+Page.tsx b/examples/full/pages/streaming/+Page.tsx
index 6dc6d7cd..4e949b8a 100644
--- a/examples/full/pages/streaming/+Page.tsx
+++ b/examples/full/pages/streaming/+Page.tsx
@@ -25,7 +25,7 @@ function MovieList() {
const movies = useAsync(['star-wars-movies'], async () => {
const response = await fetch('https://star-wars.brillout.com/api/films.json')
// Simulate slow network
- await new Promise((r) => setTimeout(r, 2 * 1000))
+ await new Promise((r) => setTimeout(r, 3 * 1000))
const movies: Movie[] = (await response.json()).results
return movies
})
diff --git a/examples/full/pages/without-ssr/+config.ts b/examples/full/pages/without-ssr/+config.ts
index f9ec2d6a..16c70ed4 100644
--- a/examples/full/pages/without-ssr/+config.ts
+++ b/examples/full/pages/without-ssr/+config.ts
@@ -2,5 +2,6 @@ import type { Config } from 'vike/types'
export default {
// https://vike.dev/ssr
- ssr: false
+ ssr: false,
+ title: 'No SSR'
} satisfies Config
diff --git a/packages/vike-react-query/package.json b/packages/vike-react-query/package.json
index f3198939..382c1ba0 100644
--- a/packages/vike-react-query/package.json
+++ b/packages/vike-react-query/package.json
@@ -12,36 +12,37 @@
},
"scripts": {
"dev": "tsc --watch",
- "build": "rm -rf dist/ && tsc",
+ "build": "rimraf dist/ && tsc",
"release": "release-me patch",
"release:minor": "release-me minor",
"release:commit": "release-me commit",
"test": "vitest run"
},
"peerDependencies": {
+ "@tanstack/react-query": "5.x.x",
"react": "18.x.x",
"react-dom": "18.x.x",
+ "react-streaming": "^0.3.19",
"vike": "^0.4.160",
"vike-react": "^0.4.4",
- "react-streaming": "^0.3.19",
- "vite": "^4.3.8 || ^5.0.10",
- "@tanstack/react-query": "5.x.x"
+ "vite": "^4.3.8 || ^5.0.10"
},
"devDependencies": {
"@brillout/release-me": "^0.3.4",
+ "@tanstack/react-query": "^5.20.1",
+ "@testing-library/react": "^14.2.1",
"@types/node": "^20.11.17",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
+ "jsdom": "^24.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-streaming": "^0.3.27",
+ "rimraf": "^5.0.5",
"typescript": "^5.3.3",
"vike": "^0.4.168",
"vike-react": "^0.4.8",
- "react-streaming": "^0.3.27",
- "vitest": "^1.2.2",
- "@testing-library/react": "^14.2.1",
- "jsdom": "^24.0.0",
- "@tanstack/react-query": "^5.20.1"
+ "vitest": "^1.2.2"
},
"dependencies": {
"devalue": "^4.3.2",
diff --git a/packages/vike-react/package.json b/packages/vike-react/package.json
index b5cb6870..fbddecdf 100644
--- a/packages/vike-react/package.json
+++ b/packages/vike-react/package.json
@@ -15,7 +15,7 @@
},
"scripts": {
"dev": "tsc --watch",
- "build": "rm -rf dist/ && tsc",
+ "build": "rimraf dist/ && tsc",
"release": "release-me patch",
"release:minor": "release-me minor",
"release:commit": "release-me commit"
@@ -34,6 +34,7 @@
"@types/react-dom": "^18.2.19",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "rimraf": "^5.0.5",
"typescript": "^5.3.3",
"vike": "^0.4.168"
},
diff --git a/packages/vike-react/src/+config.ts b/packages/vike-react/src/+config.ts
index 21ddde42..fe544066 100644
--- a/packages/vike-react/src/+config.ts
+++ b/packages/vike-react/src/+config.ts
@@ -49,6 +49,9 @@ export default {
_streamIsRequied: {
env: { server: true }
},
+ onBeforeRenderClient: {
+ env: { client: true }
+ },
onAfterRenderClient: {
env: { client: true }
},
diff --git a/packages/vike-react/src/renderer/onRenderClient.tsx b/packages/vike-react/src/renderer/onRenderClient.tsx
index fbee996b..1e9fc993 100644
--- a/packages/vike-react/src/renderer/onRenderClient.tsx
+++ b/packages/vike-react/src/renderer/onRenderClient.tsx
@@ -8,6 +8,10 @@ import { getPageElement } from './getPageElement.js'
let root: ReactDOM.Root
const onRenderClient: OnRenderClientSync = (pageContext): ReturnType => {
+ // Use case:
+ // - Store hydration https://github.com/vikejs/vike-react/issues/110
+ pageContext.config.onBeforeRenderClient?.(pageContext)
+
const page = getPageElement(pageContext)
// 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.
@@ -16,8 +20,13 @@ const onRenderClient: OnRenderClientSync = (pageContext): ReturnType {}
const container = document.getElementById('react-root')!
- if (container.innerHTML !== '' && pageContext.isHydration) {
- // First render (hydration)
+ if (
+ // Whether the page was rendered to HTML. (I.e. whether the user set the [`ssr`](https://vike.dev/ssr) setting to `false`.)
+ container.innerHTML !== '' &&
+ // Whether the page was already rendered to HTML. (I.e. whether this is the first client-side rendering.)
+ pageContext.isHydration
+ ) {
+ // Hydration
root = ReactDOM.hydrateRoot(container, page, {
// @ts-expect-error
onUncaughtError
@@ -48,6 +57,9 @@ const onRenderClient: OnRenderClientSync = (pageContext): ReturnType void
- // https://github.com/vikejs/vike-react/pull/96
+ /**
+ * Client-side hook called after the page is rendered.
+ */
onAfterRenderClient?: (pageContext: PageContextClient) => void
// Temporary until Wrapper is cumulative
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f8bf5a0a..ce694bfc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -190,6 +190,9 @@ importers:
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
+ rimraf:
+ specifier: ^5.0.5
+ version: 5.0.5
typescript:
specifier: ^5.3.3
version: 5.3.3
@@ -239,6 +242,9 @@ importers:
react-streaming:
specifier: ^0.3.27
version: 0.3.27(react-dom@18.2.0)(react@18.2.0)
+ rimraf:
+ specifier: ^5.0.5
+ version: 5.0.5
typescript:
specifier: ^5.3.3
version: 5.3.3
@@ -1273,6 +1279,18 @@ packages:
engines: {node: '>=10.13.0'}
dev: true
+ /@isaacs/cliui@8.0.2:
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: /string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: /strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: /wrap-ansi@7.0.0
+ dev: true
+
/@jest/schemas@29.6.3:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -1327,6 +1345,13 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
+ /@pkgjs/parseargs@0.11.0:
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@polka/url@1.0.0-next.23:
resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
@@ -1629,6 +1654,11 @@ packages:
engines: {node: '>=8'}
dev: true
+ /ansi-regex@6.0.1:
+ resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+ engines: {node: '>=12'}
+ dev: true
+
/ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'}
@@ -1647,6 +1677,11 @@ packages:
engines: {node: '>=10'}
dev: true
+ /ansi-styles@6.2.1:
+ resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ engines: {node: '>=12'}
+ dev: true
+
/aria-query@5.1.3:
resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
dependencies:
@@ -1677,6 +1712,16 @@ packages:
engines: {node: '>= 0.4'}
dev: true
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ dev: true
+
+ /brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+ dev: true
+
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
@@ -2034,10 +2079,22 @@ packages:
is-obj: 2.0.0
dev: true
+ /eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+ dev: true
+
/electron-to-chromium@1.4.616:
resolution: {integrity: sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==}
dev: false
+ /emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ dev: true
+
+ /emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ dev: true
+
/entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
@@ -2243,6 +2300,14 @@ packages:
is-callable: 1.2.7
dev: true
+ /foreground-child@3.1.1:
+ resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+ engines: {node: '>=14'}
+ dependencies:
+ cross-spawn: 7.0.3
+ signal-exit: 4.1.0
+ dev: true
+
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@@ -2335,6 +2400,18 @@ packages:
dependencies:
is-glob: 4.0.3
+ /glob@10.3.12:
+ resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ foreground-child: 3.1.1
+ jackspeak: 2.3.6
+ minimatch: 9.0.4
+ minipass: 7.1.0
+ path-scurry: 1.10.2
+ dev: true
+
/globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
@@ -2521,6 +2598,11 @@ packages:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
+ /is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+ dev: true
+
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
@@ -2630,6 +2712,15 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
+ /jackspeak@2.3.6:
+ resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+ dev: true
+
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -2742,6 +2833,11 @@ packages:
semver: 7.5.4
dev: true
+ /lru-cache@10.2.2:
+ resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
+ engines: {node: 14 || >=16.14}
+ dev: true
+
/lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
dependencies:
@@ -2809,10 +2905,22 @@ packages:
engines: {node: '>=12'}
dev: true
+ /minimatch@9.0.4:
+ resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
dev: true
+ /minipass@7.1.0:
+ resolution: {integrity: sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dev: true
+
/mlly@1.4.2:
resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==}
dependencies:
@@ -2990,6 +3098,14 @@ packages:
engines: {node: '>=12'}
dev: true
+ /path-scurry@1.10.2:
+ resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ lru-cache: 10.2.2
+ minipass: 7.1.0
+ dev: true
+
/pathe@1.1.1:
resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==}
dev: true
@@ -3196,6 +3312,14 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ /rimraf@5.0.5:
+ resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==}
+ engines: {node: '>=14'}
+ hasBin: true
+ dependencies:
+ glob: 10.3.12
+ dev: true
+
/rollup@3.29.4:
resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
@@ -3377,6 +3501,24 @@ packages:
internal-slot: 1.0.6
dev: true
+ /string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+ dev: true
+
+ /string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
+ dev: true
+
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
@@ -3384,6 +3526,13 @@ packages:
ansi-regex: 5.0.1
dev: true
+ /strip-ansi@7.1.0:
+ resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-regex: 6.0.1
+ dev: true
+
/strip-final-newline@2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
@@ -3881,6 +4030,24 @@ packages:
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
dev: true
+ /wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ dev: true
+
+ /wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+ dev: true
+
/ws@8.16.0:
resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
engines: {node: '>=10.0.0'}