From b32c10793a57de9b8cfa60eed675a6d46b05ab91 Mon Sep 17 00:00:00 2001 From: Clement Wong Date: Mon, 21 Sep 2026 16:28:02 +0800 Subject: [PATCH] feat: add `fastRefresh` option to disable Fast Refresh Allows `react()` to run next to a plugin that already provides Fast Refresh, such as React Router in framework mode, so that JSX and the React Compiler can still be handled by this plugin. Co-Authored-By: Claude Fable 5.1 Co-Authored-By: Claude Opus 5.5 --- packages/plugin-react/CHANGELOG.md | 4 + packages/plugin-react/README.md | 17 ++ packages/plugin-react/src/index.ts | 19 +- playground/react-router/.gitignore | 2 + .../__tests__/react-router.spec.ts | 56 +++++ playground/react-router/__tests__/serve.ts | 38 ++++ playground/react-router/app/root.tsx | 27 +++ playground/react-router/app/routes.ts | 3 + playground/react-router/app/routes/home.tsx | 13 ++ playground/react-router/package.json | 25 +++ playground/react-router/tsconfig.json | 23 ++ playground/react-router/vite.config.ts | 10 + pnpm-lock.yaml | 202 ++++++++++++++++++ 13 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 playground/react-router/.gitignore create mode 100644 playground/react-router/__tests__/react-router.spec.ts create mode 100644 playground/react-router/__tests__/serve.ts create mode 100644 playground/react-router/app/root.tsx create mode 100644 playground/react-router/app/routes.ts create mode 100644 playground/react-router/app/routes/home.tsx create mode 100644 playground/react-router/package.json create mode 100644 playground/react-router/tsconfig.json create mode 100644 playground/react-router/vite.config.ts diff --git a/packages/plugin-react/CHANGELOG.md b/packages/plugin-react/CHANGELOG.md index b42eb8e63..46edd7eb8 100644 --- a/packages/plugin-react/CHANGELOG.md +++ b/packages/plugin-react/CHANGELOG.md @@ -6,6 +6,10 @@ Add `refreshInclude` and `refreshExclude` options to skip fast refresh for certain files that won't run in the browser. +### Add `fastRefresh` option + +Set `fastRefresh` to `false` to disable Fast Refresh while keeping HMR, for setups where another plugin already provides it, such as React Router in framework mode. This allows `react({ compiler: true, fastRefresh: false })` to be used next to `reactRouter()` so that JSX and the React Compiler are still handled by this plugin. + ## 6.1.2 (2026-10-05) ### Fix HMR for compound components ([#1484](https://github.com/vitejs/vite-plugin-react/pull/1484)) diff --git a/packages/plugin-react/README.md b/packages/plugin-react/README.md index 3cda82578..910d277f4 100644 --- a/packages/plugin-react/README.md +++ b/packages/plugin-react/README.md @@ -77,6 +77,21 @@ react({ reactRefreshHost: 'http://localhost:3000' }) Under the hood, this simply updates the React Fash Refresh runtime URL from `/@react-refresh` to `http://localhost:3000/@react-refresh` to ensure there is only one Refresh runtime across the whole application. Note that if you define `base` option in the host application, you need to include it in the option, like: `http://localhost:3000/{base}`. +### fastRefresh + +Fast Refresh is enabled during development by default. Set `fastRefresh` to `false` when another plugin already provides it, so that the two do not conflict. This is the case for React Router in framework mode, whose Vite plugin ships its own Fast Refresh integration and fails with `Identifier 'RefreshRuntime' has already been declared` when both are active. The plugin then only configures JSX and, if enabled, runs the [React Compiler](#react-compiler), while the other plugin owns Fast Refresh. HMR itself is not affected. + +```js +// vite.config.js +import { reactRouter } from '@react-router/dev/vite' +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [react({ compiler: true, fastRefresh: false }), reactRouter()], +}) +``` + ## React Compiler ### Rust React Compiler @@ -112,6 +127,8 @@ Set `logDiagnostics` to `true` to log recoverable React Compiler diagnostics thr react({ compiler: { logDiagnostics: true } }) ``` +To use the compiler in a setup where another plugin provides Fast Refresh, such as React Router in framework mode, combine it with [`fastRefresh: false`](#fastrefresh). + ### Babel React Compiler React Compiler can also be used through Babel with the exported `reactCompilerPreset` helper. This requires [`@rolldown/plugin-babel`](https://npmx.dev/package/@rolldown/plugin-babel), [`babel-plugin-react-compiler`](https://npmx.dev/package/babel-plugin-react-compiler), and [`@babel/core`](https://npmx.dev/package/@babel/core) as peer dependencies: diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts index 9a0ad45d1..38ab182a2 100644 --- a/packages/plugin-react/src/index.ts +++ b/packages/plugin-react/src/index.ts @@ -73,6 +73,15 @@ export interface Options { * reactRefreshHost: 'http://localhost:3000' */ reactRefreshHost?: string + /** + * Set to `false` to disable Fast Refresh: the refresh transform, the + * runtime and the preamble are skipped while HMR stays enabled. + * Useful when another plugin already provides Fast Refresh, e.g. React + * Router in framework mode, so that this plugin can still handle JSX and + * the React Compiler next to it. + * @default true + */ + fastRefresh?: boolean /** * Enable React Compiler with its default options or configure it. * This requires `oxc-transform-react` to be installed. @@ -109,14 +118,20 @@ function viteReact(opts: Options = {}): Plugin[] { command: 'serve' | 'build', hmr: ServerOptions['hmr'], ) { - return isProduction || command === 'build' || hmr === false + return ( + opts.fastRefresh === false || + isProduction || + command === 'build' || + hmr === false + ) } const viteBabel: Plugin = { name: 'vite:react-babel', enforce: 'pre', config(_userConfig, { command }) { - const refresh = command === 'serve' && !opts.compiler + const refresh = + command === 'serve' && !opts.compiler && opts.fastRefresh !== false if (opts.jsxRuntime === 'classic') { return { oxc: { diff --git a/playground/react-router/.gitignore b/playground/react-router/.gitignore new file mode 100644 index 000000000..a7fb7c0d9 --- /dev/null +++ b/playground/react-router/.gitignore @@ -0,0 +1,2 @@ +.react-router +build diff --git a/playground/react-router/__tests__/react-router.spec.ts b/playground/react-router/__tests__/react-router.spec.ts new file mode 100644 index 000000000..c86917712 --- /dev/null +++ b/playground/react-router/__tests__/react-router.spec.ts @@ -0,0 +1,56 @@ +import fs from 'node:fs' +import path from 'node:path' +import { expect, test } from 'vitest' +import { + browserErrors, + editFile, + isBuild, + isServe, + page, + testDir, + untilBrowserLogAfter, + viteServer, + viteTestUrl, +} from '~utils' + +test('should render', async () => { + await untilBrowserLogAfter(() => page.goto(viteTestUrl), 'hydrated') + expect(await page.textContent('button')).toMatch('count is 0') + expect(await page.click('button')) + expect(await page.textContent('button')).toMatch('count is 1') + expect(browserErrors).toEqual([]) +}) + +test.runIf(isServe)('should compile without Fast Refresh', async () => { + const result = await viteServer.environments.client.transformRequest( + '/app/routes/home.tsx', + ) + const code = result!.code + expect(code).toMatch(/_c\(\d+\)/) + expect(code).toContain('jsx-dev-runtime') + // Fast Refresh is only set up by React Router + expect(code).not.toContain('/@react-refresh') + expect(code.match(/import RefreshRuntime from/g)).toEqual([ + 'import RefreshRuntime from', + ]) + expect(code).toContain('virtual:react-router/hmr-runtime') +}) + +test.runIf(isServe)('should preserve state on edit', async () => { + expect(await page.textContent('button')).toMatch('count is 1') + editFile('app/routes/home.tsx', (code) => + code.replace('count is {count}', 'count is {count}!'), + ) + await expect.poll(() => page.textContent('button')).toMatch('count is 1!') + expect(browserErrors).toEqual([]) +}) + +test.runIf(isBuild)('should compile components', () => { + const assetsDir = path.join(testDir, 'build/client/assets') + const bundle = fs + .readdirSync(assetsDir) + .filter((file) => file.endsWith('.js')) + .map((file) => fs.readFileSync(path.join(assetsDir, file), 'utf-8')) + .join('\n') + expect(bundle).toContain('react.memo_cache_sentinel') +}) diff --git a/playground/react-router/__tests__/serve.ts b/playground/react-router/__tests__/serve.ts new file mode 100644 index 000000000..fe0ec080e --- /dev/null +++ b/playground/react-router/__tests__/serve.ts @@ -0,0 +1,38 @@ +import path from 'node:path' +import { + createBuilder, + createServer, + preview, + type InlineConfig, + type ViteDevServer, +} from 'vite' +import { isBuild, rootDir, setViteUrl } from '~utils' + +export let viteServer: ViteDevServer + +// The React Router plugin requires a config file, which the default serve +// disables, so load it explicitly here. +export async function serve() { + const config: InlineConfig = { + root: rootDir, + configFile: path.join(rootDir, 'vite.config.ts'), + logLevel: 'silent', + } + + if (isBuild) { + const builder = await createBuilder(config) + await builder.buildApp() + const server = await preview(config) + setViteUrl(server.resolvedUrls!.local[0].replace(/\/$/, '')) + return server + } + + viteServer = await ( + await createServer({ + ...config, + server: { watch: { usePolling: true, interval: 100 } }, + }) + ).listen() + setViteUrl(viteServer.resolvedUrls!.local[0].replace(/\/$/, '')) + return viteServer +} diff --git a/playground/react-router/app/root.tsx b/playground/react-router/app/root.tsx new file mode 100644 index 000000000..2af582fef --- /dev/null +++ b/playground/react-router/app/root.tsx @@ -0,0 +1,27 @@ +import { useEffect } from 'react' +import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router' + +export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + + {children} + + + + + ) +} + +export default function App() { + useEffect(() => { + console.log('hydrated') + }, []) + + return +} diff --git a/playground/react-router/app/routes.ts b/playground/react-router/app/routes.ts new file mode 100644 index 000000000..10d7044bf --- /dev/null +++ b/playground/react-router/app/routes.ts @@ -0,0 +1,3 @@ +import { index, type RouteConfig } from '@react-router/dev/routes' + +export default [index('routes/home.tsx')] satisfies RouteConfig diff --git a/playground/react-router/app/routes/home.tsx b/playground/react-router/app/routes/home.tsx new file mode 100644 index 000000000..225b7c0ef --- /dev/null +++ b/playground/react-router/app/routes/home.tsx @@ -0,0 +1,13 @@ +import { useState } from 'react' + +export default function Home() { + const [count, setCount] = useState(0) + + return ( + <> + + + ) +} diff --git a/playground/react-router/package.json b/playground/react-router/package.json new file mode 100644 index 000000000..fbdbc83d7 --- /dev/null +++ b/playground/react-router/package.json @@ -0,0 +1,25 @@ +{ + "name": "@vitejs/test-react-router", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk vite", + "preview": "vite preview" + }, + "dependencies": { + "@react-router/node": "^8.5.0", + "isbot": "^5.1.40", + "react": "^19.3.1", + "react-dom": "^19.3.1", + "react-router": "^8.5.0" + }, + "devDependencies": { + "@react-router/dev": "^8.5.0", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "@vitejs/plugin-react": "workspace:*", + "oxc-transform-react": "^0.155.0" + } +} diff --git a/playground/react-router/tsconfig.json b/playground/react-router/tsconfig.json new file mode 100644 index 000000000..7054b5829 --- /dev/null +++ b/playground/react-router/tsconfig.json @@ -0,0 +1,23 @@ +{ + "include": ["app"], + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM"], + "types": ["vite/client"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + } +} diff --git a/playground/react-router/vite.config.ts b/playground/react-router/vite.config.ts new file mode 100644 index 000000000..d506bfec8 --- /dev/null +++ b/playground/react-router/vite.config.ts @@ -0,0 +1,10 @@ +import { reactRouter } from '@react-router/dev/vite' +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite' + +// React Router in framework mode provides its own Fast Refresh, so this +// plugin only handles JSX and the React Compiler next to it. +export default defineConfig({ + server: { port: 8912 /* Should be unique */ }, + plugins: [react({ compiler: true, fastRefresh: false }), reactRouter()], +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8b159afb..421316102 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1430,6 +1430,40 @@ importers: specifier: workspace:* version: link:../../packages/plugin-react + playground/react-router: + dependencies: + '@react-router/node': + specifier: ^8.5.0 + version: 8.5.0(react-router@8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(typescript@7.0.2) + isbot: + specifier: ^5.1.40 + version: 5.2.2 + react: + specifier: ^19.3.1 + version: 19.3.1 + react-dom: + specifier: ^19.3.1 + version: 19.3.1(react@19.3.1) + react-router: + specifier: ^8.5.0 + version: 8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + devDependencies: + '@react-router/dev': + specifier: ^8.5.0 + version: 8.5.0(@vitejs/plugin-rsc@packages+plugin-rsc)(babel-plugin-macros@3.1.0)(react-router@8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(typescript@7.0.2)(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(yaml@2.9.1))(wrangler@4.151.2(@types/node@24.19.2)) + '@types/react': + specifier: ^19.3.0 + version: 19.3.0 + '@types/react-dom': + specifier: ^19.3.0 + version: 19.3.0(@types/react@19.3.0) + '@vitejs/plugin-react': + specifier: workspace:* + version: link:../../packages/plugin-react + oxc-transform-react: + specifier: ^0.155.0 + version: 0.155.0 + playground/react-sourcemap: dependencies: react: @@ -2566,6 +2600,43 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@react-router/dev@8.5.0': + resolution: {integrity: sha512-SXmL0ym9Wp8Hi0LdXLG6yPaN8V1rUW4PuavvBS9eqpr0hM3PFjiCUT44pRzCj4G9lKEQBeNcj4beOtpN7IxuCg==} + engines: {node: '>=22.22.0'} + hasBin: true + peerDependencies: + '@react-router/serve': ^8.5.0 + '@vitejs/plugin-rsc': ~0.5.26 + react-router: ^8.5.0 + react-server-dom-webpack: ^19.2.7 + typescript: ^5.1.0 || ^6.0.0 || ^7.0.0 + vite: ^7.0.0 || ^8.0.0 + wrangler: ^4.0.0 + peerDependenciesMeta: + '@react-router/serve': + optional: true + '@vitejs/plugin-rsc': + optional: true + react-server-dom-webpack: + optional: true + typescript: + optional: true + wrangler: + optional: true + + '@react-router/node@8.5.0': + resolution: {integrity: sha512-9a3a37TW5GAo/J336Uk1tca/X1OxjpseETz/zCHcojtL7oRlFrlFoDt6wSdCtFRCiwlLyHcWY+qwZ+xnb05kSg==} + engines: {node: '>=22.22.0'} + peerDependencies: + react-router: 8.5.0 + typescript: ^5.1.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@remix-run/node-fetch-server@0.14.2': + resolution: {integrity: sha512-1cpM/f5i1ka/9CUMBwZXZp7Bn92x8VQjzg+F4eEe88DlVdNHkAKrf/vvbZoYgdkfy2bWHtGC6LQGLmojEqOF4Q==} + '@remix-run/route-pattern@0.22.1': resolution: {integrity: sha512-czdGJWh09Lapvcqt7Vb09KlrU2PhRJ8xQaI+AItTuD9aDJ5MAgxnS38lnys6Ll+6RJEqPiaUqTwIQhVLwFvv+w==} @@ -3326,6 +3397,9 @@ packages: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -3396,6 +3470,10 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} @@ -3507,6 +3585,14 @@ packages: decode-named-character-reference@1.0.2: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + default-browser-id@5.0.1: resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} @@ -3666,6 +3752,10 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + exit-hook@5.1.0: + resolution: {integrity: sha512-INjr2xyxHo7bhAqf5ong++GZPPnpcuBcaXUKt03yf7Fie9yWD7FapL4teOU0+awQazGs5ucBh7xWs/AD+6nhog==} + engines: {node: '>=20'} + expect-type@1.4.0: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} @@ -3844,6 +3934,10 @@ packages: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} + isbot@5.2.2: + resolution: {integrity: sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w==} + engines: {node: '>=18'} + jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true @@ -3867,6 +3961,11 @@ packages: engines: {node: '>=6'} hasBin: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -4050,6 +4149,9 @@ packages: resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} engines: {node: '>=14'} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -4286,6 +4388,10 @@ packages: vite-plus: optional: true + p-map@7.1.1: + resolution: {integrity: sha512-6Lh3jQPLthYujSrlw6ccWXBGZTkoTCz27Hd92g79LH/kjAbgoEu0t442cCCNbegPSJsA0lwDX8z0bcKtkpA32g==} + engines: {node: '>=18'} + package-manager-detector@1.8.0: resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} @@ -4410,6 +4516,10 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + react-router@8.5.0: resolution: {integrity: sha512-9nEd/deifcTJIIcUaNIyQGkyXD0D6QVB9XD2O5GgHpP3xu3U5RXm87YQ8++Wn8JQWgMBM/5+PjWPM/7n7O7WHA==} engines: {node: '>=22.22.0'} @@ -4448,6 +4558,10 @@ packages: resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==} engines: {node: '>=0.10.0'} + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -4812,6 +4926,14 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + valibot@1.5.0: + resolution: {integrity: sha512-nil6AkP2TChWL43Z5uJ6GTxX01CUA+g8LWUM+N/rB9NBbkUMaUsi9PUNzlUPgoKASgmx9f7eGOYpJ04/fSa6FQ==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + verkit@0.5.0: resolution: {integrity: sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==} engines: {node: '>=18.12.0'} @@ -5875,6 +5997,51 @@ snapshots: dependencies: quansync: 1.0.0 + '@react-router/dev@8.5.0(@vitejs/plugin-rsc@packages+plugin-rsc)(babel-plugin-macros@3.1.0)(react-router@8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(typescript@7.0.2)(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(yaml@2.9.1))(wrangler@4.151.2(@types/node@24.19.2))': + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@react-router/node': 8.5.0(react-router@8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(typescript@7.0.2) + '@remix-run/node-fetch-server': 0.14.2 + babel-dead-code-elimination: 1.0.12 + chokidar: 5.0.0 + dedent: 1.7.2(babel-plugin-macros@3.1.0) + es-module-lexer: 2.3.2 + exit-hook: 5.1.0 + isbot: 5.2.2 + jsesc: 3.1.0 + lodash: 4.18.1 + p-map: 7.1.1 + pathe: 2.0.3 + picocolors: 1.1.1 + pkg-types: 2.3.3 + react-refresh: 0.18.0 + react-router: 8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + semver: 7.8.5 + tinyglobby: 0.2.17 + valibot: 1.5.0(typescript@7.0.2) + vite: 8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(yaml@2.9.1) + optionalDependencies: + '@vitejs/plugin-rsc': link:packages/plugin-rsc + react-server-dom-webpack: 19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + typescript: 7.0.2 + wrangler: 4.151.2(@types/node@24.19.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + '@react-router/node@8.5.0(react-router@8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(typescript@7.0.2)': + dependencies: + '@remix-run/node-fetch-server': 0.14.2 + react-router: 8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + optionalDependencies: + typescript: 7.0.2 + + '@remix-run/node-fetch-server@0.14.2': {} + '@remix-run/route-pattern@0.22.1': {} '@rolldown/binding-android-arm-eabi@1.2.14': @@ -6420,6 +6587,15 @@ snapshots: astring@1.8.6: {} + babel-dead-code-elimination@1.0.12: + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + babel-plugin-macros@3.1.0: dependencies: '@babel/runtime': 7.23.5 @@ -6478,6 +6654,10 @@ snapshots: character-reference-invalid@2.0.1: {} + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + collapse-white-space@2.1.0: {} comma-separated-tokens@2.0.3: {} @@ -6576,6 +6756,10 @@ snapshots: dependencies: character-entities: 2.0.2 + dedent@1.7.2(babel-plugin-macros@3.1.0): + optionalDependencies: + babel-plugin-macros: 3.1.0 + default-browser-id@5.0.1: {} default-browser@5.5.1: @@ -6739,6 +6923,8 @@ snapshots: dependencies: '@types/estree': 1.0.9 + exit-hook@5.1.0: {} + expect-type@1.4.0: {} exsolve@1.1.3: {} @@ -6921,6 +7107,8 @@ snapshots: dependencies: is-inside-container: 1.0.0 + isbot@5.2.2: {} + jiti@2.7.0: {} js-tokens@10.0.0: {} @@ -6937,6 +7125,8 @@ snapshots: jsesc@3.0.2: {} + jsesc@3.1.0: {} + json-parse-even-better-errors@2.3.1: {} json5@2.2.3: {} @@ -7070,6 +7260,8 @@ snapshots: pkg-types: 2.3.3 quansync: 0.2.11 + lodash@4.18.1: {} + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -7548,6 +7740,8 @@ snapshots: '@oxlint/binding-win32-x64-msvc': 1.89.0 oxlint-tsgolint: 7.0.2004 + p-map@7.1.1: {} + package-manager-detector@1.8.0: {} parent-module@1.0.1: @@ -7674,6 +7868,8 @@ snapshots: react-is@16.13.1: {} + react-refresh@0.18.0: {} + react-router@8.5.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: '@remix-run/route-pattern': 0.22.1 @@ -7704,6 +7900,8 @@ snapshots: react@19.3.1: {} + readdirp@5.1.1: {} + refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.2 @@ -8080,6 +8278,10 @@ snapshots: utils-merge@1.0.1: {} + valibot@1.5.0(typescript@7.0.2): + optionalDependencies: + typescript: 7.0.2 + verkit@0.5.0: {} vfile-message@4.0.2: