From 89cb733fa5f5af56a00a47970ca725fcd3180df3 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 26 Aug 2026 08:02:07 +0330 Subject: [PATCH 1/3] ci: run the test suite on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turn the tests job into an os matrix (ubuntu-latest, windows-latest), fail-fast off. The posix-separator regression test is trivially green on Linux — it only fails on a Windows runner, where node:path relative() emits backslashes. Without Windows in CI the invariant is pinned but never enforced; this makes the regression impossible to reintroduce unnoticed. --- .github/workflows/tests.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b249002..187e2b5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,8 +14,12 @@ permissions: jobs: tests: - name: Build and test - runs-on: ubuntu-latest + name: Build and test (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v4 From 06993310731802808357bbccf3c5f71ed4d2d81a Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 26 Aug 2026 07:38:12 +0330 Subject: [PATCH 2/3] test: assert the exact serialized lazy-ref src value in both code-splitting modes --- test/vite.spec.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/vite.spec.ts b/test/vite.spec.ts index d0af478..302d012 100644 --- a/test/vite.spec.ts +++ b/test/vite.spec.ts @@ -85,6 +85,21 @@ describe("fileRoutes vite plugin", () => { expect(code.match(/pick=default&pick=\$css&lang\.tsx'\)/g)?.length).toBe(2); }); + it("serializes lazy-ref src values with forward slashes", async () => { + const directory = createRouteTree({ + "index.tsx": "export default () =>

Home

;" + }); + + const split = await loadVirtualModule(directory); + const eager = await loadWith(createPlugin(directory, { codeSplitting: false }), directory); + + // `src` is matched against Vite's manifest keys, which are always posix, + // so it must not carry the platform separator node:path emits on Windows + const src = '"src":"src/routes/index.tsx?pick=default&pick=$css&lang.tsx"'; + expect(split).toContain(src); + expect(eager).toContain(src); + }); + it("resolves only the virtual module id", async () => { const [plugin] = fileRoutes() as any[]; expect(moduleId).toBe("virtual:file-routes"); From 5cd77a607448f2e1c643e4374693bcba4368a824 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 26 Aug 2026 07:53:17 +0330 Subject: [PATCH 3/3] fix: normalize lazy-ref src values to posix separators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit node:path relative() emits Windows separators, which never match Vite's always-posix client-manifest keys — SSR hydration preloads miss and server lazy() breaks. Every other path in the pipeline is already normalized through normalizePath(); these two sites were the only ones missed. Turns the regression test from the previous commit green on Windows. --- src/vite/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vite/index.ts b/src/vite/index.ts index 4279b50..3bc19fa 100644 --- a/src/vite/index.ts +++ b/src/vite/index.ts @@ -319,12 +319,12 @@ export function fileRoutes(options: FileRoutesOptions = {}): PluginOption[] { // plus the `src` lazy refs already expose. if (!codeSplitting) { return { - src: relative(root, buildId), + src: normalizePath(relative(root, buildId)), require: `_$() => (${js.addNamespaceImport(buildId)})$_` }; } return { - src: relative(root, buildId), + src: normalizePath(relative(root, buildId)), build: isBuild ? `_$() => import('${buildId}')$_` : undefined, import: `_$() => import('${buildId}')$_` };