diff --git a/.changeset/quiet-prerender-root.md b/.changeset/quiet-prerender-root.md new file mode 100644 index 00000000000..c178e6cd905 --- /dev/null +++ b/.changeset/quiet-prerender-root.md @@ -0,0 +1,5 @@ +--- +'@tanstack/start-plugin-core': patch +--- + +Resolve the prerender paths against Vite's resolved `root` instead of `process.cwd()`. When the root is not the working directory, `vite build ` and `createBuilder({ root })` previously failed to start the preview server or wrote `index.html`, `pages.json` and `sitemap.xml` outside the project. diff --git a/packages/start-plugin-core/src/vite/post-server-build.ts b/packages/start-plugin-core/src/vite/post-server-build.ts index 2e74b7635d1..5ad1b40445e 100644 --- a/packages/start-plugin-core/src/vite/post-server-build.ts +++ b/packages/start-plugin-core/src/vite/post-server-build.ts @@ -1,3 +1,4 @@ +import { resolve } from 'pathe' import { postBuild } from '../post-build' import { getClientOutputDirectory } from './output-directory' import { prerenderWithVite } from './prerender' @@ -15,7 +16,7 @@ export async function postServerBuild({ startConfig, adapter: { getClientOutputDirectory() { - return getClientOutputDirectory(builder.config) + return resolve(builder.config.root, getClientOutputDirectory(builder.config)) }, prerender(startConfig) { return prerenderWithVite({ diff --git a/packages/start-plugin-core/src/vite/prerender.ts b/packages/start-plugin-core/src/vite/prerender.ts index 5d1838e43aa..7d2f0eafbca 100644 --- a/packages/start-plugin-core/src/vite/prerender.ts +++ b/packages/start-plugin-core/src/vite/prerender.ts @@ -1,3 +1,4 @@ +import { resolve } from 'pathe' import { VITE_ENVIRONMENT_NAMES } from '../constants' import { prerender } from '../prerender' import type { PrerenderHandler } from '../prerender' @@ -26,7 +27,10 @@ export async function prerenderWithVite({ ) } - const outputDir = clientEnv.config.build.outDir + const outputDir = resolve( + clientEnv.config.root, + clientEnv.config.build.outDir, + ) process.env.TSS_PRERENDERING = 'true' process.env.TSS_CLIENT_OUTPUT_DIR = outputDir @@ -66,6 +70,9 @@ async function startPreviewServer( try { return await vite.preview({ + // Reuse the root the build resolved, so the preview config is not + // re-resolved against `process.cwd()` when the root is not the cwd. + root: viteConfig.root, configFile: viteConfig.configFile, preview: { port: 0, diff --git a/packages/start-plugin-core/src/vite/preview-server-plugin/plugin.ts b/packages/start-plugin-core/src/vite/preview-server-plugin/plugin.ts index 1541d9edfbe..d9c815b855b 100644 --- a/packages/start-plugin-core/src/vite/preview-server-plugin/plugin.ts +++ b/packages/start-plugin-core/src/vite/preview-server-plugin/plugin.ts @@ -1,5 +1,5 @@ import { pathToFileURL } from 'node:url' -import { basename, extname, join } from 'pathe' +import { basename, extname, join, resolve } from 'pathe' import { NodeRequest, sendNodeResponse } from 'srvx/node' import { joinURL } from 'ufo' import { VITE_ENVIRONMENT_NAMES } from '../../constants' @@ -36,7 +36,10 @@ export function previewServerPlugin(): Plugin { // Get basename without extension and add .js const outputFilename = `${basename(serverInput, extname(serverInput))}.js` - const serverOutputDir = getServerOutputDirectory(server.config) + const serverOutputDir = resolve( + server.config.root, + getServerOutputDirectory(server.config), + ) const serverEntryPath = join(serverOutputDir, outputFilename) const imported = await import( pathToFileURL(serverEntryPath).toString() diff --git a/packages/start-plugin-core/tests/prerender-vite.test.ts b/packages/start-plugin-core/tests/prerender-vite.test.ts index 013557e4dfa..12fb0fc12fe 100644 --- a/packages/start-plugin-core/tests/prerender-vite.test.ts +++ b/packages/start-plugin-core/tests/prerender-vite.test.ts @@ -122,4 +122,31 @@ describe('Vite prerender network sink', () => { 'http://127.0.0.1:4173/next/?from=about', ]) }) + + it('resolves the client output directory and the preview root against the Vite root', async () => { + vi.stubGlobal( + 'fetch', + vi.fn(async () => new Response(null, { status: 200 })), + ) + const builder = { + environments: { + ssr: { + config: { root: '/repo/project', configFile: '/vite.config.ts' }, + }, + client: { + config: { root: '/repo/project', build: { outDir: 'dist/client' } }, + }, + }, + } as any + + await prerenderWithVite({ + startConfig: { ...makeStartConfig(), pages: [] }, + builder, + }) + + expect(preview).toHaveBeenCalledWith( + expect.objectContaining({ root: '/repo/project' }), + ) + expect(process.env.TSS_CLIENT_OUTPUT_DIR).toBe('/repo/project/dist/client') + }) })