diff --git a/.changeset/four-olives-design.md b/.changeset/four-olives-design.md new file mode 100644 index 00000000000..2cedb70681e --- /dev/null +++ b/.changeset/four-olives-design.md @@ -0,0 +1,5 @@ +--- +'@tanstack/start-plugin-core': patch +--- + +Omit build-only route file paths from the production Start manifest so identical builds do not depend on their checkout directory. diff --git a/packages/start-plugin-core/src/start-manifest-plugin/manifestBuilder.ts b/packages/start-plugin-core/src/start-manifest-plugin/manifestBuilder.ts index 02a85865928..c8fa130f329 100644 --- a/packages/start-plugin-core/src/start-manifest-plugin/manifestBuilder.ts +++ b/packages/start-plugin-core/src/start-manifest-plugin/manifestBuilder.ts @@ -285,9 +285,10 @@ export function buildStartManifest(options: { dedupeNestedRouteManifestEntries(rootRouteId, routes[rootRouteId]!, routes) - // Prune routes with no manifest data + // Remove build-only paths and prune routes with no manifest data for (const routeId in routes) { const route = routes[routeId]! + delete route.filePath const hasScripts = route.scripts && route.scripts.length > 0 const hasCssLinks = route.css && route.css.length > 0 const hasPreloads = route.preloads && route.preloads.length > 0 diff --git a/packages/start-plugin-core/tests/start-manifest-plugin/manifestBuilder.test.ts b/packages/start-plugin-core/tests/start-manifest-plugin/manifestBuilder.test.ts index ad34b92e282..d46938b9867 100644 --- a/packages/start-plugin-core/tests/start-manifest-plugin/manifestBuilder.test.ts +++ b/packages/start-plugin-core/tests/start-manifest-plugin/manifestBuilder.test.ts @@ -301,6 +301,57 @@ describe('createChunkCssAssetCollector', () => { }) describe('buildStartManifest', () => { + // https://github.com/TanStack/router/commit/49b01ffea0304938d5ec9a9822c8bb8ea5c18091 + test('production manifests are independent of the checkout path', () => { + const outputs = ['/checkout/app', '/another/location/app'].map((root) => { + const rootPath = `${root}/src/routes/__root.tsx` + const aboutPath = `${root}/src/routes/about.tsx` + const routeTreeRoutes = { + __root__: Object.freeze({ + filePath: rootPath, + children: ['/about'], + }), + '/about': Object.freeze({ filePath: aboutPath }), + } + const manifest = buildStartManifest({ + clientBuild: normalizeTestBuild({ + 'entry.js': makeChunk({ + fileName: 'entry.js', + isEntry: true, + importedCss: ['entry.css'], + moduleIds: [`${rootPath}?tsr-split=component`], + }), + 'about.js': makeChunk({ + fileName: 'about.js', + importedCss: ['about.css'], + moduleIds: [`${aboutPath}?tsr-split=component`], + }), + }), + routeTreeRoutes, + basePath: '/assets', + }) + const serialized = serializeStartManifest(manifest) + const emitted = deserializeSerializedManifest(serialized) + + expect(routeTreeRoutes.__root__).toEqual({ + filePath: rootPath, + children: ['/about'], + }) + expect(routeTreeRoutes['/about']).toEqual({ filePath: aboutPath }) + expect(emitted.routes.__root__?.preloads).toEqual(['/assets/entry.js']) + expect(emitted.routes.__root__?.scripts).toEqual([ + { attrs: { type: 'module', async: true, src: '/assets/entry.js' } }, + ]) + expect(emitted.routes.__root__?.css).toEqual(['/assets/entry.css']) + expect(emitted.routes['/about']?.preloads).toEqual(['/assets/about.js']) + expect(emitted.routes['/about']?.css).toEqual(['/assets/about.css']) + + return serialized + }) + + expect(outputs[0]).toBe(outputs[1]) + }) + test('skips inline CSS transforms when no relative URLs need rebasing', () => { expect(shouldRebaseInlineCssUrls('.root {\n color: red;\n}')).toBe(false) expect(shouldRebaseInlineCssUrls('.root{background:url(/dot.svg)}')).toBe(