@tanstack/start-plugin-core 1.169.1 → 1.169.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/esm/rsbuild/normalized-client-build.js +9 -1
  2. package/dist/esm/rsbuild/normalized-client-build.js.map +1 -1
  3. package/dist/esm/rsbuild/plugin.js +4 -1
  4. package/dist/esm/rsbuild/plugin.js.map +1 -1
  5. package/dist/esm/rsbuild/schema.d.ts +8 -0
  6. package/dist/esm/rsbuild/virtual-modules.js +14 -13
  7. package/dist/esm/rsbuild/virtual-modules.js.map +1 -1
  8. package/dist/esm/schema.d.ts +25 -0
  9. package/dist/esm/schema.js +4 -1
  10. package/dist/esm/schema.js.map +1 -1
  11. package/dist/esm/start-manifest-plugin/inlineCss.d.ts +6 -0
  12. package/dist/esm/start-manifest-plugin/inlineCss.js +59 -0
  13. package/dist/esm/start-manifest-plugin/inlineCss.js.map +1 -0
  14. package/dist/esm/start-manifest-plugin/manifestBuilder.d.ts +4 -0
  15. package/dist/esm/start-manifest-plugin/manifestBuilder.js +32 -2
  16. package/dist/esm/start-manifest-plugin/manifestBuilder.js.map +1 -1
  17. package/dist/esm/types.d.ts +1 -0
  18. package/dist/esm/vite/planning.d.ts +3 -0
  19. package/dist/esm/vite/planning.js +1 -0
  20. package/dist/esm/vite/planning.js.map +1 -1
  21. package/dist/esm/vite/plugin.js +1 -0
  22. package/dist/esm/vite/plugin.js.map +1 -1
  23. package/dist/esm/vite/schema.d.ts +8 -0
  24. package/dist/esm/vite/start-manifest-plugin/normalized-client-build.js +11 -1
  25. package/dist/esm/vite/start-manifest-plugin/normalized-client-build.js.map +1 -1
  26. package/dist/esm/vite/start-manifest-plugin/plugin.js +2 -1
  27. package/dist/esm/vite/start-manifest-plugin/plugin.js.map +1 -1
  28. package/package.json +8 -7
  29. package/src/rsbuild/normalized-client-build.ts +14 -0
  30. package/src/rsbuild/plugin.ts +7 -0
  31. package/src/rsbuild/virtual-modules.ts +15 -5
  32. package/src/schema.ts +6 -0
  33. package/src/start-manifest-plugin/inlineCss.ts +93 -0
  34. package/src/start-manifest-plugin/manifestBuilder.ts +72 -2
  35. package/src/types.ts +1 -0
  36. package/src/vite/planning.ts +5 -0
  37. package/src/vite/plugin.ts +2 -0
  38. package/src/vite/start-manifest-plugin/normalized-client-build.ts +19 -0
  39. package/src/vite/start-manifest-plugin/plugin.ts +2 -1
@@ -1,3 +1,4 @@
1
+ import { getCssAssetSource } from "../start-manifest-plugin/inlineCss.js";
1
2
  import { RSBUILD_ENVIRONMENT_NAMES } from "./planning.js";
2
3
  import { tsrSplit } from "@tanstack/router-plugin";
3
4
  //#region src/rsbuild/normalized-client-build.ts
@@ -104,6 +105,7 @@ function normalizeRspackClientBuild(compilation) {
104
105
  const chunksByFileName = /* @__PURE__ */ new Map();
105
106
  const chunkFileNamesByRouteFilePath = /* @__PURE__ */ new Map();
106
107
  const cssFilesBySourcePath = /* @__PURE__ */ new Map();
108
+ const cssContentByFileName = /* @__PURE__ */ new Map();
107
109
  let entryChunkFileName;
108
110
  const entrypoint = compilation.entrypoints.get("index");
109
111
  const initialJsFileNames = [];
@@ -161,6 +163,11 @@ function normalizeRspackClientBuild(compilation) {
161
163
  }
162
164
  }
163
165
  if (!entryChunkFileName) throw new Error("No entry file found in rspack client build");
166
+ for (const asset of compilation.getAssets()) {
167
+ if (!asset.name.endsWith(".css")) continue;
168
+ const css = getCssAssetSource(asset.source.source());
169
+ if (css !== void 0) cssContentByFileName.set(asset.name, css);
170
+ }
164
171
  const rscEntrypoint = compilation.entrypoints.get("rsc");
165
172
  if (rscEntrypoint && entryChunkFileName) {
166
173
  const mainEntryChunk = chunksByFileName.get(entryChunkFileName);
@@ -173,7 +180,8 @@ function normalizeRspackClientBuild(compilation) {
173
180
  entryChunkFileName,
174
181
  chunksByFileName,
175
182
  chunkFileNamesByRouteFilePath,
176
- cssFilesBySourcePath
183
+ cssFilesBySourcePath,
184
+ cssContentByFileName
177
185
  };
178
186
  }
179
187
  function appendUniqueStrings(target, source) {
@@ -1 +1 @@
1
- {"version":3,"file":"normalized-client-build.js","names":[],"sources":["../../../src/rsbuild/normalized-client-build.ts"],"sourcesContent":["import { tsrSplit } from '@tanstack/router-plugin'\nimport { RSBUILD_ENVIRONMENT_NAMES } from './planning'\nimport type { RsbuildPluginAPI, Rspack } from '@rsbuild/core'\nimport type { NormalizedClientBuild, NormalizedClientChunk } from '../types'\n\ntype ProcessAssetsContext = Parameters<\n Parameters<RsbuildPluginAPI['processAssets']>[1]\n>[0]\ntype RspackCompilation = Rspack.Compilation\ntype RspackCompilationChunk = Rspack.Chunk\ntype RspackModule = Rspack.Module\n\n/**\n * Extract route file paths from rspack module identifiers.\n *\n * In rspack, module identifiers contain query params similar to Vite's moduleIds.\n * We look for the `tsr-split` query to identify route-split chunks.\n */\nfunction getRouteFilePathsFromModules(\n modules: Array<RspackModule>,\n): Array<string> {\n let routeFilePaths: Array<string> | undefined\n let seen: Set<string> | undefined\n\n for (const mod of modules) {\n const identifier = mod.identifier()\n\n // rspack module identifiers include loader prefixes separated by '!'.\n // The actual file path (with query string) is after the last '!'.\n // Example: \"builtin:swc-loader??ruleSet[...]!.../transform.js??...!.../rsc-basic.tsx?tsr-split=component\"\n const lastBangIndex = identifier.lastIndexOf('!')\n const resourcePart =\n lastBangIndex >= 0 ? identifier.slice(lastBangIndex + 1) : identifier\n\n const queryIndex = resourcePart.indexOf('?')\n if (queryIndex < 0) continue\n\n const query = resourcePart.slice(queryIndex + 1)\n if (!query.includes(tsrSplit)) continue\n if (!new URLSearchParams(query).has(tsrSplit)) continue\n\n const nameForCondition = mod.nameForCondition()\n const routeFilePath = nameForCondition ?? resourcePart.slice(0, queryIndex)\n\n if (seen?.has(routeFilePath)) continue\n\n if (!routeFilePaths || !seen) {\n routeFilePaths = []\n seen = new Set()\n }\n\n routeFilePaths.push(routeFilePath)\n seen.add(routeFilePath)\n }\n\n return routeFilePaths ?? []\n}\n\n/**\n * Returns true for Rspack/webpack HMR runtime chunks that should never be\n * surfaced to the Start manifest. These files are emitted on every rebuild\n * (e.g. `index.<hash>.hot-update.mjs`) and must not be treated as the entry\n * chunk, route preloads, or sibling imports.\n */\nfunction isHotUpdateAsset(file: string): boolean {\n return file.includes('.hot-update.')\n}\n\n/**\n * True for any JS/MJS asset that should be included in the manifest.\n * Excludes HMR runtime patches.\n */\nfunction isManifestJsAsset(file: string): boolean {\n if (!file.endsWith('.js') && !file.endsWith('.mjs')) return false\n return !isHotUpdateAsset(file)\n}\n\n/**\n * Get all JS file names from a chunk.\n */\nfunction getChunkJsFiles(chunk: RspackCompilationChunk): Array<string> {\n const jsFiles: Array<string> = []\n for (const file of chunk.files) {\n if (isManifestJsAsset(file)) {\n jsFiles.push(file)\n }\n }\n return jsFiles\n}\n\n/**\n * Compute dynamicImports for a chunk by traversing its chunk groups'\n * childrenIterable (async/dynamic import edges).\n *\n * In rspack, a chunk belongs to one or more ChunkGroups. Each ChunkGroup\n * has childrenIterable — child ChunkGroups representing dynamic import()\n * points. The JS files from those child groups' chunks are the\n * dynamicImports (analogous to Rollup's OutputChunk.dynamicImports).\n */\nfunction computeDynamicImports(chunk: RspackCompilationChunk): Array<string> {\n const dynamicImportFiles: Array<string> = []\n const seen = new Set<string>()\n\n for (const group of chunk.groupsIterable) {\n for (const childGroup of group.childrenIterable) {\n for (const childChunk of childGroup.chunks) {\n for (const file of childChunk.files) {\n if (isManifestJsAsset(file) && !seen.has(file)) {\n seen.add(file)\n dynamicImportFiles.push(file)\n }\n }\n }\n }\n }\n\n return dynamicImportFiles\n}\n\n/**\n * Compute static imports (sibling chunks) for an async chunk.\n *\n * In rspack/webpack, an async chunk's ChunkGroup contains ALL chunks needed to\n * satisfy that dynamic import — the async chunk itself plus any shared/vendor\n * chunks it statically imports. This is analogous to Rollup's\n * `OutputChunk.imports` for async chunks.\n *\n * We collect JS files from all sibling chunks in the group (excluding the\n * current chunk's own file) to populate the `imports` field.\n */\nfunction computeAsyncChunkImports(\n chunk: RspackCompilationChunk,\n currentFile: string,\n): Array<string> {\n const imports: Array<string> = []\n const seen = new Set<string>()\n seen.add(currentFile)\n\n for (const group of chunk.groupsIterable) {\n for (const siblingChunk of group.chunks) {\n for (const file of siblingChunk.files) {\n if (isManifestJsAsset(file) && !seen.has(file)) {\n seen.add(file)\n imports.push(file)\n }\n }\n }\n }\n\n return imports\n}\n\n/**\n * Normalize an rspack compilation into a NormalizedClientBuild.\n *\n * Iterates ALL chunks in the compilation (initial + async), not just\n * entrypoint chunks, to ensure route-split async chunks are included.\n */\nexport function normalizeRspackClientBuild(\n compilation: RspackCompilation,\n): NormalizedClientBuild {\n const chunksByFileName = new Map<string, NormalizedClientChunk>()\n const chunkFileNamesByRouteFilePath = new Map<string, Array<string>>()\n const cssFilesBySourcePath = new Map<string, Array<string>>()\n let entryChunkFileName: string | undefined\n\n // Collect all initial JS file names from the main entry for computing\n // the entry chunk's `imports` (vendor/shared sibling chunks).\n const entrypoint = compilation.entrypoints.get('index')\n const initialJsFileNames: Array<string> = []\n const entryChunkSet = new Set<RspackCompilationChunk>()\n if (entrypoint) {\n for (const chunk of entrypoint.chunks) {\n entryChunkSet.add(chunk)\n for (const file of chunk.files) {\n if (isManifestJsAsset(file)) {\n initialJsFileNames.push(file)\n }\n }\n }\n }\n\n // Iterate ALL chunks (initial + async) to capture route-split chunks\n for (const chunk of compilation.chunks) {\n const modules = compilation.chunkGraph.getChunkModules(chunk)\n const routeFilePaths = getRouteFilePathsFromModules(modules)\n const cssFiles: Array<string> = []\n const seenCssFiles = new Set<string>()\n\n for (const auxFile of chunk.auxiliaryFiles) {\n if (auxFile.endsWith('.css') && !seenCssFiles.has(auxFile)) {\n seenCssFiles.add(auxFile)\n cssFiles.push(auxFile)\n }\n }\n\n for (const mainFile of chunk.files) {\n if (mainFile.endsWith('.css') && !seenCssFiles.has(mainFile)) {\n seenCssFiles.add(mainFile)\n cssFiles.push(mainFile)\n }\n }\n\n if (cssFiles.length > 0) {\n for (const mod of modules) {\n const sourcePath = mod.nameForCondition()\n if (!sourcePath) continue\n\n const existing = cssFilesBySourcePath.get(sourcePath)\n cssFilesBySourcePath.set(\n sourcePath,\n existing ? appendUniqueStrings(existing, cssFiles) : cssFiles.slice(),\n )\n }\n }\n\n // The entry chunk is the one named 'index' in the 'index' entrypoint\n const isEntryChunk = chunk.name === 'index' && entryChunkSet.has(chunk)\n\n const jsFiles = getChunkJsFiles(chunk)\n if (jsFiles.length === 0) continue\n\n // Compute dynamicImports from chunk group children\n const dynamicImports = computeDynamicImports(chunk)\n\n for (const file of jsFiles) {\n // For the entry chunk, `imports` contains all sibling initial chunks\n // (vendor/shared). For async chunks, `imports` contains all sibling\n // chunks from the ChunkGroup (shared dependencies the browser must\n // load alongside this chunk). This mirrors Rollup's\n // OutputChunk.imports which lists statically imported chunks.\n const imports = isEntryChunk\n ? initialJsFileNames.filter((f) => f !== file)\n : computeAsyncChunkImports(chunk, file)\n\n const normalizedChunk: NormalizedClientChunk = {\n fileName: file,\n isEntry: isEntryChunk,\n imports,\n dynamicImports,\n css: [],\n routeFilePaths,\n }\n\n chunksByFileName.set(file, normalizedChunk)\n\n if (isEntryChunk && !entryChunkFileName) {\n entryChunkFileName = file\n }\n\n for (const routeFilePath of routeFilePaths) {\n let chunkFileNames = chunkFileNamesByRouteFilePath.get(routeFilePath)\n if (!chunkFileNames) {\n chunkFileNames = []\n chunkFileNamesByRouteFilePath.set(routeFilePath, chunkFileNames)\n }\n chunkFileNames.push(file)\n }\n }\n\n for (const cssFile of cssFiles) {\n for (const file of jsFiles) {\n const existing = chunksByFileName.get(file)\n if (existing && !existing.css.includes(cssFile)) {\n existing.css.push(cssFile)\n }\n }\n }\n }\n\n if (!entryChunkFileName) {\n throw new Error('No entry file found in rspack client build')\n }\n\n // In RSC mode, CSS from server components is associated with the 'rsc'\n // client entry chunk (not the main 'index' entry). The manifest builder\n // merges the entry chunk's CSS into __root__, so by appending RSC CSS\n // to the entry chunk, those stylesheets get loaded on all pages.\n // CSS may appear in either `files` or `auxiliaryFiles` depending on\n // rspack's CSS extraction strategy.\n const rscEntrypoint = compilation.entrypoints.get('rsc')\n\n if (rscEntrypoint && entryChunkFileName) {\n const mainEntryChunk = chunksByFileName.get(entryChunkFileName)\n if (mainEntryChunk) {\n for (const rscChunk of rscEntrypoint.chunks) {\n const allFiles = [...rscChunk.files, ...rscChunk.auxiliaryFiles]\n for (const file of allFiles) {\n if (file.endsWith('.css') && !mainEntryChunk.css.includes(file)) {\n mainEntryChunk.css.push(file)\n }\n }\n }\n }\n }\n\n return {\n entryChunkFileName,\n chunksByFileName,\n chunkFileNamesByRouteFilePath,\n cssFilesBySourcePath,\n }\n}\n\nfunction appendUniqueStrings(\n target: Array<string>,\n source: Array<string>,\n): Array<string> {\n const seen = new Set(target)\n let result: Array<string> | undefined\n\n for (const value of source) {\n if (seen.has(value)) continue\n seen.add(value)\n if (!result) {\n result = target.slice()\n }\n result.push(value)\n }\n\n return result ?? target\n}\n\n/**\n * Registers a processAssets hook to capture the client build stats\n * after compilation. Returns a getter for the captured build.\n */\nexport function registerClientBuildCapture(api: RsbuildPluginAPI): {\n getClientBuild: () => NormalizedClientBuild | undefined\n} {\n let clientBuild: NormalizedClientBuild | undefined\n\n api.processAssets(\n {\n stage: 'report',\n environments: [RSBUILD_ENVIRONMENT_NAMES.client],\n },\n (context: ProcessAssetsContext) => {\n clientBuild = normalizeRspackClientBuild(context.compilation)\n },\n )\n\n return {\n getClientBuild: () => clientBuild,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"normalized-client-build.js","names":[],"sources":["../../../src/rsbuild/normalized-client-build.ts"],"sourcesContent":["import { tsrSplit } from '@tanstack/router-plugin'\nimport { getCssAssetSource } from '../start-manifest-plugin/inlineCss'\nimport { RSBUILD_ENVIRONMENT_NAMES } from './planning'\nimport type { RsbuildPluginAPI, Rspack } from '@rsbuild/core'\nimport type { NormalizedClientBuild, NormalizedClientChunk } from '../types'\n\ntype ProcessAssetsContext = Parameters<\n Parameters<RsbuildPluginAPI['processAssets']>[1]\n>[0]\ntype RspackCompilation = Rspack.Compilation\ntype RspackCompilationChunk = Rspack.Chunk\ntype RspackModule = Rspack.Module\n\n/**\n * Extract route file paths from rspack module identifiers.\n *\n * In rspack, module identifiers contain query params similar to Vite's moduleIds.\n * We look for the `tsr-split` query to identify route-split chunks.\n */\nfunction getRouteFilePathsFromModules(\n modules: Array<RspackModule>,\n): Array<string> {\n let routeFilePaths: Array<string> | undefined\n let seen: Set<string> | undefined\n\n for (const mod of modules) {\n const identifier = mod.identifier()\n\n // rspack module identifiers include loader prefixes separated by '!'.\n // The actual file path (with query string) is after the last '!'.\n // Example: \"builtin:swc-loader??ruleSet[...]!.../transform.js??...!.../rsc-basic.tsx?tsr-split=component\"\n const lastBangIndex = identifier.lastIndexOf('!')\n const resourcePart =\n lastBangIndex >= 0 ? identifier.slice(lastBangIndex + 1) : identifier\n\n const queryIndex = resourcePart.indexOf('?')\n if (queryIndex < 0) continue\n\n const query = resourcePart.slice(queryIndex + 1)\n if (!query.includes(tsrSplit)) continue\n if (!new URLSearchParams(query).has(tsrSplit)) continue\n\n const nameForCondition = mod.nameForCondition()\n const routeFilePath = nameForCondition ?? resourcePart.slice(0, queryIndex)\n\n if (seen?.has(routeFilePath)) continue\n\n if (!routeFilePaths || !seen) {\n routeFilePaths = []\n seen = new Set()\n }\n\n routeFilePaths.push(routeFilePath)\n seen.add(routeFilePath)\n }\n\n return routeFilePaths ?? []\n}\n\n/**\n * Returns true for Rspack/webpack HMR runtime chunks that should never be\n * surfaced to the Start manifest. These files are emitted on every rebuild\n * (e.g. `index.<hash>.hot-update.mjs`) and must not be treated as the entry\n * chunk, route preloads, or sibling imports.\n */\nfunction isHotUpdateAsset(file: string): boolean {\n return file.includes('.hot-update.')\n}\n\n/**\n * True for any JS/MJS asset that should be included in the manifest.\n * Excludes HMR runtime patches.\n */\nfunction isManifestJsAsset(file: string): boolean {\n if (!file.endsWith('.js') && !file.endsWith('.mjs')) return false\n return !isHotUpdateAsset(file)\n}\n\n/**\n * Get all JS file names from a chunk.\n */\nfunction getChunkJsFiles(chunk: RspackCompilationChunk): Array<string> {\n const jsFiles: Array<string> = []\n for (const file of chunk.files) {\n if (isManifestJsAsset(file)) {\n jsFiles.push(file)\n }\n }\n return jsFiles\n}\n\n/**\n * Compute dynamicImports for a chunk by traversing its chunk groups'\n * childrenIterable (async/dynamic import edges).\n *\n * In rspack, a chunk belongs to one or more ChunkGroups. Each ChunkGroup\n * has childrenIterable — child ChunkGroups representing dynamic import()\n * points. The JS files from those child groups' chunks are the\n * dynamicImports (analogous to Rollup's OutputChunk.dynamicImports).\n */\nfunction computeDynamicImports(chunk: RspackCompilationChunk): Array<string> {\n const dynamicImportFiles: Array<string> = []\n const seen = new Set<string>()\n\n for (const group of chunk.groupsIterable) {\n for (const childGroup of group.childrenIterable) {\n for (const childChunk of childGroup.chunks) {\n for (const file of childChunk.files) {\n if (isManifestJsAsset(file) && !seen.has(file)) {\n seen.add(file)\n dynamicImportFiles.push(file)\n }\n }\n }\n }\n }\n\n return dynamicImportFiles\n}\n\n/**\n * Compute static imports (sibling chunks) for an async chunk.\n *\n * In rspack/webpack, an async chunk's ChunkGroup contains ALL chunks needed to\n * satisfy that dynamic import — the async chunk itself plus any shared/vendor\n * chunks it statically imports. This is analogous to Rollup's\n * `OutputChunk.imports` for async chunks.\n *\n * We collect JS files from all sibling chunks in the group (excluding the\n * current chunk's own file) to populate the `imports` field.\n */\nfunction computeAsyncChunkImports(\n chunk: RspackCompilationChunk,\n currentFile: string,\n): Array<string> {\n const imports: Array<string> = []\n const seen = new Set<string>()\n seen.add(currentFile)\n\n for (const group of chunk.groupsIterable) {\n for (const siblingChunk of group.chunks) {\n for (const file of siblingChunk.files) {\n if (isManifestJsAsset(file) && !seen.has(file)) {\n seen.add(file)\n imports.push(file)\n }\n }\n }\n }\n\n return imports\n}\n\n/**\n * Normalize an rspack compilation into a NormalizedClientBuild.\n *\n * Iterates ALL chunks in the compilation (initial + async), not just\n * entrypoint chunks, to ensure route-split async chunks are included.\n */\nexport function normalizeRspackClientBuild(\n compilation: RspackCompilation,\n): NormalizedClientBuild {\n const chunksByFileName = new Map<string, NormalizedClientChunk>()\n const chunkFileNamesByRouteFilePath = new Map<string, Array<string>>()\n const cssFilesBySourcePath = new Map<string, Array<string>>()\n const cssContentByFileName = new Map<string, string>()\n let entryChunkFileName: string | undefined\n\n // Collect all initial JS file names from the main entry for computing\n // the entry chunk's `imports` (vendor/shared sibling chunks).\n const entrypoint = compilation.entrypoints.get('index')\n const initialJsFileNames: Array<string> = []\n const entryChunkSet = new Set<RspackCompilationChunk>()\n if (entrypoint) {\n for (const chunk of entrypoint.chunks) {\n entryChunkSet.add(chunk)\n for (const file of chunk.files) {\n if (isManifestJsAsset(file)) {\n initialJsFileNames.push(file)\n }\n }\n }\n }\n\n // Iterate ALL chunks (initial + async) to capture route-split chunks\n for (const chunk of compilation.chunks) {\n const modules = compilation.chunkGraph.getChunkModules(chunk)\n const routeFilePaths = getRouteFilePathsFromModules(modules)\n const cssFiles: Array<string> = []\n const seenCssFiles = new Set<string>()\n\n for (const auxFile of chunk.auxiliaryFiles) {\n if (auxFile.endsWith('.css') && !seenCssFiles.has(auxFile)) {\n seenCssFiles.add(auxFile)\n cssFiles.push(auxFile)\n }\n }\n\n for (const mainFile of chunk.files) {\n if (mainFile.endsWith('.css') && !seenCssFiles.has(mainFile)) {\n seenCssFiles.add(mainFile)\n cssFiles.push(mainFile)\n }\n }\n\n if (cssFiles.length > 0) {\n for (const mod of modules) {\n const sourcePath = mod.nameForCondition()\n if (!sourcePath) continue\n\n const existing = cssFilesBySourcePath.get(sourcePath)\n cssFilesBySourcePath.set(\n sourcePath,\n existing ? appendUniqueStrings(existing, cssFiles) : cssFiles.slice(),\n )\n }\n }\n\n // The entry chunk is the one named 'index' in the 'index' entrypoint\n const isEntryChunk = chunk.name === 'index' && entryChunkSet.has(chunk)\n\n const jsFiles = getChunkJsFiles(chunk)\n if (jsFiles.length === 0) continue\n\n // Compute dynamicImports from chunk group children\n const dynamicImports = computeDynamicImports(chunk)\n\n for (const file of jsFiles) {\n // For the entry chunk, `imports` contains all sibling initial chunks\n // (vendor/shared). For async chunks, `imports` contains all sibling\n // chunks from the ChunkGroup (shared dependencies the browser must\n // load alongside this chunk). This mirrors Rollup's\n // OutputChunk.imports which lists statically imported chunks.\n const imports = isEntryChunk\n ? initialJsFileNames.filter((f) => f !== file)\n : computeAsyncChunkImports(chunk, file)\n\n const normalizedChunk: NormalizedClientChunk = {\n fileName: file,\n isEntry: isEntryChunk,\n imports,\n dynamicImports,\n css: [],\n routeFilePaths,\n }\n\n chunksByFileName.set(file, normalizedChunk)\n\n if (isEntryChunk && !entryChunkFileName) {\n entryChunkFileName = file\n }\n\n for (const routeFilePath of routeFilePaths) {\n let chunkFileNames = chunkFileNamesByRouteFilePath.get(routeFilePath)\n if (!chunkFileNames) {\n chunkFileNames = []\n chunkFileNamesByRouteFilePath.set(routeFilePath, chunkFileNames)\n }\n chunkFileNames.push(file)\n }\n }\n\n for (const cssFile of cssFiles) {\n for (const file of jsFiles) {\n const existing = chunksByFileName.get(file)\n if (existing && !existing.css.includes(cssFile)) {\n existing.css.push(cssFile)\n }\n }\n }\n }\n\n if (!entryChunkFileName) {\n throw new Error('No entry file found in rspack client build')\n }\n\n for (const asset of compilation.getAssets()) {\n if (!asset.name.endsWith('.css')) {\n continue\n }\n\n const css = getCssAssetSource(asset.source.source())\n if (css !== undefined) {\n cssContentByFileName.set(asset.name, css)\n }\n }\n\n // In RSC mode, CSS from server components is associated with the 'rsc'\n // client entry chunk (not the main 'index' entry). The manifest builder\n // merges the entry chunk's CSS into __root__, so by appending RSC CSS\n // to the entry chunk, those stylesheets get loaded on all pages.\n // CSS may appear in either `files` or `auxiliaryFiles` depending on\n // rspack's CSS extraction strategy.\n const rscEntrypoint = compilation.entrypoints.get('rsc')\n\n if (rscEntrypoint && entryChunkFileName) {\n const mainEntryChunk = chunksByFileName.get(entryChunkFileName)\n if (mainEntryChunk) {\n for (const rscChunk of rscEntrypoint.chunks) {\n const allFiles = [...rscChunk.files, ...rscChunk.auxiliaryFiles]\n for (const file of allFiles) {\n if (file.endsWith('.css') && !mainEntryChunk.css.includes(file)) {\n mainEntryChunk.css.push(file)\n }\n }\n }\n }\n }\n\n return {\n entryChunkFileName,\n chunksByFileName,\n chunkFileNamesByRouteFilePath,\n cssFilesBySourcePath,\n cssContentByFileName,\n }\n}\n\nfunction appendUniqueStrings(\n target: Array<string>,\n source: Array<string>,\n): Array<string> {\n const seen = new Set(target)\n let result: Array<string> | undefined\n\n for (const value of source) {\n if (seen.has(value)) continue\n seen.add(value)\n if (!result) {\n result = target.slice()\n }\n result.push(value)\n }\n\n return result ?? target\n}\n\n/**\n * Registers a processAssets hook to capture the client build stats\n * after compilation. Returns a getter for the captured build.\n */\nexport function registerClientBuildCapture(api: RsbuildPluginAPI): {\n getClientBuild: () => NormalizedClientBuild | undefined\n} {\n let clientBuild: NormalizedClientBuild | undefined\n\n api.processAssets(\n {\n stage: 'report',\n environments: [RSBUILD_ENVIRONMENT_NAMES.client],\n },\n (context: ProcessAssetsContext) => {\n clientBuild = normalizeRspackClientBuild(context.compilation)\n },\n )\n\n return {\n getClientBuild: () => clientBuild,\n }\n}\n"],"mappings":"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"}
@@ -86,6 +86,7 @@ function tanStackStartRsbuild(corePluginOpts, startPluginOpts = {}) {
86
86
  routerBasepath,
87
87
  serverFnBase: startConfig.serverFns.base
88
88
  });
89
+ const inlineCssEnabled = !isDev && startConfig.server.build.inlineCss;
89
90
  return mergeRsbuildConfig(rsbuildConfig, {
90
91
  source: { define: {
91
92
  "process.env.TSS_SERVER_FN_BASE": JSON.stringify(serverFnBase),
@@ -97,7 +98,9 @@ function tanStackStartRsbuild(corePluginOpts, startPluginOpts = {}) {
97
98
  "process.env.TSS_DEV_SSR_STYLES_ENABLED": JSON.stringify("false"),
98
99
  "import.meta.env.TSS_DEV_SSR_STYLES_ENABLED": JSON.stringify("false"),
99
100
  "process.env.TSS_DEV_SSR_STYLES_BASEPATH": JSON.stringify(resolvedStartConfig.basePaths.publicBase),
100
- "import.meta.env.TSS_DEV_SSR_STYLES_BASEPATH": JSON.stringify(resolvedStartConfig.basePaths.publicBase)
101
+ "import.meta.env.TSS_DEV_SSR_STYLES_BASEPATH": JSON.stringify(resolvedStartConfig.basePaths.publicBase),
102
+ "process.env.TSS_INLINE_CSS_ENABLED": JSON.stringify(inlineCssEnabled ? "true" : "false"),
103
+ "import.meta.env.TSS_INLINE_CSS_ENABLED": JSON.stringify(inlineCssEnabled ? "true" : "false")
101
104
  } },
102
105
  server: {
103
106
  htmlFallback: false,
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../../../src/rsbuild/plugin.ts"],"sourcesContent":["import { existsSync, readdirSync, realpathSync, statSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { joinURL } from 'ufo'\nimport {\n applyResolvedBaseAndOutput,\n applyResolvedRouterBasepath,\n createStartConfigContext,\n} from '../config-context'\nimport { normalizePath } from '../utils'\nimport { createServerFnBasePath, normalizePublicBase } from '../planning'\nimport { parseStartConfig } from './schema'\nimport {\n RSBUILD_ENVIRONMENT_NAMES,\n RSBUILD_RSC_LAYERS,\n createRsbuildEnvironmentPlan,\n createRsbuildResolvedEntryAliases,\n resolveRsbuildOutputDirectory,\n} from './planning'\nimport { registerStartCompilerTransforms } from './start-compiler-host'\nimport { registerImportProtection } from './import-protection'\nimport {\n START_MANIFEST_PLACEHOLDER,\n registerVirtualModules,\n} from './virtual-modules'\nimport { createServerSetup } from './dev-server'\nimport { registerClientBuildCapture } from './normalized-client-build'\nimport { registerRouterPlugins } from './start-router-plugin'\nimport { postBuildWithRsbuild } from './post-build'\nimport { enableSwcReactServerComponents } from './swc-rsc'\nimport type { ServerFn } from '../start-compiler/types'\nimport type { TanStackStartRsbuildPluginCoreOptions } from './types'\nimport type {\n ModifyRspackConfigFn,\n RsbuildDevServer,\n RsbuildPlugin,\n RsbuildPluginAPI,\n Rspack,\n rspack as rspackNamespaceType,\n} from '@rsbuild/core'\nimport type { TanStackStartRsbuildInputConfig } from './schema'\n\n// Detect whether this plugin source is running from inside the TanStack\n// Router monorepo (packages/start-plugin-core/src/rsbuild/plugin.ts). When\n// installed from npm in a user app, the path structure is different and\n// this evaluates to false. Used to gate dev-only workarounds that only\n// matter when workspace package dists are symlinked into node_modules.\nconst currentDir = dirname(fileURLToPath(import.meta.url))\nconst isInsideRouterMonoRepo = (() => {\n // src layout: <repo>/packages/start-plugin-core/src/rsbuild → 4 levels up\n // dist layout (CJS/ESM): <repo>/packages/start-plugin-core/dist/<fmt>/rsbuild\n // → also 4 levels up\n const candidate = resolve(currentDir, '../../../../')\n return candidate.endsWith('/packages') || candidate.endsWith('\\\\packages')\n})()\n\ntype RspackNamespace = typeof rspackNamespaceType\ntype RscPluginPair = ReturnType<\n NonNullable<RspackNamespace['experiments']['rsc']>['createPlugins']\n>\ntype RspackConfig = Parameters<ModifyRspackConfigFn>[0]\ntype RspackCompiler = Rspack.Compiler\ntype RspackCompilationExtended = Rspack.Compilation\n\nexport function tanStackStartRsbuild(\n corePluginOpts: TanStackStartRsbuildPluginCoreOptions,\n startPluginOpts: TanStackStartRsbuildInputConfig = {},\n): RsbuildPlugin {\n const rscOpts = corePluginOpts.rsc\n const rscEnabled = Boolean(rscOpts)\n\n const configContext = createStartConfigContext({\n corePluginOpts,\n startPluginOpts,\n parseConfig: parseStartConfig,\n })\n const { getConfig, resolvedStartConfig } = configContext\n const serverFnProviderEnv = corePluginOpts.providerEnvironmentName\n const ssrIsProvider = corePluginOpts.ssrIsProvider\n\n // RSC plugin instances — created lazily when rspack namespace is available\n let rscPlugins: RscPluginPair | undefined\n\n // Reference to the dev server for RSC HMR socket writes\n let devServerRef: Pick<RsbuildDevServer, 'sockWrite'> | null = null\n const serverFnsById: Record<string, ServerFn> = {}\n let updateServerFnResolver: (() => void) | undefined\n\n return {\n name: 'tanstack-start-rsbuild',\n setup(api: RsbuildPluginAPI) {\n // ---------------------------------------------------------------\n // 1. modifyRsbuildConfig — resolve config, set up environments\n // ---------------------------------------------------------------\n api.modifyRsbuildConfig((rsbuildConfig, { mergeRsbuildConfig }) => {\n const root =\n typeof rsbuildConfig.root === 'string'\n ? rsbuildConfig.root\n : process.cwd()\n\n const serverBase = rsbuildConfig.server?.base\n const assetPrefix = rsbuildConfig.output?.assetPrefix\n const publicBase = normalizePublicBase(\n typeof serverBase === 'string'\n ? serverBase\n : typeof assetPrefix === 'string' && assetPrefix !== 'auto'\n ? assetPrefix\n : undefined,\n )\n const rootDistPath = rsbuildConfig.output?.distPath\n const clientDistPath =\n rsbuildConfig.environments?.[RSBUILD_ENVIRONMENT_NAMES.client]?.output\n ?.distPath\n const serverDistPath =\n rsbuildConfig.environments?.[RSBUILD_ENVIRONMENT_NAMES.server]?.output\n ?.distPath\n\n applyResolvedBaseAndOutput({\n resolvedStartConfig,\n root,\n publicBase,\n clientOutputDirectory: resolveRsbuildOutputDirectory({\n distPath: clientDistPath,\n rootDistPath,\n fallback: 'dist/client',\n subdirectory: 'client',\n }),\n serverOutputDirectory: resolveRsbuildOutputDirectory({\n distPath: serverDistPath,\n rootDistPath,\n fallback: 'dist/server',\n subdirectory: 'server',\n }),\n })\n\n const { startConfig } = getConfig()\n const routerBasepath = applyResolvedRouterBasepath({\n resolvedStartConfig,\n startConfig,\n })\n\n const resolvedEntryPlan = configContext.resolveEntries()\n const isDev = api.context.action === 'dev'\n\n const entryAliases = createRsbuildResolvedEntryAliases({\n entryPaths: resolvedEntryPlan.entryPaths,\n })\n\n const environmentPlan = createRsbuildEnvironmentPlan({\n root,\n entryAliases,\n clientOutputDirectory: resolvedStartConfig.outputDirectories.client,\n serverOutputDirectory: resolvedStartConfig.outputDirectories.server,\n publicBase: resolvedStartConfig.basePaths.publicBase,\n serverFnProviderEnv,\n environmentOverrides: corePluginOpts.rsbuild?.environments,\n rsc: rscOpts,\n dev: isDev,\n })\n const serverFnBase = createServerFnBasePath({\n routerBasepath,\n serverFnBase: startConfig.serverFns.base,\n })\n\n return mergeRsbuildConfig(rsbuildConfig, {\n source: {\n define: {\n 'process.env.TSS_SERVER_FN_BASE': JSON.stringify(serverFnBase),\n 'import.meta.env.TSS_SERVER_FN_BASE':\n JSON.stringify(serverFnBase),\n 'process.env.TSS_ROUTER_BASEPATH': JSON.stringify(routerBasepath),\n 'import.meta.env.TSS_ROUTER_BASEPATH':\n JSON.stringify(routerBasepath),\n 'process.env.TSS_DEV_SERVER': JSON.stringify(\n isDev ? 'true' : 'false',\n ),\n 'import.meta.env.TSS_DEV_SERVER': JSON.stringify(\n isDev ? 'true' : 'false',\n ),\n // Rsbuild dev already injects emitted CSS asset hrefs, so keep\n // Start's synthetic `/@tanstack-start/styles.css` path disabled.\n 'process.env.TSS_DEV_SSR_STYLES_ENABLED': JSON.stringify('false'),\n 'import.meta.env.TSS_DEV_SSR_STYLES_ENABLED':\n JSON.stringify('false'),\n 'process.env.TSS_DEV_SSR_STYLES_BASEPATH': JSON.stringify(\n resolvedStartConfig.basePaths.publicBase,\n ),\n 'import.meta.env.TSS_DEV_SSR_STYLES_BASEPATH': JSON.stringify(\n resolvedStartConfig.basePaths.publicBase,\n ),\n },\n },\n server: {\n // SSR apps render every route on the server — disable HTML\n // fallback so rsbuild doesn't intercept /_serverFn/ URLs.\n htmlFallback: false,\n // server.setup returned callback runs after built-in middleware\n // but BEFORE fallback middleware — the ideal slot for SSR.\n ...(isDev &&\n startPluginOpts.rsbuild?.installDevServerMiddleware !== false\n ? {\n setup: createServerSetup({\n serverFnBasePath: serverFnBase,\n }),\n }\n : {}),\n },\n ...(isDev\n ? {\n dev: {\n lazyCompilation: false,\n ...(rscEnabled ? { liveReload: false } : {}),\n },\n }\n : {}),\n environments: environmentPlan.environments,\n resolve: {\n alias: environmentPlan.alias,\n },\n })\n })\n\n // ---------------------------------------------------------------\n // 2. StartCompiler transforms — server fns, isomorphic fns, etc.\n // ---------------------------------------------------------------\n registerStartCompilerTransforms(api, {\n framework: corePluginOpts.framework,\n // modifyRsbuildConfig copies rsbuildConfig.root into resolvedStartConfig.root,\n // so defer this read until transform time instead of falling back to\n // process.cwd() during plugin setup.\n root: () => resolvedStartConfig.root || process.cwd(),\n providerEnvName: serverFnProviderEnv,\n generateFunctionId: startPluginOpts.serverFns?.generateFunctionId,\n serverFnsById,\n onServerFnsByIdChange: () => {\n updateServerFnResolver?.()\n },\n })\n\n registerImportProtection(api, {\n getConfig,\n framework: corePluginOpts.framework,\n environments: [\n { name: RSBUILD_ENVIRONMENT_NAMES.client, type: 'client' },\n { name: RSBUILD_ENVIRONMENT_NAMES.server, type: 'server' },\n ...(serverFnProviderEnv !== RSBUILD_ENVIRONMENT_NAMES.server &&\n !rscEnabled\n ? [{ name: serverFnProviderEnv, type: 'server' as const }]\n : []),\n ],\n })\n\n // ---------------------------------------------------------------\n // 3. Virtual modules — manifest, server fn resolver, adapters,\n // RSC runtime, RSC HMR\n // ---------------------------------------------------------------\n const virtualModuleState = registerVirtualModules(api, {\n root: resolvedStartConfig.root || process.cwd(),\n getConfig,\n serverFnsById,\n providerEnvName: serverFnProviderEnv,\n ssrIsProvider,\n serializationAdapters: corePluginOpts.serializationAdapters,\n getDevClientEntryUrl: (publicBase: string) =>\n joinURL(publicBase, 'static/js/index.js'),\n rscEnabled,\n })\n updateServerFnResolver = virtualModuleState.updateServerFnResolver\n\n // ---------------------------------------------------------------\n // 4. Client build stats capture via processAssets\n // ---------------------------------------------------------------\n const { getClientBuild } = registerClientBuildCapture(api)\n\n // ---------------------------------------------------------------\n // 4b. Server manifest module generation (build only)\n // For ordinary multi-environment builds, Rsbuild can compile the\n // server environment after the client environment finishes. Generate\n // the final manifest as module source in that phase instead of\n // patching emitted server assets afterwards.\n // ---------------------------------------------------------------\n if (api.context.action !== 'dev') {\n const normalizedManifestPath = normalizePath(\n virtualModuleState.manifestPath,\n )\n const matchesManifestPath = (id: string) =>\n normalizePath(id) === normalizedManifestPath\n\n api.transform(\n {\n test: (id: string) => matchesManifestPath(id),\n environments: [RSBUILD_ENVIRONMENT_NAMES.server],\n },\n ({ code }) => {\n const clientBuild = getClientBuild()\n\n if (clientBuild) {\n return virtualModuleState.generateManifestContent(clientBuild)\n }\n\n if (!rscEnabled) {\n throw new Error(\n 'TanStack Start could not generate the rsbuild server manifest before the client build completed',\n )\n }\n\n // RSC builds cannot express the required client -> server ordering\n // through MultiCompiler dependencies, so keep the placeholder for\n // the RSC-only asset-patching fallback below.\n return code\n },\n )\n }\n\n // ---------------------------------------------------------------\n // 5. Router plugin wiring (generator + code splitter)\n // ---------------------------------------------------------------\n registerRouterPlugins(api, {\n getConfig,\n corePluginOpts,\n startPluginOpts,\n })\n\n // ---------------------------------------------------------------\n // 6. Dev SSR middleware — registered via server.setup in\n // modifyRsbuildConfig above (returned callback runs after\n // built-ins but before fallback middleware)\n // ---------------------------------------------------------------\n\n // ---------------------------------------------------------------\n // 6b. Dev watcher: ignore workspace package `dist/**` directories.\n //\n // In a real user app, `@tanstack/react-router` and friends live\n // inside `node_modules/` and are ignored by Rspack's default\n // watcher. In this monorepo, pnpm symlinks them to\n // `packages/*/dist` (realpath outside node_modules), so the\n // watcher follows them and treats their dist files as live\n // sources. If anything rewrites those files during dev, Rspack\n // sees transient half-written modules and fails to resolve\n // relative imports between them.\n //\n // Only apply this in monorepo development. In user apps this\n // is a no-op — their `node_modules/@tanstack/*/dist/**` is\n // already ignored by Rspack's default watchOptions.\n // ---------------------------------------------------------------\n if (isInsideRouterMonoRepo && api.context.action === 'dev') {\n api.modifyRspackConfig((config) => {\n const workspaceDistRealpaths = resolveWorkspacePackageDistRealpaths()\n if (workspaceDistRealpaths.length === 0) return\n\n const workspaceDistIgnored = new RegExp(\n workspaceDistRealpaths\n .map((path) => `^${escapeRegExp(path)}(?:[\\\\\\\\/]|$)`)\n .join('|'),\n )\n const ignored = config.watchOptions?.ignored\n\n config.watchOptions = {\n ...(config.watchOptions ?? {}),\n ignored:\n ignored == null\n ? new RegExp(\n `${defaultRspackWatchIgnored.source}|${workspaceDistIgnored.source}`,\n )\n : typeof ignored === 'string'\n ? [ignored, ...workspaceDistRealpaths]\n : Array.isArray(ignored)\n ? [...ignored, ...workspaceDistRealpaths]\n : new RegExp(\n `${ignored.source}|${workspaceDistIgnored.source}`,\n ),\n }\n })\n }\n\n // ---------------------------------------------------------------\n // 7. RSC: rspack layer rules + native RSC plugins\n // When RSC is enabled, we add:\n // - issuerLayer rule for react-server condition propagation\n // - SWC reactServerComponents: true\n // - rspack ServerPlugin (server env) / ClientPlugin (client env)\n // The Coordinator inside createPlugins() handles compilation\n // ordering (server→client→server-actions) automatically.\n // ---------------------------------------------------------------\n if (rscEnabled) {\n api.modifyRspackConfig((config, utils) => {\n const envName = utils.environment.name\n const isServerEnv = envName === RSBUILD_ENVIRONMENT_NAMES.server\n const isClientEnv = envName === RSBUILD_ENVIRONMENT_NAMES.client\n\n // Create RSC plugin pair lazily (once per build)\n if (!rscPlugins) {\n rscPlugins = utils.rspack.experiments.rsc.createPlugins()\n }\n\n if (isServerEnv) {\n // --- issuerLayer rule: modules imported from RSC layer\n // get react-server resolve condition ---\n const moduleRules = (config.module.rules ??= [])\n const root = resolvedStartConfig.root || process.cwd()\n\n // Split server-fn provider modules are the actual RSC execution\n // boundary in Start's layered model. They must compile in the\n // RSC layer so React and react-server-dom-rspack resolve their\n // react-server exports without forcing the whole SSR graph into\n // react-server conditions.\n moduleRules.push({\n resourceQuery: /(?:^|[?&])tss-serverfn-split(?:&|$)/,\n layer: RSBUILD_RSC_LAYERS.rsc,\n resolve: {\n conditionNames: ['react-server', '...'],\n },\n })\n\n // All modules imported from the RSC layer inherit\n // the react-server condition (transitive propagation), except\n // route split virtual modules. Those remain ordinary SSR/client\n // route code; only `?tsr-shared=1` modules may be shared with the\n // provider subtree.\n moduleRules.push({\n issuerLayer: RSBUILD_RSC_LAYERS.rsc,\n resourceQuery: {\n not: [/(?:^|[?&])tsr-split(?:=|&|$)/],\n },\n resolve: {\n conditionNames: ['react-server', '...'],\n },\n })\n\n // The RSC ServerPlugin injects imports like\n // `react-server-dom-rspack/server` into transformed modules.\n // Some modules in the server graph resolve from real package paths\n // outside the app root, so relying on the default relative\n // `node_modules` lookup is not enough. Seed resolve.modules with the\n // app root explicitly, without package-manager-specific heuristics.\n seedResolveModules(config, [`${root}/node_modules`, 'node_modules'])\n\n // Add ServerPlugin with HMR callback\n config.plugins.push(\n new rscPlugins.ServerPlugin({\n clientEntryName: 'index',\n runtimeEntryName: 'index',\n injectSsrModulesToEntries: ['index'],\n onServerComponentChanges: () => {\n // Send rsc:update to connected clients for HMR\n devServerRef?.sockWrite('custom', {\n event: 'rsc:update',\n })\n },\n }),\n )\n\n config.plugins.push({\n apply(compiler: RspackCompiler) {\n compiler.hooks.finishMake.tapPromise(\n {\n name: 'TanStackStartRscServerFnResolverRebuild',\n stage: -10,\n },\n async (compilation: RspackCompilationExtended) => {\n if (Object.keys(serverFnsById).length === 0) {\n return\n }\n\n const resolverContent =\n virtualModuleState.generateCurrentResolverContent(true)\n virtualModuleState.tryUpdateServerFnResolver(\n resolverContent,\n )\n\n await rebuildModulesContaining(\n compilation,\n virtualModuleState.serverFnResolverPath,\n )\n },\n )\n },\n })\n\n if (api.context.action !== 'dev') {\n config.plugins.push({\n apply(compiler: RspackCompiler) {\n compiler.hooks.finishMake.tapPromise(\n {\n name: 'TanStackStartRscManifestRebuild',\n // The native RSC ServerPlugin completes the client-entry\n // handoff during its finishMake hook. Rebuild the manifest\n // after that point so the transform hook can emit the final\n // manifest source instead of the placeholder.\n stage: 10,\n },\n async (compilation: RspackCompilationExtended) => {\n const clientBuild = getClientBuild()\n\n if (!clientBuild) {\n return\n }\n\n virtualModuleState.updateManifest(clientBuild)\n\n await rebuildModulesContaining(\n compilation,\n virtualModuleState.manifestPath,\n )\n },\n )\n },\n })\n }\n }\n\n if (isClientEnv) {\n // Add ClientPlugin — the Coordinator links it to the\n // ServerPlugin's compilation state\n config.plugins.push(new rscPlugins.ClientPlugin())\n }\n\n // --- SWC reactServerComponents ---\n // Enable RSC directive detection where the native RSC plugins need it.\n // In the server build, scope it to the actual RSC provider subtree so\n // ordinary route-split modules (e.g. ?tsr-split=component) stay out of\n // RSC validation unless they are really imported by a provider module.\n if (isServerEnv) {\n enableSwcReactServerComponents(config, 'rsc-subtree')\n } else if (isClientEnv) {\n enableSwcReactServerComponents(config, 'all')\n }\n })\n\n // Capture dev server reference for RSC HMR socket writes\n if (api.context.action === 'dev') {\n api.onBeforeStartDevServer(({ server }) => {\n devServerRef = server\n })\n }\n }\n\n // ---------------------------------------------------------------\n // 8. Build ordering — client must complete before server starts\n // so that the manifest virtual module has real client build stats.\n // Uses rspack MultiCompiler.setDependencies() under the hood.\n //\n // IMPORTANT: When RSC is enabled we must NOT set dependencies.\n // The RSC Coordinator already orchestrates server↔client\n // compilation ordering by interleaving phases within compiler\n // hooks. Adding setDependencies(server, [client]) on top of\n // the Coordinator creates a deadlock: MultiCompiler blocks\n // the server compiler until client is `done`, but the\n // Coordinator blocks the client's `make` hook until the\n // server's entries phase completes — neither can start.\n // ---------------------------------------------------------------\n if (!rscEnabled) {\n api.onAfterCreateCompiler(({ compiler }) => {\n // MultiCompiler has a `compilers` array; single compiler does not\n if ('compilers' in compiler) {\n const serverCompiler = compiler.compilers.find(\n (c) => c.name === RSBUILD_ENVIRONMENT_NAMES.server,\n )\n if (serverCompiler) {\n compiler.setDependencies(serverCompiler, [\n RSBUILD_ENVIRONMENT_NAMES.client,\n ])\n }\n }\n })\n }\n\n // ---------------------------------------------------------------\n // 8b. Manifest asset replacement fallback (RSC build only)\n // Rsbuild's native RSC coordinator interleaves server and client\n // compilers, so the server manifest module can compile before Start's\n // normalized client build stats exist. Keep final replacement in the\n // server asset pipeline, after the client processAssets capture has a\n // chance to run.\n // ---------------------------------------------------------------\n if (api.context.action !== 'dev' && rscEnabled) {\n const manifestPlaceholderLiteral = JSON.stringify(\n START_MANIFEST_PLACEHOLDER,\n )\n api.modifyRspackConfig((config, utils) => {\n if (utils.environment.name !== RSBUILD_ENVIRONMENT_NAMES.server)\n return\n\n config.plugins.push({\n apply(compiler: RspackCompiler) {\n compiler.hooks.compilation.tap(\n 'TanStackStartManifestReplace',\n (compilation: RspackCompilationExtended) => {\n compilation.hooks.processAssets.tap(\n {\n name: 'TanStackStartManifestReplace',\n stage:\n utils.rspack.Compilation\n .PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,\n },\n () => {\n const assetsWithPlaceholder = compilation\n .getAssets()\n .flatMap((asset) => {\n if (!asset.name.endsWith('.js')) return []\n\n const sourceStr = String(asset.source.source())\n return sourceStr.includes(manifestPlaceholderLiteral)\n ? [{ asset, sourceStr }]\n : []\n })\n\n if (assetsWithPlaceholder.length === 0) return\n\n const clientBuild = getClientBuild()\n if (!clientBuild) {\n throw new Error(\n 'TanStack Start could not replace the rsbuild RSC server manifest placeholder because the client build was unavailable',\n )\n }\n\n const manifestValueLiteral =\n virtualModuleState.generateManifestValueLiteral(\n clientBuild,\n )\n\n for (const {\n asset,\n sourceStr,\n } of assetsWithPlaceholder) {\n compilation.updateAsset(\n asset.name,\n new utils.rspack.sources.RawSource(\n sourceStr.replace(\n manifestPlaceholderLiteral,\n manifestValueLiteral,\n ),\n ),\n )\n }\n },\n )\n },\n )\n },\n })\n })\n }\n\n // ---------------------------------------------------------------\n // 9. After client env compiles — refresh resolver + manifest\n // ---------------------------------------------------------------\n api.onAfterEnvironmentCompile(({ environment }) => {\n if (environment.name !== RSBUILD_ENVIRONMENT_NAMES.client) return\n\n virtualModuleState.updateServerFnResolver()\n\n const clientBuild = getClientBuild()\n if (clientBuild) {\n virtualModuleState.updateManifest(clientBuild)\n }\n })\n\n if (api.context.action === 'build') {\n api.onAfterBuild(async () => {\n const { startConfig } = getConfig()\n\n await postBuildWithRsbuild({\n startConfig,\n clientOutputDirectory: resolvedStartConfig.outputDirectories.client,\n serverOutputDirectory: resolvedStartConfig.outputDirectories.server,\n })\n })\n }\n },\n }\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nconst defaultRspackWatchIgnored = /[\\\\/](?:\\.git|node_modules)[\\\\/]/\n\nfunction seedResolveModules(\n config: RspackConfig,\n entries: Array<string>,\n): void {\n const resolveModules = (config.resolve.modules ??= [])\n\n for (const entry of entries) {\n if (!resolveModules.includes(entry)) {\n resolveModules.push(entry)\n }\n }\n}\n\nfunction rebuildModulesContaining(\n compilation: RspackCompilationExtended,\n identifierFragment: string,\n): Promise<void> {\n const modulesToRebuild = Array.from(compilation.modules).filter((mod) =>\n mod.identifier().includes(identifierFragment),\n )\n\n if (modulesToRebuild.length === 0) {\n return Promise.resolve()\n }\n\n return Promise.all(\n modulesToRebuild.map(\n (mod) =>\n new Promise<void>((resolve, reject) => {\n compilation.rebuildModule(mod, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n }),\n ),\n ).then(() => undefined)\n}\n\n/**\n * Return the realpath of every packages/<name>/dist directory in the\n * TanStack Router monorepo. Only meaningful when called from inside the\n * monorepo — in user apps, callers should guard with\n * `isInsideRouterMonoRepo` before invoking this.\n */\nfunction resolveWorkspacePackageDistRealpaths(): Array<string> {\n // currentDir points at either <repo>/packages/start-plugin-core/src/rsbuild\n // or <repo>/packages/start-plugin-core/dist/<fmt>/rsbuild. Four levels up\n // lands on <repo>/packages in both layouts.\n const packagesDir = resolve(currentDir, '../../../../')\n if (!existsSync(packagesDir)) return []\n\n let entries: Array<string>\n try {\n entries = readdirSync(packagesDir)\n } catch {\n return []\n }\n\n const dists: Array<string> = []\n for (const entry of entries) {\n const distPath = join(packagesDir, entry, 'dist')\n try {\n if (!statSync(distPath).isDirectory()) continue\n } catch {\n continue\n }\n try {\n dists.push(realpathSync(distPath))\n } catch {\n dists.push(distPath)\n }\n }\n\n return dists\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../../../src/rsbuild/plugin.ts"],"sourcesContent":["import { existsSync, readdirSync, realpathSync, statSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { joinURL } from 'ufo'\nimport {\n applyResolvedBaseAndOutput,\n applyResolvedRouterBasepath,\n createStartConfigContext,\n} from '../config-context'\nimport { normalizePath } from '../utils'\nimport { createServerFnBasePath, normalizePublicBase } from '../planning'\nimport { parseStartConfig } from './schema'\nimport {\n RSBUILD_ENVIRONMENT_NAMES,\n RSBUILD_RSC_LAYERS,\n createRsbuildEnvironmentPlan,\n createRsbuildResolvedEntryAliases,\n resolveRsbuildOutputDirectory,\n} from './planning'\nimport { registerStartCompilerTransforms } from './start-compiler-host'\nimport { registerImportProtection } from './import-protection'\nimport {\n START_MANIFEST_PLACEHOLDER,\n registerVirtualModules,\n} from './virtual-modules'\nimport { createServerSetup } from './dev-server'\nimport { registerClientBuildCapture } from './normalized-client-build'\nimport { registerRouterPlugins } from './start-router-plugin'\nimport { postBuildWithRsbuild } from './post-build'\nimport { enableSwcReactServerComponents } from './swc-rsc'\nimport type { ServerFn } from '../start-compiler/types'\nimport type { TanStackStartRsbuildPluginCoreOptions } from './types'\nimport type {\n ModifyRspackConfigFn,\n RsbuildDevServer,\n RsbuildPlugin,\n RsbuildPluginAPI,\n Rspack,\n rspack as rspackNamespaceType,\n} from '@rsbuild/core'\nimport type { TanStackStartRsbuildInputConfig } from './schema'\n\n// Detect whether this plugin source is running from inside the TanStack\n// Router monorepo (packages/start-plugin-core/src/rsbuild/plugin.ts). When\n// installed from npm in a user app, the path structure is different and\n// this evaluates to false. Used to gate dev-only workarounds that only\n// matter when workspace package dists are symlinked into node_modules.\nconst currentDir = dirname(fileURLToPath(import.meta.url))\nconst isInsideRouterMonoRepo = (() => {\n // src layout: <repo>/packages/start-plugin-core/src/rsbuild → 4 levels up\n // dist layout (CJS/ESM): <repo>/packages/start-plugin-core/dist/<fmt>/rsbuild\n // → also 4 levels up\n const candidate = resolve(currentDir, '../../../../')\n return candidate.endsWith('/packages') || candidate.endsWith('\\\\packages')\n})()\n\ntype RspackNamespace = typeof rspackNamespaceType\ntype RscPluginPair = ReturnType<\n NonNullable<RspackNamespace['experiments']['rsc']>['createPlugins']\n>\ntype RspackConfig = Parameters<ModifyRspackConfigFn>[0]\ntype RspackCompiler = Rspack.Compiler\ntype RspackCompilationExtended = Rspack.Compilation\n\nexport function tanStackStartRsbuild(\n corePluginOpts: TanStackStartRsbuildPluginCoreOptions,\n startPluginOpts: TanStackStartRsbuildInputConfig = {},\n): RsbuildPlugin {\n const rscOpts = corePluginOpts.rsc\n const rscEnabled = Boolean(rscOpts)\n\n const configContext = createStartConfigContext({\n corePluginOpts,\n startPluginOpts,\n parseConfig: parseStartConfig,\n })\n const { getConfig, resolvedStartConfig } = configContext\n const serverFnProviderEnv = corePluginOpts.providerEnvironmentName\n const ssrIsProvider = corePluginOpts.ssrIsProvider\n\n // RSC plugin instances — created lazily when rspack namespace is available\n let rscPlugins: RscPluginPair | undefined\n\n // Reference to the dev server for RSC HMR socket writes\n let devServerRef: Pick<RsbuildDevServer, 'sockWrite'> | null = null\n const serverFnsById: Record<string, ServerFn> = {}\n let updateServerFnResolver: (() => void) | undefined\n\n return {\n name: 'tanstack-start-rsbuild',\n setup(api: RsbuildPluginAPI) {\n // ---------------------------------------------------------------\n // 1. modifyRsbuildConfig — resolve config, set up environments\n // ---------------------------------------------------------------\n api.modifyRsbuildConfig((rsbuildConfig, { mergeRsbuildConfig }) => {\n const root =\n typeof rsbuildConfig.root === 'string'\n ? rsbuildConfig.root\n : process.cwd()\n\n const serverBase = rsbuildConfig.server?.base\n const assetPrefix = rsbuildConfig.output?.assetPrefix\n const publicBase = normalizePublicBase(\n typeof serverBase === 'string'\n ? serverBase\n : typeof assetPrefix === 'string' && assetPrefix !== 'auto'\n ? assetPrefix\n : undefined,\n )\n const rootDistPath = rsbuildConfig.output?.distPath\n const clientDistPath =\n rsbuildConfig.environments?.[RSBUILD_ENVIRONMENT_NAMES.client]?.output\n ?.distPath\n const serverDistPath =\n rsbuildConfig.environments?.[RSBUILD_ENVIRONMENT_NAMES.server]?.output\n ?.distPath\n\n applyResolvedBaseAndOutput({\n resolvedStartConfig,\n root,\n publicBase,\n clientOutputDirectory: resolveRsbuildOutputDirectory({\n distPath: clientDistPath,\n rootDistPath,\n fallback: 'dist/client',\n subdirectory: 'client',\n }),\n serverOutputDirectory: resolveRsbuildOutputDirectory({\n distPath: serverDistPath,\n rootDistPath,\n fallback: 'dist/server',\n subdirectory: 'server',\n }),\n })\n\n const { startConfig } = getConfig()\n const routerBasepath = applyResolvedRouterBasepath({\n resolvedStartConfig,\n startConfig,\n })\n\n const resolvedEntryPlan = configContext.resolveEntries()\n const isDev = api.context.action === 'dev'\n\n const entryAliases = createRsbuildResolvedEntryAliases({\n entryPaths: resolvedEntryPlan.entryPaths,\n })\n\n const environmentPlan = createRsbuildEnvironmentPlan({\n root,\n entryAliases,\n clientOutputDirectory: resolvedStartConfig.outputDirectories.client,\n serverOutputDirectory: resolvedStartConfig.outputDirectories.server,\n publicBase: resolvedStartConfig.basePaths.publicBase,\n serverFnProviderEnv,\n environmentOverrides: corePluginOpts.rsbuild?.environments,\n rsc: rscOpts,\n dev: isDev,\n })\n const serverFnBase = createServerFnBasePath({\n routerBasepath,\n serverFnBase: startConfig.serverFns.base,\n })\n const inlineCssEnabled = !isDev && startConfig.server.build.inlineCss\n\n return mergeRsbuildConfig(rsbuildConfig, {\n source: {\n define: {\n 'process.env.TSS_SERVER_FN_BASE': JSON.stringify(serverFnBase),\n 'import.meta.env.TSS_SERVER_FN_BASE':\n JSON.stringify(serverFnBase),\n 'process.env.TSS_ROUTER_BASEPATH': JSON.stringify(routerBasepath),\n 'import.meta.env.TSS_ROUTER_BASEPATH':\n JSON.stringify(routerBasepath),\n 'process.env.TSS_DEV_SERVER': JSON.stringify(\n isDev ? 'true' : 'false',\n ),\n 'import.meta.env.TSS_DEV_SERVER': JSON.stringify(\n isDev ? 'true' : 'false',\n ),\n // Rsbuild dev already injects emitted CSS asset hrefs, so keep\n // Start's synthetic `/@tanstack-start/styles.css` path disabled.\n 'process.env.TSS_DEV_SSR_STYLES_ENABLED': JSON.stringify('false'),\n 'import.meta.env.TSS_DEV_SSR_STYLES_ENABLED':\n JSON.stringify('false'),\n 'process.env.TSS_DEV_SSR_STYLES_BASEPATH': JSON.stringify(\n resolvedStartConfig.basePaths.publicBase,\n ),\n 'import.meta.env.TSS_DEV_SSR_STYLES_BASEPATH': JSON.stringify(\n resolvedStartConfig.basePaths.publicBase,\n ),\n 'process.env.TSS_INLINE_CSS_ENABLED': JSON.stringify(\n inlineCssEnabled ? 'true' : 'false',\n ),\n 'import.meta.env.TSS_INLINE_CSS_ENABLED': JSON.stringify(\n inlineCssEnabled ? 'true' : 'false',\n ),\n },\n },\n server: {\n // SSR apps render every route on the server — disable HTML\n // fallback so rsbuild doesn't intercept /_serverFn/ URLs.\n htmlFallback: false,\n // server.setup returned callback runs after built-in middleware\n // but BEFORE fallback middleware — the ideal slot for SSR.\n ...(isDev &&\n startPluginOpts.rsbuild?.installDevServerMiddleware !== false\n ? {\n setup: createServerSetup({\n serverFnBasePath: serverFnBase,\n }),\n }\n : {}),\n },\n ...(isDev\n ? {\n dev: {\n lazyCompilation: false,\n ...(rscEnabled ? { liveReload: false } : {}),\n },\n }\n : {}),\n environments: environmentPlan.environments,\n resolve: {\n alias: environmentPlan.alias,\n },\n })\n })\n\n // ---------------------------------------------------------------\n // 2. StartCompiler transforms — server fns, isomorphic fns, etc.\n // ---------------------------------------------------------------\n registerStartCompilerTransforms(api, {\n framework: corePluginOpts.framework,\n // modifyRsbuildConfig copies rsbuildConfig.root into resolvedStartConfig.root,\n // so defer this read until transform time instead of falling back to\n // process.cwd() during plugin setup.\n root: () => resolvedStartConfig.root || process.cwd(),\n providerEnvName: serverFnProviderEnv,\n generateFunctionId: startPluginOpts.serverFns?.generateFunctionId,\n serverFnsById,\n onServerFnsByIdChange: () => {\n updateServerFnResolver?.()\n },\n })\n\n registerImportProtection(api, {\n getConfig,\n framework: corePluginOpts.framework,\n environments: [\n { name: RSBUILD_ENVIRONMENT_NAMES.client, type: 'client' },\n { name: RSBUILD_ENVIRONMENT_NAMES.server, type: 'server' },\n ...(serverFnProviderEnv !== RSBUILD_ENVIRONMENT_NAMES.server &&\n !rscEnabled\n ? [{ name: serverFnProviderEnv, type: 'server' as const }]\n : []),\n ],\n })\n\n // ---------------------------------------------------------------\n // 3. Virtual modules — manifest, server fn resolver, adapters,\n // RSC runtime, RSC HMR\n // ---------------------------------------------------------------\n const virtualModuleState = registerVirtualModules(api, {\n root: resolvedStartConfig.root || process.cwd(),\n getConfig,\n serverFnsById,\n providerEnvName: serverFnProviderEnv,\n ssrIsProvider,\n serializationAdapters: corePluginOpts.serializationAdapters,\n getDevClientEntryUrl: (publicBase: string) =>\n joinURL(publicBase, 'static/js/index.js'),\n rscEnabled,\n })\n updateServerFnResolver = virtualModuleState.updateServerFnResolver\n\n // ---------------------------------------------------------------\n // 4. Client build stats capture via processAssets\n // ---------------------------------------------------------------\n const { getClientBuild } = registerClientBuildCapture(api)\n\n // ---------------------------------------------------------------\n // 4b. Server manifest module generation (build only)\n // For ordinary multi-environment builds, Rsbuild can compile the\n // server environment after the client environment finishes. Generate\n // the final manifest as module source in that phase instead of\n // patching emitted server assets afterwards.\n // ---------------------------------------------------------------\n if (api.context.action !== 'dev') {\n const normalizedManifestPath = normalizePath(\n virtualModuleState.manifestPath,\n )\n const matchesManifestPath = (id: string) =>\n normalizePath(id) === normalizedManifestPath\n\n api.transform(\n {\n test: (id: string) => matchesManifestPath(id),\n environments: [RSBUILD_ENVIRONMENT_NAMES.server],\n },\n ({ code }) => {\n const clientBuild = getClientBuild()\n\n if (clientBuild) {\n return virtualModuleState.generateManifestContent(clientBuild)\n }\n\n if (!rscEnabled) {\n throw new Error(\n 'TanStack Start could not generate the rsbuild server manifest before the client build completed',\n )\n }\n\n // RSC builds cannot express the required client -> server ordering\n // through MultiCompiler dependencies, so keep the placeholder for\n // the RSC-only asset-patching fallback below.\n return code\n },\n )\n }\n\n // ---------------------------------------------------------------\n // 5. Router plugin wiring (generator + code splitter)\n // ---------------------------------------------------------------\n registerRouterPlugins(api, {\n getConfig,\n corePluginOpts,\n startPluginOpts,\n })\n\n // ---------------------------------------------------------------\n // 6. Dev SSR middleware — registered via server.setup in\n // modifyRsbuildConfig above (returned callback runs after\n // built-ins but before fallback middleware)\n // ---------------------------------------------------------------\n\n // ---------------------------------------------------------------\n // 6b. Dev watcher: ignore workspace package `dist/**` directories.\n //\n // In a real user app, `@tanstack/react-router` and friends live\n // inside `node_modules/` and are ignored by Rspack's default\n // watcher. In this monorepo, pnpm symlinks them to\n // `packages/*/dist` (realpath outside node_modules), so the\n // watcher follows them and treats their dist files as live\n // sources. If anything rewrites those files during dev, Rspack\n // sees transient half-written modules and fails to resolve\n // relative imports between them.\n //\n // Only apply this in monorepo development. In user apps this\n // is a no-op — their `node_modules/@tanstack/*/dist/**` is\n // already ignored by Rspack's default watchOptions.\n // ---------------------------------------------------------------\n if (isInsideRouterMonoRepo && api.context.action === 'dev') {\n api.modifyRspackConfig((config) => {\n const workspaceDistRealpaths = resolveWorkspacePackageDistRealpaths()\n if (workspaceDistRealpaths.length === 0) return\n\n const workspaceDistIgnored = new RegExp(\n workspaceDistRealpaths\n .map((path) => `^${escapeRegExp(path)}(?:[\\\\\\\\/]|$)`)\n .join('|'),\n )\n const ignored = config.watchOptions?.ignored\n\n config.watchOptions = {\n ...(config.watchOptions ?? {}),\n ignored:\n ignored == null\n ? new RegExp(\n `${defaultRspackWatchIgnored.source}|${workspaceDistIgnored.source}`,\n )\n : typeof ignored === 'string'\n ? [ignored, ...workspaceDistRealpaths]\n : Array.isArray(ignored)\n ? [...ignored, ...workspaceDistRealpaths]\n : new RegExp(\n `${ignored.source}|${workspaceDistIgnored.source}`,\n ),\n }\n })\n }\n\n // ---------------------------------------------------------------\n // 7. RSC: rspack layer rules + native RSC plugins\n // When RSC is enabled, we add:\n // - issuerLayer rule for react-server condition propagation\n // - SWC reactServerComponents: true\n // - rspack ServerPlugin (server env) / ClientPlugin (client env)\n // The Coordinator inside createPlugins() handles compilation\n // ordering (server→client→server-actions) automatically.\n // ---------------------------------------------------------------\n if (rscEnabled) {\n api.modifyRspackConfig((config, utils) => {\n const envName = utils.environment.name\n const isServerEnv = envName === RSBUILD_ENVIRONMENT_NAMES.server\n const isClientEnv = envName === RSBUILD_ENVIRONMENT_NAMES.client\n\n // Create RSC plugin pair lazily (once per build)\n if (!rscPlugins) {\n rscPlugins = utils.rspack.experiments.rsc.createPlugins()\n }\n\n if (isServerEnv) {\n // --- issuerLayer rule: modules imported from RSC layer\n // get react-server resolve condition ---\n const moduleRules = (config.module.rules ??= [])\n const root = resolvedStartConfig.root || process.cwd()\n\n // Split server-fn provider modules are the actual RSC execution\n // boundary in Start's layered model. They must compile in the\n // RSC layer so React and react-server-dom-rspack resolve their\n // react-server exports without forcing the whole SSR graph into\n // react-server conditions.\n moduleRules.push({\n resourceQuery: /(?:^|[?&])tss-serverfn-split(?:&|$)/,\n layer: RSBUILD_RSC_LAYERS.rsc,\n resolve: {\n conditionNames: ['react-server', '...'],\n },\n })\n\n // All modules imported from the RSC layer inherit\n // the react-server condition (transitive propagation), except\n // route split virtual modules. Those remain ordinary SSR/client\n // route code; only `?tsr-shared=1` modules may be shared with the\n // provider subtree.\n moduleRules.push({\n issuerLayer: RSBUILD_RSC_LAYERS.rsc,\n resourceQuery: {\n not: [/(?:^|[?&])tsr-split(?:=|&|$)/],\n },\n resolve: {\n conditionNames: ['react-server', '...'],\n },\n })\n\n // The RSC ServerPlugin injects imports like\n // `react-server-dom-rspack/server` into transformed modules.\n // Some modules in the server graph resolve from real package paths\n // outside the app root, so relying on the default relative\n // `node_modules` lookup is not enough. Seed resolve.modules with the\n // app root explicitly, without package-manager-specific heuristics.\n seedResolveModules(config, [`${root}/node_modules`, 'node_modules'])\n\n // Add ServerPlugin with HMR callback\n config.plugins.push(\n new rscPlugins.ServerPlugin({\n clientEntryName: 'index',\n runtimeEntryName: 'index',\n injectSsrModulesToEntries: ['index'],\n onServerComponentChanges: () => {\n // Send rsc:update to connected clients for HMR\n devServerRef?.sockWrite('custom', {\n event: 'rsc:update',\n })\n },\n }),\n )\n\n config.plugins.push({\n apply(compiler: RspackCompiler) {\n compiler.hooks.finishMake.tapPromise(\n {\n name: 'TanStackStartRscServerFnResolverRebuild',\n stage: -10,\n },\n async (compilation: RspackCompilationExtended) => {\n if (Object.keys(serverFnsById).length === 0) {\n return\n }\n\n const resolverContent =\n virtualModuleState.generateCurrentResolverContent(true)\n virtualModuleState.tryUpdateServerFnResolver(\n resolverContent,\n )\n\n await rebuildModulesContaining(\n compilation,\n virtualModuleState.serverFnResolverPath,\n )\n },\n )\n },\n })\n\n if (api.context.action !== 'dev') {\n config.plugins.push({\n apply(compiler: RspackCompiler) {\n compiler.hooks.finishMake.tapPromise(\n {\n name: 'TanStackStartRscManifestRebuild',\n // The native RSC ServerPlugin completes the client-entry\n // handoff during its finishMake hook. Rebuild the manifest\n // after that point so the transform hook can emit the final\n // manifest source instead of the placeholder.\n stage: 10,\n },\n async (compilation: RspackCompilationExtended) => {\n const clientBuild = getClientBuild()\n\n if (!clientBuild) {\n return\n }\n\n virtualModuleState.updateManifest(clientBuild)\n\n await rebuildModulesContaining(\n compilation,\n virtualModuleState.manifestPath,\n )\n },\n )\n },\n })\n }\n }\n\n if (isClientEnv) {\n // Add ClientPlugin — the Coordinator links it to the\n // ServerPlugin's compilation state\n config.plugins.push(new rscPlugins.ClientPlugin())\n }\n\n // --- SWC reactServerComponents ---\n // Enable RSC directive detection where the native RSC plugins need it.\n // In the server build, scope it to the actual RSC provider subtree so\n // ordinary route-split modules (e.g. ?tsr-split=component) stay out of\n // RSC validation unless they are really imported by a provider module.\n if (isServerEnv) {\n enableSwcReactServerComponents(config, 'rsc-subtree')\n } else if (isClientEnv) {\n enableSwcReactServerComponents(config, 'all')\n }\n })\n\n // Capture dev server reference for RSC HMR socket writes\n if (api.context.action === 'dev') {\n api.onBeforeStartDevServer(({ server }) => {\n devServerRef = server\n })\n }\n }\n\n // ---------------------------------------------------------------\n // 8. Build ordering — client must complete before server starts\n // so that the manifest virtual module has real client build stats.\n // Uses rspack MultiCompiler.setDependencies() under the hood.\n //\n // IMPORTANT: When RSC is enabled we must NOT set dependencies.\n // The RSC Coordinator already orchestrates server↔client\n // compilation ordering by interleaving phases within compiler\n // hooks. Adding setDependencies(server, [client]) on top of\n // the Coordinator creates a deadlock: MultiCompiler blocks\n // the server compiler until client is `done`, but the\n // Coordinator blocks the client's `make` hook until the\n // server's entries phase completes — neither can start.\n // ---------------------------------------------------------------\n if (!rscEnabled) {\n api.onAfterCreateCompiler(({ compiler }) => {\n // MultiCompiler has a `compilers` array; single compiler does not\n if ('compilers' in compiler) {\n const serverCompiler = compiler.compilers.find(\n (c) => c.name === RSBUILD_ENVIRONMENT_NAMES.server,\n )\n if (serverCompiler) {\n compiler.setDependencies(serverCompiler, [\n RSBUILD_ENVIRONMENT_NAMES.client,\n ])\n }\n }\n })\n }\n\n // ---------------------------------------------------------------\n // 8b. Manifest asset replacement fallback (RSC build only)\n // Rsbuild's native RSC coordinator interleaves server and client\n // compilers, so the server manifest module can compile before Start's\n // normalized client build stats exist. Keep final replacement in the\n // server asset pipeline, after the client processAssets capture has a\n // chance to run.\n // ---------------------------------------------------------------\n if (api.context.action !== 'dev' && rscEnabled) {\n const manifestPlaceholderLiteral = JSON.stringify(\n START_MANIFEST_PLACEHOLDER,\n )\n api.modifyRspackConfig((config, utils) => {\n if (utils.environment.name !== RSBUILD_ENVIRONMENT_NAMES.server)\n return\n\n config.plugins.push({\n apply(compiler: RspackCompiler) {\n compiler.hooks.compilation.tap(\n 'TanStackStartManifestReplace',\n (compilation: RspackCompilationExtended) => {\n compilation.hooks.processAssets.tap(\n {\n name: 'TanStackStartManifestReplace',\n stage:\n utils.rspack.Compilation\n .PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,\n },\n () => {\n const assetsWithPlaceholder = compilation\n .getAssets()\n .flatMap((asset) => {\n if (!asset.name.endsWith('.js')) return []\n\n const sourceStr = String(asset.source.source())\n return sourceStr.includes(manifestPlaceholderLiteral)\n ? [{ asset, sourceStr }]\n : []\n })\n\n if (assetsWithPlaceholder.length === 0) return\n\n const clientBuild = getClientBuild()\n if (!clientBuild) {\n throw new Error(\n 'TanStack Start could not replace the rsbuild RSC server manifest placeholder because the client build was unavailable',\n )\n }\n\n const manifestValueLiteral =\n virtualModuleState.generateManifestValueLiteral(\n clientBuild,\n )\n\n for (const {\n asset,\n sourceStr,\n } of assetsWithPlaceholder) {\n compilation.updateAsset(\n asset.name,\n new utils.rspack.sources.RawSource(\n sourceStr.replace(\n manifestPlaceholderLiteral,\n manifestValueLiteral,\n ),\n ),\n )\n }\n },\n )\n },\n )\n },\n })\n })\n }\n\n // ---------------------------------------------------------------\n // 9. After client env compiles — refresh resolver + manifest\n // ---------------------------------------------------------------\n api.onAfterEnvironmentCompile(({ environment }) => {\n if (environment.name !== RSBUILD_ENVIRONMENT_NAMES.client) return\n\n virtualModuleState.updateServerFnResolver()\n\n const clientBuild = getClientBuild()\n if (clientBuild) {\n virtualModuleState.updateManifest(clientBuild)\n }\n })\n\n if (api.context.action === 'build') {\n api.onAfterBuild(async () => {\n const { startConfig } = getConfig()\n\n await postBuildWithRsbuild({\n startConfig,\n clientOutputDirectory: resolvedStartConfig.outputDirectories.client,\n serverOutputDirectory: resolvedStartConfig.outputDirectories.server,\n })\n })\n }\n },\n }\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nconst defaultRspackWatchIgnored = /[\\\\/](?:\\.git|node_modules)[\\\\/]/\n\nfunction seedResolveModules(\n config: RspackConfig,\n entries: Array<string>,\n): void {\n const resolveModules = (config.resolve.modules ??= [])\n\n for (const entry of entries) {\n if (!resolveModules.includes(entry)) {\n resolveModules.push(entry)\n }\n }\n}\n\nfunction rebuildModulesContaining(\n compilation: RspackCompilationExtended,\n identifierFragment: string,\n): Promise<void> {\n const modulesToRebuild = Array.from(compilation.modules).filter((mod) =>\n mod.identifier().includes(identifierFragment),\n )\n\n if (modulesToRebuild.length === 0) {\n return Promise.resolve()\n }\n\n return Promise.all(\n modulesToRebuild.map(\n (mod) =>\n new Promise<void>((resolve, reject) => {\n compilation.rebuildModule(mod, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n }),\n ),\n ).then(() => undefined)\n}\n\n/**\n * Return the realpath of every packages/<name>/dist directory in the\n * TanStack Router monorepo. Only meaningful when called from inside the\n * monorepo — in user apps, callers should guard with\n * `isInsideRouterMonoRepo` before invoking this.\n */\nfunction resolveWorkspacePackageDistRealpaths(): Array<string> {\n // currentDir points at either <repo>/packages/start-plugin-core/src/rsbuild\n // or <repo>/packages/start-plugin-core/dist/<fmt>/rsbuild. Four levels up\n // lands on <repo>/packages in both layouts.\n const packagesDir = resolve(currentDir, '../../../../')\n if (!existsSync(packagesDir)) return []\n\n let entries: Array<string>\n try {\n entries = readdirSync(packagesDir)\n } catch {\n return []\n }\n\n const dists: Array<string> = []\n for (const entry of entries) {\n const distPath = join(packagesDir, entry, 'dist')\n try {\n if (!statSync(distPath).isDirectory()) continue\n } catch {\n continue\n }\n try {\n dists.push(realpathSync(distPath))\n } catch {\n dists.push(distPath)\n }\n }\n\n return dists\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA+CA,IAAM,aAAa,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAC1D,IAAM,gCAAgC;CAIpC,MAAM,YAAY,QAAQ,YAAY,eAAe;AACrD,QAAO,UAAU,SAAS,YAAY,IAAI,UAAU,SAAS,aAAa;IACxE;AAUJ,SAAgB,qBACd,gBACA,kBAAmD,EAAE,EACtC;CACf,MAAM,UAAU,eAAe;CAC/B,MAAM,aAAa,QAAQ,QAAQ;CAEnC,MAAM,gBAAgB,yBAAyB;EAC7C;EACA;EACA,aAAa;EACd,CAAC;CACF,MAAM,EAAE,WAAW,wBAAwB;CAC3C,MAAM,sBAAsB,eAAe;CAC3C,MAAM,gBAAgB,eAAe;CAGrC,IAAI;CAGJ,IAAI,eAA2D;CAC/D,MAAM,gBAA0C,EAAE;CAClD,IAAI;AAEJ,QAAO;EACL,MAAM;EACN,MAAM,KAAuB;AAI3B,OAAI,qBAAqB,eAAe,EAAE,yBAAyB;IACjE,MAAM,OACJ,OAAO,cAAc,SAAS,WAC1B,cAAc,OACd,QAAQ,KAAK;IAEnB,MAAM,aAAa,cAAc,QAAQ;IACzC,MAAM,cAAc,cAAc,QAAQ;IAC1C,MAAM,aAAa,oBACjB,OAAO,eAAe,WAClB,aACA,OAAO,gBAAgB,YAAY,gBAAgB,SACjD,cACA,KAAA,EACP;IACD,MAAM,eAAe,cAAc,QAAQ;IAC3C,MAAM,iBACJ,cAAc,eAAe,0BAA0B,SAAS,QAC5D;IACN,MAAM,iBACJ,cAAc,eAAe,0BAA0B,SAAS,QAC5D;AAEN,+BAA2B;KACzB;KACA;KACA;KACA,uBAAuB,8BAA8B;MACnD,UAAU;MACV;MACA,UAAU;MACV,cAAc;MACf,CAAC;KACF,uBAAuB,8BAA8B;MACnD,UAAU;MACV;MACA,UAAU;MACV,cAAc;MACf,CAAC;KACH,CAAC;IAEF,MAAM,EAAE,gBAAgB,WAAW;IACnC,MAAM,iBAAiB,4BAA4B;KACjD;KACA;KACD,CAAC;IAEF,MAAM,oBAAoB,cAAc,gBAAgB;IACxD,MAAM,QAAQ,IAAI,QAAQ,WAAW;IAMrC,MAAM,kBAAkB,6BAA6B;KACnD;KACA,cANmB,kCAAkC,EACrD,YAAY,kBAAkB,YAC/B,CAAC;KAKA,uBAAuB,oBAAoB,kBAAkB;KAC7D,uBAAuB,oBAAoB,kBAAkB;KAC7D,YAAY,oBAAoB,UAAU;KAC1C;KACA,sBAAsB,eAAe,SAAS;KAC9C,KAAK;KACL,KAAK;KACN,CAAC;IACF,MAAM,eAAe,uBAAuB;KAC1C;KACA,cAAc,YAAY,UAAU;KACrC,CAAC;IACF,MAAM,mBAAmB,CAAC,SAAS,YAAY,OAAO,MAAM;AAE5D,WAAO,mBAAmB,eAAe;KACvC,QAAQ,EACN,QAAQ;MACN,kCAAkC,KAAK,UAAU,aAAa;MAC9D,sCACE,KAAK,UAAU,aAAa;MAC9B,mCAAmC,KAAK,UAAU,eAAe;MACjE,uCACE,KAAK,UAAU,eAAe;MAChC,8BAA8B,KAAK,UACjC,QAAQ,SAAS,QAClB;MACD,kCAAkC,KAAK,UACrC,QAAQ,SAAS,QAClB;MAGD,0CAA0C,KAAK,UAAU,QAAQ;MACjE,8CACE,KAAK,UAAU,QAAQ;MACzB,2CAA2C,KAAK,UAC9C,oBAAoB,UAAU,WAC/B;MACD,+CAA+C,KAAK,UAClD,oBAAoB,UAAU,WAC/B;MACD,sCAAsC,KAAK,UACzC,mBAAmB,SAAS,QAC7B;MACD,0CAA0C,KAAK,UAC7C,mBAAmB,SAAS,QAC7B;MACF,EACF;KACD,QAAQ;MAGN,cAAc;MAGd,GAAI,SACJ,gBAAgB,SAAS,+BAA+B,QACpD,EACE,OAAO,kBAAkB,EACvB,kBAAkB,cACnB,CAAC,EACH,GACD,EAAE;MACP;KACD,GAAI,QACA,EACE,KAAK;MACH,iBAAiB;MACjB,GAAI,aAAa,EAAE,YAAY,OAAO,GAAG,EAAE;MAC5C,EACF,GACD,EAAE;KACN,cAAc,gBAAgB;KAC9B,SAAS,EACP,OAAO,gBAAgB,OACxB;KACF,CAAC;KACF;AAKF,mCAAgC,KAAK;IACnC,WAAW,eAAe;IAI1B,YAAY,oBAAoB,QAAQ,QAAQ,KAAK;IACrD,iBAAiB;IACjB,oBAAoB,gBAAgB,WAAW;IAC/C;IACA,6BAA6B;AAC3B,+BAA0B;;IAE7B,CAAC;AAEF,4BAAyB,KAAK;IAC5B;IACA,WAAW,eAAe;IAC1B,cAAc;KACZ;MAAE,MAAM,0BAA0B;MAAQ,MAAM;MAAU;KAC1D;MAAE,MAAM,0BAA0B;MAAQ,MAAM;MAAU;KAC1D,GAAI,wBAAwB,0BAA0B,UACtD,CAAC,aACG,CAAC;MAAE,MAAM;MAAqB,MAAM;MAAmB,CAAC,GACxD,EAAE;KACP;IACF,CAAC;GAMF,MAAM,qBAAqB,uBAAuB,KAAK;IACrD,MAAM,oBAAoB,QAAQ,QAAQ,KAAK;IAC/C;IACA;IACA,iBAAiB;IACjB;IACA,uBAAuB,eAAe;IACtC,uBAAuB,eACrB,QAAQ,YAAY,qBAAqB;IAC3C;IACD,CAAC;AACF,4BAAyB,mBAAmB;GAK5C,MAAM,EAAE,mBAAmB,2BAA2B,IAAI;AAS1D,OAAI,IAAI,QAAQ,WAAW,OAAO;IAChC,MAAM,yBAAyB,cAC7B,mBAAmB,aACpB;IACD,MAAM,uBAAuB,OAC3B,cAAc,GAAG,KAAK;AAExB,QAAI,UACF;KACE,OAAO,OAAe,oBAAoB,GAAG;KAC7C,cAAc,CAAC,0BAA0B,OAAO;KACjD,GACA,EAAE,WAAW;KACZ,MAAM,cAAc,gBAAgB;AAEpC,SAAI,YACF,QAAO,mBAAmB,wBAAwB,YAAY;AAGhE,SAAI,CAAC,WACH,OAAM,IAAI,MACR,kGACD;AAMH,YAAO;MAEV;;AAMH,yBAAsB,KAAK;IACzB;IACA;IACA;IACD,CAAC;AAwBF,OAAI,0BAA0B,IAAI,QAAQ,WAAW,MACnD,KAAI,oBAAoB,WAAW;IACjC,MAAM,yBAAyB,sCAAsC;AACrE,QAAI,uBAAuB,WAAW,EAAG;IAEzC,MAAM,uBAAuB,IAAI,OAC/B,uBACG,KAAK,SAAS,IAAI,aAAa,KAAK,CAAC,eAAe,CACpD,KAAK,IAAI,CACb;IACD,MAAM,UAAU,OAAO,cAAc;AAErC,WAAO,eAAe;KACpB,GAAI,OAAO,gBAAgB,EAAE;KAC7B,SACE,WAAW,OACP,IAAI,OACF,GAAG,0BAA0B,OAAO,GAAG,qBAAqB,SAC7D,GACD,OAAO,YAAY,WACjB,CAAC,SAAS,GAAG,uBAAuB,GACpC,MAAM,QAAQ,QAAQ,GACpB,CAAC,GAAG,SAAS,GAAG,uBAAuB,GACvC,IAAI,OACF,GAAG,QAAQ,OAAO,GAAG,qBAAqB,SAC3C;KACZ;KACD;AAYJ,OAAI,YAAY;AACd,QAAI,oBAAoB,QAAQ,UAAU;KACxC,MAAM,UAAU,MAAM,YAAY;KAClC,MAAM,cAAc,YAAY,0BAA0B;KAC1D,MAAM,cAAc,YAAY,0BAA0B;AAG1D,SAAI,CAAC,WACH,cAAa,MAAM,OAAO,YAAY,IAAI,eAAe;AAG3D,SAAI,aAAa;MAGf,MAAM,cAAe,OAAO,OAAO,UAAU,EAAE;MAC/C,MAAM,OAAO,oBAAoB,QAAQ,QAAQ,KAAK;AAOtD,kBAAY,KAAK;OACf,eAAe;OACf,OAAO,mBAAmB;OAC1B,SAAS,EACP,gBAAgB,CAAC,gBAAgB,MAAM,EACxC;OACF,CAAC;AAOF,kBAAY,KAAK;OACf,aAAa,mBAAmB;OAChC,eAAe,EACb,KAAK,CAAC,+BAA+B,EACtC;OACD,SAAS,EACP,gBAAgB,CAAC,gBAAgB,MAAM,EACxC;OACF,CAAC;AAQF,yBAAmB,QAAQ,CAAC,GAAG,KAAK,gBAAgB,eAAe,CAAC;AAGpE,aAAO,QAAQ,KACb,IAAI,WAAW,aAAa;OAC1B,iBAAiB;OACjB,kBAAkB;OAClB,2BAA2B,CAAC,QAAQ;OACpC,gCAAgC;AAE9B,sBAAc,UAAU,UAAU,EAChC,OAAO,cACR,CAAC;;OAEL,CAAC,CACH;AAED,aAAO,QAAQ,KAAK,EAClB,MAAM,UAA0B;AAC9B,gBAAS,MAAM,WAAW,WACxB;QACE,MAAM;QACN,OAAO;QACR,EACD,OAAO,gBAA2C;AAChD,YAAI,OAAO,KAAK,cAAc,CAAC,WAAW,EACxC;QAGF,MAAM,kBACJ,mBAAmB,+BAA+B,KAAK;AACzD,2BAAmB,0BACjB,gBACD;AAED,cAAM,yBACJ,aACA,mBAAmB,qBACpB;SAEJ;SAEJ,CAAC;AAEF,UAAI,IAAI,QAAQ,WAAW,MACzB,QAAO,QAAQ,KAAK,EAClB,MAAM,UAA0B;AAC9B,gBAAS,MAAM,WAAW,WACxB;QACE,MAAM;QAKN,OAAO;QACR,EACD,OAAO,gBAA2C;QAChD,MAAM,cAAc,gBAAgB;AAEpC,YAAI,CAAC,YACH;AAGF,2BAAmB,eAAe,YAAY;AAE9C,cAAM,yBACJ,aACA,mBAAmB,aACpB;SAEJ;SAEJ,CAAC;;AAIN,SAAI,YAGF,QAAO,QAAQ,KAAK,IAAI,WAAW,cAAc,CAAC;AAQpD,SAAI,YACF,gCAA+B,QAAQ,cAAc;cAC5C,YACT,gCAA+B,QAAQ,MAAM;MAE/C;AAGF,QAAI,IAAI,QAAQ,WAAW,MACzB,KAAI,wBAAwB,EAAE,aAAa;AACzC,oBAAe;MACf;;AAkBN,OAAI,CAAC,WACH,KAAI,uBAAuB,EAAE,eAAe;AAE1C,QAAI,eAAe,UAAU;KAC3B,MAAM,iBAAiB,SAAS,UAAU,MACvC,MAAM,EAAE,SAAS,0BAA0B,OAC7C;AACD,SAAI,eACF,UAAS,gBAAgB,gBAAgB,CACvC,0BAA0B,OAC3B,CAAC;;KAGN;AAWJ,OAAI,IAAI,QAAQ,WAAW,SAAS,YAAY;IAC9C,MAAM,6BAA6B,KAAK,UACtC,2BACD;AACD,QAAI,oBAAoB,QAAQ,UAAU;AACxC,SAAI,MAAM,YAAY,SAAS,0BAA0B,OACvD;AAEF,YAAO,QAAQ,KAAK,EAClB,MAAM,UAA0B;AAC9B,eAAS,MAAM,YAAY,IACzB,iCACC,gBAA2C;AAC1C,mBAAY,MAAM,cAAc,IAC9B;QACE,MAAM;QACN,OACE,MAAM,OAAO,YACV;QACN,QACK;QACJ,MAAM,wBAAwB,YAC3B,WAAW,CACX,SAAS,UAAU;AAClB,aAAI,CAAC,MAAM,KAAK,SAAS,MAAM,CAAE,QAAO,EAAE;SAE1C,MAAM,YAAY,OAAO,MAAM,OAAO,QAAQ,CAAC;AAC/C,gBAAO,UAAU,SAAS,2BAA2B,GACjD,CAAC;UAAE;UAAO;UAAW,CAAC,GACtB,EAAE;UACN;AAEJ,YAAI,sBAAsB,WAAW,EAAG;QAExC,MAAM,cAAc,gBAAgB;AACpC,YAAI,CAAC,YACH,OAAM,IAAI,MACR,wHACD;QAGH,MAAM,uBACJ,mBAAmB,6BACjB,YACD;AAEH,aAAK,MAAM,EACT,OACA,eACG,sBACH,aAAY,YACV,MAAM,MACN,IAAI,MAAM,OAAO,QAAQ,UACvB,UAAU,QACR,4BACA,qBACD,CACF,CACF;SAGN;QAEJ;QAEJ,CAAC;MACF;;AAMJ,OAAI,2BAA2B,EAAE,kBAAkB;AACjD,QAAI,YAAY,SAAS,0BAA0B,OAAQ;AAE3D,uBAAmB,wBAAwB;IAE3C,MAAM,cAAc,gBAAgB;AACpC,QAAI,YACF,oBAAmB,eAAe,YAAY;KAEhD;AAEF,OAAI,IAAI,QAAQ,WAAW,QACzB,KAAI,aAAa,YAAY;IAC3B,MAAM,EAAE,gBAAgB,WAAW;AAEnC,UAAM,qBAAqB;KACzB;KACA,uBAAuB,oBAAoB,kBAAkB;KAC7D,uBAAuB,oBAAoB,kBAAkB;KAC9D,CAAC;KACF;;EAGP;;AAGH,SAAS,aAAa,OAAuB;AAC3C,QAAO,MAAM,QAAQ,uBAAuB,OAAO;;AAGrD,IAAM,4BAA4B;AAElC,SAAS,mBACP,QACA,SACM;CACN,MAAM,iBAAkB,OAAO,QAAQ,YAAY,EAAE;AAErD,MAAK,MAAM,SAAS,QAClB,KAAI,CAAC,eAAe,SAAS,MAAM,CACjC,gBAAe,KAAK,MAAM;;AAKhC,SAAS,yBACP,aACA,oBACe;CACf,MAAM,mBAAmB,MAAM,KAAK,YAAY,QAAQ,CAAC,QAAQ,QAC/D,IAAI,YAAY,CAAC,SAAS,mBAAmB,CAC9C;AAED,KAAI,iBAAiB,WAAW,EAC9B,QAAO,QAAQ,SAAS;AAG1B,QAAO,QAAQ,IACb,iBAAiB,KACd,QACC,IAAI,SAAe,SAAS,WAAW;AACrC,cAAY,cAAc,MAAM,QAAsB;AACpD,OAAI,IAAK,QAAO,IAAI;OACf,UAAS;IACd;GACF,CACL,CACF,CAAC,WAAW,KAAA,EAAU;;;;;;;;AASzB,SAAS,uCAAsD;CAI7D,MAAM,cAAc,QAAQ,YAAY,eAAe;AACvD,KAAI,CAAC,WAAW,YAAY,CAAE,QAAO,EAAE;CAEvC,IAAI;AACJ,KAAI;AACF,YAAU,YAAY,YAAY;SAC5B;AACN,SAAO,EAAE;;CAGX,MAAM,QAAuB,EAAE;AAC/B,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,aAAa,OAAO,OAAO;AACjD,MAAI;AACF,OAAI,CAAC,SAAS,SAAS,CAAC,aAAa,CAAE;UACjC;AACN;;AAEF,MAAI;AACF,SAAM,KAAK,aAAa,SAAS,CAAC;UAC5B;AACN,SAAM,KAAK,SAAS;;;AAIxB,QAAO"}
@@ -209,20 +209,25 @@ export declare const tanstackStartRsbuildOptionsSchema: z.ZodDefault<z.ZodOption
209
209
  entry: z.ZodOptional<z.ZodString>;
210
210
  build: z.ZodDefault<z.ZodOptional<z.ZodObject<{
211
211
  staticNodeEnv: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
212
+ inlineCss: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
212
213
  }, "strip", z.ZodTypeAny, {
213
214
  staticNodeEnv: boolean;
215
+ inlineCss: boolean;
214
216
  }, {
215
217
  staticNodeEnv?: boolean | undefined;
218
+ inlineCss?: boolean | undefined;
216
219
  }>>>;
217
220
  }, "strip", z.ZodTypeAny, {
218
221
  build: {
219
222
  staticNodeEnv: boolean;
223
+ inlineCss: boolean;
220
224
  };
221
225
  entry?: string | undefined;
222
226
  }, {
223
227
  entry?: string | undefined;
224
228
  build?: {
225
229
  staticNodeEnv?: boolean | undefined;
230
+ inlineCss?: boolean | undefined;
226
231
  } | undefined;
227
232
  }>>>;
228
233
  serverFns: z.ZodDefault<z.ZodOptional<z.ZodObject<{
@@ -2391,6 +2396,7 @@ export declare const tanstackStartRsbuildOptionsSchema: z.ZodDefault<z.ZodOption
2391
2396
  server: {
2392
2397
  build: {
2393
2398
  staticNodeEnv: boolean;
2399
+ inlineCss: boolean;
2394
2400
  };
2395
2401
  entry?: string | undefined;
2396
2402
  };
@@ -2720,6 +2726,7 @@ export declare const tanstackStartRsbuildOptionsSchema: z.ZodDefault<z.ZodOption
2720
2726
  entry?: string | undefined;
2721
2727
  build?: {
2722
2728
  staticNodeEnv?: boolean | undefined;
2729
+ inlineCss?: boolean | undefined;
2723
2730
  } | undefined;
2724
2731
  } | undefined;
2725
2732
  srcDirectory?: string | undefined;
@@ -3099,6 +3106,7 @@ export declare function parseStartConfig(opts: z.input<typeof tanstackStartRsbui
3099
3106
  server: {
3100
3107
  build: {
3101
3108
  staticNodeEnv: boolean;
3109
+ inlineCss: boolean;
3102
3110
  };
3103
3111
  entry?: string | undefined;
3104
3112
  };
@@ -24,21 +24,22 @@ function generateManifestModuleDev(devClientEntryUrl) {
24
24
  }
25
25
  export const tsrStartManifest = () => globalThis[${JSON.stringify(DEV_START_MANIFEST_GLOBAL)}] ?? fallbackManifest`;
26
26
  }
27
- function buildStartManifestData(clientBuild, publicBase) {
27
+ function buildStartManifestData(clientBuild, publicBase, inlineCss) {
28
28
  const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST;
29
29
  return buildStartManifest({
30
30
  clientBuild,
31
31
  routeTreeRoutes,
32
- basePath: publicBase
32
+ basePath: publicBase,
33
+ inlineCss
33
34
  });
34
35
  }
35
- function serializeStartManifestData(clientBuild, publicBase) {
36
- return JSON.stringify(buildStartManifestData(clientBuild, publicBase));
36
+ function serializeStartManifestData(clientBuild, publicBase, inlineCss) {
37
+ return JSON.stringify(buildStartManifestData(clientBuild, publicBase, inlineCss));
37
38
  }
38
- function generateManifestModuleBuild(clientBuild, publicBase, _devClientEntryUrl) {
39
+ function generateManifestModuleBuild(clientBuild, publicBase, _devClientEntryUrl, inlineCss) {
39
40
  if (!clientBuild) return `const tsrStartManifestData = ${JSON.stringify(START_MANIFEST_PLACEHOLDER)}
40
41
  export const tsrStartManifest = () => tsrStartManifestData`;
41
- return `export const tsrStartManifest = () => (${serializeStartManifestData(clientBuild, publicBase)})`;
42
+ return `export const tsrStartManifest = () => (${serializeStartManifestData(clientBuild, publicBase, inlineCss)})`;
42
43
  }
43
44
  function generateInjectedHeadScripts(scripts) {
44
45
  return `export const injectedHeadScripts = ${scripts ? JSON.stringify(scripts) : "undefined"}`;
@@ -177,13 +178,13 @@ function registerVirtualModules(api, opts) {
177
178
  if (writes.size === 0) pendingWrites.delete(environmentName);
178
179
  }
179
180
  function getInitialContent(environmentName) {
180
- const { resolvedStartConfig } = opts.getConfig();
181
+ const { resolvedStartConfig, startConfig } = opts.getConfig();
181
182
  const isServerEnv = environmentName === RSBUILD_ENVIRONMENT_NAMES.server;
182
183
  const isClientEnv = environmentName === RSBUILD_ENVIRONMENT_NAMES.client;
183
184
  const content = {};
184
185
  if (isServerEnv) {
185
186
  const devClientEntryUrl = opts.getDevClientEntryUrl(resolvedStartConfig.basePaths.publicBase);
186
- content[paths.manifest] = isDev ? generateManifestModuleDev(devClientEntryUrl) : generateManifestModuleBuild(clientBuild, resolvedStartConfig.basePaths.publicBase, devClientEntryUrl);
187
+ content[paths.manifest] = isDev ? generateManifestModuleDev(devClientEntryUrl) : generateManifestModuleBuild(clientBuild, resolvedStartConfig.basePaths.publicBase, devClientEntryUrl, startConfig.server.build.inlineCss);
187
188
  } else content[paths.manifest] = "export default {}";
188
189
  content[paths.injectedHeadScripts] = generateInjectedHeadScripts();
189
190
  if (needsServerFnResolver(environmentName)) content[paths.serverFnResolver] = generateResolverContent(environmentName);
@@ -253,18 +254,18 @@ export function createFromReadableStream() { throw new Error('RSC SSR decode is
253
254
  return generateResolverContent(forProvider ? opts.providerEnvName : RSBUILD_ENVIRONMENT_NAMES.server);
254
255
  },
255
256
  generateManifestContent(newClientBuild) {
256
- const { resolvedStartConfig } = opts.getConfig();
257
+ const { resolvedStartConfig, startConfig } = opts.getConfig();
257
258
  const devClientEntryUrl = opts.getDevClientEntryUrl(resolvedStartConfig.basePaths.publicBase);
258
- return generateManifestModuleBuild(newClientBuild, resolvedStartConfig.basePaths.publicBase, devClientEntryUrl);
259
+ return generateManifestModuleBuild(newClientBuild, resolvedStartConfig.basePaths.publicBase, devClientEntryUrl, !isDev && startConfig.server.build.inlineCss);
259
260
  },
260
261
  generateManifestValueLiteral(newClientBuild) {
261
- const { resolvedStartConfig } = opts.getConfig();
262
- return serializeStartManifestData(newClientBuild, resolvedStartConfig.basePaths.publicBase);
262
+ const { resolvedStartConfig, startConfig } = opts.getConfig();
263
+ return serializeStartManifestData(newClientBuild, resolvedStartConfig.basePaths.publicBase, !isDev && startConfig.server.build.inlineCss);
263
264
  },
264
265
  updateManifest(newClientBuild) {
265
266
  clientBuild = newClientBuild;
266
267
  const { resolvedStartConfig } = opts.getConfig();
267
- if (isDev) globalThis[DEV_START_MANIFEST_GLOBAL] = buildStartManifestData(clientBuild, resolvedStartConfig.basePaths.publicBase);
268
+ if (isDev) globalThis[DEV_START_MANIFEST_GLOBAL] = buildStartManifestData(clientBuild, resolvedStartConfig.basePaths.publicBase, false);
268
269
  },
269
270
  updateServerFnResolver() {
270
271
  for (const environmentName of new Set([RSBUILD_ENVIRONMENT_NAMES.server, ...hasSeparateProviderEnvironment ? [opts.providerEnvName] : []])) {
@@ -1 +1 @@
1
- {"version":3,"file":"virtual-modules.js","names":[],"sources":["../../../src/rsbuild/virtual-modules.ts"],"sourcesContent":["import { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { generateSerializationAdaptersModule } from '../serialization-adapters-module'\nimport { generateServerFnResolverModule } from '../start-compiler/server-fn-resolver-module'\nimport { buildStartManifest } from '../start-manifest-plugin/manifestBuilder'\nimport { RSBUILD_ENVIRONMENT_NAMES } from './planning'\nimport type {\n RsbuildPluginAPI,\n rspack as rspackNamespaceType,\n} from '@rsbuild/core'\nimport type {\n GetConfigFn,\n NormalizedClientBuild,\n SerializationAdapterConfig,\n} from '../types'\nimport type { ServerFn } from '../start-compiler/types'\n\ntype RspackNamespace = typeof rspackNamespaceType\ntype RspackVirtualModulesPlugin = InstanceType<\n RspackNamespace['experiments']['VirtualModulesPlugin']\n>\n\n// Virtual module IDs for RSC (must match what react-start-rsc imports)\nconst RSC_RUNTIME_VIRTUAL_ID = 'virtual:tanstack-rsc-runtime'\nconst RSC_HMR_VIRTUAL_ID = 'virtual:tanstack-rsc-hmr'\nconst RSC_BROWSER_DECODE_VIRTUAL_ID = 'virtual:tanstack-rsc-browser-decode'\nconst RSC_SSR_DECODE_VIRTUAL_ID = 'virtual:tanstack-rsc-ssr-decode'\nexport const START_MANIFEST_PLACEHOLDER = '__TSS_START_MANIFEST_PLACEHOLDER__'\nconst DEV_START_MANIFEST_GLOBAL = '__TSS_DEV_START_MANIFEST__'\n/**\n * VirtualModulesPlugin resolves module paths relative to compiler.context.\n * Prefix them under the app root so they are unique and watcher-friendly.\n */\nfunction virtualPath(root: string, moduleId: string): string {\n // VirtualModulesPlugin resolves paths relative to compiler.context (root).\n // Use a recognizable prefix to avoid collisions with real files.\n const sanitized = moduleId.replace(/[:#]/g, '_')\n return `${root}/node_modules/.virtual/${sanitized}.js`\n}\n\nexport interface VirtualModuleState {\n /** Call to update manifest content after client build completes */\n updateManifest: (clientBuild: NormalizedClientBuild) => void\n /** Call to update server fn resolver content after compilation discovers fns */\n updateServerFnResolver: () => void\n /** Try to write explicit resolver content now; queues if env not ready */\n tryUpdateServerFnResolver: (content: string) => void\n /** Get the virtual path for a given module ID */\n getVirtualPath: (moduleId: string) => string\n /** Generate resolver module content from current serverFnsById state.\n * When forProvider=true, generates without isClientReferenced checks (RSC layer). */\n generateCurrentResolverContent: (forProvider?: boolean) => string\n /** The absolute virtual path of the server fn resolver module */\n serverFnResolverPath: string\n /** The absolute virtual path of the manifest module */\n manifestPath: string\n /** Generate manifest module content from a given client build */\n generateManifestContent: (clientBuild: NormalizedClientBuild) => string\n /** Generate the serialized manifest value literal for asset patching */\n generateManifestValueLiteral: (clientBuild: NormalizedClientBuild) => string\n /** VirtualModulesPlugin instances keyed by environment name */\n vmPlugins: Record<string, RspackVirtualModulesPlugin>\n}\n\n// ---------------------------------------------------------------------------\n// Manifest module codegen\n// ---------------------------------------------------------------------------\n\nfunction generateManifestModuleDev(devClientEntryUrl: string): string {\n return `const fallbackManifest = {\n routes: {},\n clientEntry: '${devClientEntryUrl}',\n}\nexport const tsrStartManifest = () => globalThis[${JSON.stringify(DEV_START_MANIFEST_GLOBAL)}] ?? fallbackManifest`\n}\n\nfunction buildStartManifestData(\n clientBuild: NormalizedClientBuild,\n publicBase: string,\n) {\n const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST\n return buildStartManifest({\n clientBuild,\n routeTreeRoutes,\n basePath: publicBase,\n })\n}\n\nfunction serializeStartManifestData(\n clientBuild: NormalizedClientBuild,\n publicBase: string,\n): string {\n return JSON.stringify(buildStartManifestData(clientBuild, publicBase))\n}\n\nfunction generateManifestModuleBuild(\n clientBuild: NormalizedClientBuild | undefined,\n publicBase: string,\n _devClientEntryUrl: string,\n): string {\n if (!clientBuild) {\n return `const tsrStartManifestData = ${JSON.stringify(START_MANIFEST_PLACEHOLDER)}\nexport const tsrStartManifest = () => tsrStartManifestData`\n }\n\n return `export const tsrStartManifest = () => (${serializeStartManifestData(clientBuild, publicBase)})`\n}\n\n// ---------------------------------------------------------------------------\n// Injected head scripts codegen\n// ---------------------------------------------------------------------------\n\nfunction generateInjectedHeadScripts(scripts?: string): string {\n return `export const injectedHeadScripts = ${scripts ? JSON.stringify(scripts) : 'undefined'}`\n}\n\n// ---------------------------------------------------------------------------\n// RSC virtual module codegen\n// ---------------------------------------------------------------------------\n\n/**\n * Generate virtual:tanstack-rsc-runtime content.\n * In the RSC layer this re-exports from react-server-dom-rspack/server.\n * In other layers it provides stubs that throw.\n */\nfunction generateRscRuntimeModule(isRscLayer: boolean): string {\n if (isRscLayer) {\n // Re-export the RSC runtime functions from react-server-dom-rspack/server.\n // NOTE: `createFromReadableStream` is a CLIENT-side API — it's NOT exported\n // by react-server-dom-rspack/server. The RSC layer never needs it (RSC\n // renders TO streams, doesn't decode FROM them). We provide a stub that\n // throws so the export surface stays consistent across bundlers.\n return `export { renderToReadableStream, createTemporaryReferenceSet, decodeReply, decodeAction, decodeFormState } from 'react-server-dom-rspack/server'\nexport function createFromReadableStream() { throw new Error('createFromReadableStream is not available in RSC environment (use SSR or browser decode instead)'); }\n// loadServerAction is provided by the RSC entry, not react-server-dom-rspack\nimport { getServerFnById } from '#tanstack-start-server-fn-resolver'\nexport const loadServerAction = async (id) => getServerFnById(id, { origin: 'server' })`\n }\n\n // In other layers, provide stubs that throw\n return `\nexport function renderToReadableStream() { throw new Error('renderToReadableStream can only be used in RSC environment'); }\nexport function createFromReadableStream() { throw new Error('createFromReadableStream can only be used in RSC environment'); }\nexport function createTemporaryReferenceSet() { throw new Error('createTemporaryReferenceSet can only be used in RSC environment'); }\nexport function decodeReply() { throw new Error('decodeReply can only be used in RSC environment'); }\nexport function loadServerAction() { throw new Error('loadServerAction can only be used in RSC environment'); }\nexport function decodeAction() { throw new Error('decodeAction can only be used in RSC environment'); }\nexport function decodeFormState() { throw new Error('decodeFormState can only be used in RSC environment'); }\n`\n}\n\n/**\n * Generate virtual:tanstack-rsc-hmr content.\n * In the client env during dev, listens for rsc:update WebSocket events\n * and invalidates the router. In all other contexts, exports nothing.\n */\nfunction generateRscHmrModule(isClientEnv: boolean, isDev: boolean): string {\n if (!isClientEnv || !isDev) {\n return 'export function setupRscHmr() {}'\n }\n\n // Rsbuild dev server delivers custom WebSocket events through\n // import.meta.webpackHot.on(event, cb). The server-side\n // sockWrite('custom', { event: 'rsc:update' }) maps directly to that.\n return `\n// RSC HMR listener for rsbuild dev server\n// Listens for 'rsc:update' custom events sent via sockWrite\nexport function setupRscHmr() {\n let __invalidateQueued = false\n\n function __queueInvalidate() {\n if (__invalidateQueued) return\n __invalidateQueued = true\n queueMicrotask(async () => {\n __invalidateQueued = false\n try {\n const router = window.__TSR_ROUTER__\n if (!router) {\n console.warn('[rsc:hmr] No router found on window.__TSR_ROUTER__')\n return\n }\n await router.invalidate()\n } catch (e) {\n console.warn('[rsc:hmr] Failed to invalidate router:', e)\n }\n })\n }\n\n if (import.meta.webpackHot) {\n import.meta.webpackHot.on('rsc:update', () => {\n __queueInvalidate()\n })\n }\n}\n`\n}\n\n// ---------------------------------------------------------------------------\n// Main registration\n// ---------------------------------------------------------------------------\n\nexport interface RegisterVirtualModulesOptions {\n root: string\n getConfig: GetConfigFn\n serverFnsById: Record<string, ServerFn>\n providerEnvName: string\n ssrIsProvider: boolean\n serializationAdapters: Array<SerializationAdapterConfig> | undefined\n /**\n * Get the URL at which the rsbuild dev server serves the client entry JS.\n * Called lazily inside modifyRspackConfig when getConfig() is available.\n * Example return: '/static/js/index.js'\n */\n getDevClientEntryUrl: (publicBase: string) => string\n /** Whether RSC virtual modules should be registered. */\n rscEnabled?: boolean | undefined\n}\n\n/**\n * Registers virtual modules for the rsbuild adapter using VirtualModulesPlugin.\n *\n * Creates one VirtualModulesPlugin per environment and registers them via\n * `modifyBundlerChain`. Provides update functions to refresh content dynamically.\n */\nexport function registerVirtualModules(\n api: RsbuildPluginAPI,\n opts: RegisterVirtualModulesOptions,\n): VirtualModuleState {\n const isDev = api.context.action === 'dev'\n const root = opts.root\n\n // Virtual module paths keyed by module ID\n const paths = {\n manifest: virtualPath(root, VIRTUAL_MODULES.startManifest),\n injectedHeadScripts: virtualPath(root, VIRTUAL_MODULES.injectedHeadScripts),\n serverFnResolver: virtualPath(root, VIRTUAL_MODULES.serverFnResolver),\n pluginAdapters: virtualPath(root, VIRTUAL_MODULES.pluginAdapters),\n }\n\n // RSC virtual module paths (only defined when RSC is enabled)\n const rscPaths = opts.rscEnabled\n ? {\n rscRuntime: virtualPath(root, RSC_RUNTIME_VIRTUAL_ID),\n rscHmr: virtualPath(root, RSC_HMR_VIRTUAL_ID),\n rscBrowserDecode: virtualPath(root, RSC_BROWSER_DECODE_VIRTUAL_ID),\n rscSsrDecode: virtualPath(root, RSC_SSR_DECODE_VIRTUAL_ID),\n }\n : null\n\n // Track VirtualModulesPlugin instances per environment for dynamic updates\n const vmPlugins: Record<string, RspackVirtualModulesPlugin> = {}\n const readyVmPlugins: Record<string, boolean> = {}\n const pendingWrites = new Map<string, Map<string, string>>()\n\n let clientBuild: NormalizedClientBuild | undefined\n const lastResolverContentByEnvironment: Record<string, string | undefined> =\n {}\n const hasSeparateProviderEnvironment =\n !opts.rscEnabled &&\n opts.providerEnvName !== RSBUILD_ENVIRONMENT_NAMES.server\n\n function isProviderEnvironment(environmentName: string): boolean {\n return environmentName === opts.providerEnvName\n }\n\n function needsServerFnResolver(environmentName: string): boolean {\n return (\n environmentName === RSBUILD_ENVIRONMENT_NAMES.server ||\n (hasSeparateProviderEnvironment && isProviderEnvironment(environmentName))\n )\n }\n\n function generateResolverContent(environmentName: string): string {\n return generateServerFnResolverModule({\n serverFnsById: opts.serverFnsById,\n includeClientReferencedCheck: !isProviderEnvironment(environmentName),\n useStaticImports: Boolean(opts.rscEnabled && isDev),\n })\n }\n\n function writeResolverContent(environmentName: string, content: string) {\n if (\n !isDev ||\n content !== lastResolverContentByEnvironment[environmentName]\n ) {\n lastResolverContentByEnvironment[environmentName] = content\n tryWriteModule(environmentName, paths.serverFnResolver, content)\n }\n }\n\n function queuePendingWrite(\n environmentName: string,\n filePath: string,\n content: string,\n ) {\n let writes = pendingWrites.get(environmentName)\n if (!writes) {\n writes = new Map()\n pendingWrites.set(environmentName, writes)\n }\n writes.set(filePath, content)\n }\n\n function tryWriteModule(\n environmentName: string,\n filePath: string,\n content: string,\n ) {\n const vmPlugin = vmPlugins[environmentName]\n if (!vmPlugin || !readyVmPlugins[environmentName]) {\n queuePendingWrite(environmentName, filePath, content)\n return false\n }\n\n vmPlugin.writeModule(filePath, content)\n return true\n }\n\n function flushPendingWrites(environmentName: string) {\n if (!readyVmPlugins[environmentName]) {\n return\n }\n\n const writes = pendingWrites.get(environmentName)\n if (!writes?.size) {\n return\n }\n\n for (const [filePath, content] of writes) {\n if (!tryWriteModule(environmentName, filePath, content)) {\n return\n }\n writes.delete(filePath)\n }\n\n if (writes.size === 0) {\n pendingWrites.delete(environmentName)\n }\n }\n\n // NOTE: getConfig() is deferred — it must NOT be called until modifyRsbuildConfig\n // has resolved (which sets resolvedStartConfig.root). All access to resolvedStartConfig\n // happens inside modifyRspackConfig (which runs after modifyRsbuildConfig) or\n // inside update callbacks (which run even later during/after compilation).\n\n // Generate initial content for each virtual module per environment\n function getInitialContent(environmentName: string): Record<string, string> {\n // Safe to call getConfig() here — this runs inside modifyRspackConfig\n const { resolvedStartConfig } = opts.getConfig()\n const isServerEnv = environmentName === RSBUILD_ENVIRONMENT_NAMES.server\n const isClientEnv = environmentName === RSBUILD_ENVIRONMENT_NAMES.client\n const content: Record<string, string> = {}\n\n // Manifest — only meaningful for server env\n if (isServerEnv) {\n const devClientEntryUrl = opts.getDevClientEntryUrl(\n resolvedStartConfig.basePaths.publicBase,\n )\n content[paths.manifest] = isDev\n ? generateManifestModuleDev(devClientEntryUrl)\n : generateManifestModuleBuild(\n clientBuild,\n resolvedStartConfig.basePaths.publicBase,\n devClientEntryUrl,\n )\n } else {\n content[paths.manifest] = 'export default {}'\n }\n\n // Injected head scripts — only server\n content[paths.injectedHeadScripts] = generateInjectedHeadScripts()\n\n // Server fn resolver — SSR and provider environments\n if (needsServerFnResolver(environmentName)) {\n content[paths.serverFnResolver] = generateResolverContent(environmentName)\n } else {\n // Client doesn't need the resolver but needs a valid module\n content[paths.serverFnResolver] = 'export {}'\n }\n\n // Plugin adapters — both environments get environment-specific content\n content[paths.pluginAdapters] = generateSerializationAdaptersModule({\n adapters: opts.serializationAdapters,\n runtime:\n environmentName === RSBUILD_ENVIRONMENT_NAMES.client\n ? 'client'\n : 'server',\n })\n\n // --- RSC virtual modules ---\n if (rscPaths) {\n // virtual:tanstack-rsc-runtime\n // In the server env, this provides the RSC runtime for the RSC layer.\n // The virtual module content is the same regardless of layer since\n // rspack layers handle module isolation. The RSC entry imports this\n // and the react-server condition on the RSC layer resolves\n // react-server-dom-rspack/server correctly.\n if (isServerEnv) {\n // Server env gets the real RSC runtime (used by RSC layer)\n content[rscPaths.rscRuntime] = generateRscRuntimeModule(true)\n } else {\n // Client env gets stubs\n content[rscPaths.rscRuntime] = generateRscRuntimeModule(false)\n }\n\n // virtual:tanstack-rsc-hmr\n content[rscPaths.rscHmr] = generateRscHmrModule(isClientEnv, isDev)\n content[rscPaths.rscBrowserDecode] = isClientEnv\n ? `export * from '@tanstack/react-start/rsbuild/browser-decode'`\n : `export function createFromReadableStream() { throw new Error('RSC browser decode is only available in the client environment') }\nexport function createFromFetch() { throw new Error('RSC browser decode is only available in the client environment') }`\n content[rscPaths.rscSsrDecode] = isServerEnv\n ? `export * from '@tanstack/react-start/rsbuild/ssr-decode'`\n : `export function setOnClientReference() {}\nexport function createFromReadableStream() { throw new Error('RSC SSR decode is only available in the server environment') }`\n }\n\n return content\n }\n\n // Build a map from virtual module IDs to their virtual file paths.\n // Scheme-like IDs are rewritten with NormalModuleReplacementPlugin because\n // rspack validates request schemes before normal alias resolution.\n const aliasMap: Record<string, string> = {\n [VIRTUAL_MODULES.startManifest]: paths.manifest,\n [VIRTUAL_MODULES.injectedHeadScripts]: paths.injectedHeadScripts,\n [VIRTUAL_MODULES.serverFnResolver]: paths.serverFnResolver,\n [VIRTUAL_MODULES.pluginAdapters]: paths.pluginAdapters,\n }\n\n // Add RSC virtual module aliases\n if (rscPaths) {\n aliasMap[RSC_RUNTIME_VIRTUAL_ID] = rscPaths.rscRuntime\n aliasMap[RSC_HMR_VIRTUAL_ID] = rscPaths.rscHmr\n aliasMap[RSC_BROWSER_DECODE_VIRTUAL_ID] = rscPaths.rscBrowserDecode\n aliasMap[RSC_SSR_DECODE_VIRTUAL_ID] = rscPaths.rscSsrDecode\n }\n\n // Register VirtualModulesPlugin per environment via modifyRspackConfig\n api.modifyRspackConfig((config, utils) => {\n const envName = utils.environment.name\n const initialContent = getInitialContent(envName)\n\n // Create VirtualModulesPlugin instance\n const VMP = utils.rspack.experiments.VirtualModulesPlugin\n const vmPlugin = new VMP(initialContent)\n vmPlugins[envName] = vmPlugin\n readyVmPlugins[envName] = false\n config.plugins.push(vmPlugin)\n config.plugins.push({\n apply(compiler: {\n hooks: {\n thisCompilation: { tap: (name: string, handler: () => void) => void }\n }\n }) {\n compiler.hooks.thisCompilation.tap(\n 'TanStackStartFlushPendingVirtualModules',\n () => {\n readyVmPlugins[envName] = true\n flushPendingWrites(envName)\n },\n )\n },\n })\n\n // Rewrite scheme-like IDs to the VirtualModulesPlugin-backed file paths.\n for (const [moduleId, virtualFilePath] of Object.entries(aliasMap)) {\n const escaped = moduleId.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const NMR = utils.rspack.NormalModuleReplacementPlugin\n config.plugins.push(new NMR(new RegExp(`^${escaped}$`), virtualFilePath))\n }\n\n const resolve = config.resolve\n const resolveAlias = (resolve.alias ??= {}) as Record<string, string>\n resolveAlias[VIRTUAL_MODULES.serverFnResolver] = paths.serverFnResolver\n resolveAlias[VIRTUAL_MODULES.pluginAdapters] = paths.pluginAdapters\n\n // Add RSC-specific resolve aliases\n if (rscPaths) {\n resolveAlias[RSC_RUNTIME_VIRTUAL_ID] = rscPaths.rscRuntime\n resolveAlias[RSC_HMR_VIRTUAL_ID] = rscPaths.rscHmr\n resolveAlias[RSC_BROWSER_DECODE_VIRTUAL_ID] = rscPaths.rscBrowserDecode\n resolveAlias[RSC_SSR_DECODE_VIRTUAL_ID] = rscPaths.rscSsrDecode\n }\n })\n\n return {\n serverFnResolverPath: paths.serverFnResolver,\n manifestPath: paths.manifest,\n vmPlugins,\n\n generateCurrentResolverContent(forProvider?: boolean): string {\n return generateResolverContent(\n forProvider ? opts.providerEnvName : RSBUILD_ENVIRONMENT_NAMES.server,\n )\n },\n\n generateManifestContent(newClientBuild: NormalizedClientBuild): string {\n const { resolvedStartConfig } = opts.getConfig()\n const devClientEntryUrl = opts.getDevClientEntryUrl(\n resolvedStartConfig.basePaths.publicBase,\n )\n return generateManifestModuleBuild(\n newClientBuild,\n resolvedStartConfig.basePaths.publicBase,\n devClientEntryUrl,\n )\n },\n\n generateManifestValueLiteral(\n newClientBuild: NormalizedClientBuild,\n ): string {\n const { resolvedStartConfig } = opts.getConfig()\n return serializeStartManifestData(\n newClientBuild,\n resolvedStartConfig.basePaths.publicBase,\n )\n },\n\n updateManifest(newClientBuild: NormalizedClientBuild) {\n clientBuild = newClientBuild\n // Safe to call getConfig() here — runs after client build\n const { resolvedStartConfig } = opts.getConfig()\n if (isDev) {\n ;(\n globalThis as typeof globalThis & {\n [DEV_START_MANIFEST_GLOBAL]?: ReturnType<typeof buildStartManifest>\n }\n )[DEV_START_MANIFEST_GLOBAL] = buildStartManifestData(\n clientBuild,\n resolvedStartConfig.basePaths.publicBase,\n )\n }\n },\n\n updateServerFnResolver() {\n for (const environmentName of new Set([\n RSBUILD_ENVIRONMENT_NAMES.server,\n ...(hasSeparateProviderEnvironment ? [opts.providerEnvName] : []),\n ])) {\n if (!needsServerFnResolver(environmentName)) {\n continue\n }\n\n writeResolverContent(\n environmentName,\n generateResolverContent(environmentName),\n )\n }\n },\n\n tryUpdateServerFnResolver(content: string) {\n lastResolverContentByEnvironment[RSBUILD_ENVIRONMENT_NAMES.server] =\n content\n tryWriteModule(\n RSBUILD_ENVIRONMENT_NAMES.server,\n paths.serverFnResolver,\n content,\n )\n },\n\n getVirtualPath(moduleId: string): string {\n return virtualPath(root, moduleId)\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"virtual-modules.js","names":[],"sources":["../../../src/rsbuild/virtual-modules.ts"],"sourcesContent":["import { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { generateSerializationAdaptersModule } from '../serialization-adapters-module'\nimport { generateServerFnResolverModule } from '../start-compiler/server-fn-resolver-module'\nimport { buildStartManifest } from '../start-manifest-plugin/manifestBuilder'\nimport { RSBUILD_ENVIRONMENT_NAMES } from './planning'\nimport type {\n RsbuildPluginAPI,\n rspack as rspackNamespaceType,\n} from '@rsbuild/core'\nimport type {\n GetConfigFn,\n NormalizedClientBuild,\n SerializationAdapterConfig,\n} from '../types'\nimport type { ServerFn } from '../start-compiler/types'\n\ntype RspackNamespace = typeof rspackNamespaceType\ntype RspackVirtualModulesPlugin = InstanceType<\n RspackNamespace['experiments']['VirtualModulesPlugin']\n>\n\n// Virtual module IDs for RSC (must match what react-start-rsc imports)\nconst RSC_RUNTIME_VIRTUAL_ID = 'virtual:tanstack-rsc-runtime'\nconst RSC_HMR_VIRTUAL_ID = 'virtual:tanstack-rsc-hmr'\nconst RSC_BROWSER_DECODE_VIRTUAL_ID = 'virtual:tanstack-rsc-browser-decode'\nconst RSC_SSR_DECODE_VIRTUAL_ID = 'virtual:tanstack-rsc-ssr-decode'\nexport const START_MANIFEST_PLACEHOLDER = '__TSS_START_MANIFEST_PLACEHOLDER__'\nconst DEV_START_MANIFEST_GLOBAL = '__TSS_DEV_START_MANIFEST__'\n/**\n * VirtualModulesPlugin resolves module paths relative to compiler.context.\n * Prefix them under the app root so they are unique and watcher-friendly.\n */\nfunction virtualPath(root: string, moduleId: string): string {\n // VirtualModulesPlugin resolves paths relative to compiler.context (root).\n // Use a recognizable prefix to avoid collisions with real files.\n const sanitized = moduleId.replace(/[:#]/g, '_')\n return `${root}/node_modules/.virtual/${sanitized}.js`\n}\n\nexport interface VirtualModuleState {\n /** Call to update manifest content after client build completes */\n updateManifest: (clientBuild: NormalizedClientBuild) => void\n /** Call to update server fn resolver content after compilation discovers fns */\n updateServerFnResolver: () => void\n /** Try to write explicit resolver content now; queues if env not ready */\n tryUpdateServerFnResolver: (content: string) => void\n /** Get the virtual path for a given module ID */\n getVirtualPath: (moduleId: string) => string\n /** Generate resolver module content from current serverFnsById state.\n * When forProvider=true, generates without isClientReferenced checks (RSC layer). */\n generateCurrentResolverContent: (forProvider?: boolean) => string\n /** The absolute virtual path of the server fn resolver module */\n serverFnResolverPath: string\n /** The absolute virtual path of the manifest module */\n manifestPath: string\n /** Generate manifest module content from a given client build */\n generateManifestContent: (clientBuild: NormalizedClientBuild) => string\n /** Generate the serialized manifest value literal for asset patching */\n generateManifestValueLiteral: (clientBuild: NormalizedClientBuild) => string\n /** VirtualModulesPlugin instances keyed by environment name */\n vmPlugins: Record<string, RspackVirtualModulesPlugin>\n}\n\n// ---------------------------------------------------------------------------\n// Manifest module codegen\n// ---------------------------------------------------------------------------\n\nfunction generateManifestModuleDev(devClientEntryUrl: string): string {\n return `const fallbackManifest = {\n routes: {},\n clientEntry: '${devClientEntryUrl}',\n}\nexport const tsrStartManifest = () => globalThis[${JSON.stringify(DEV_START_MANIFEST_GLOBAL)}] ?? fallbackManifest`\n}\n\nfunction buildStartManifestData(\n clientBuild: NormalizedClientBuild,\n publicBase: string,\n inlineCss: boolean,\n) {\n const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST\n return buildStartManifest({\n clientBuild,\n routeTreeRoutes,\n basePath: publicBase,\n inlineCss,\n })\n}\n\nfunction serializeStartManifestData(\n clientBuild: NormalizedClientBuild,\n publicBase: string,\n inlineCss: boolean,\n): string {\n return JSON.stringify(\n buildStartManifestData(clientBuild, publicBase, inlineCss),\n )\n}\n\nfunction generateManifestModuleBuild(\n clientBuild: NormalizedClientBuild | undefined,\n publicBase: string,\n _devClientEntryUrl: string,\n inlineCss: boolean,\n): string {\n if (!clientBuild) {\n return `const tsrStartManifestData = ${JSON.stringify(START_MANIFEST_PLACEHOLDER)}\nexport const tsrStartManifest = () => tsrStartManifestData`\n }\n\n return `export const tsrStartManifest = () => (${serializeStartManifestData(clientBuild, publicBase, inlineCss)})`\n}\n\n// ---------------------------------------------------------------------------\n// Injected head scripts codegen\n// ---------------------------------------------------------------------------\n\nfunction generateInjectedHeadScripts(scripts?: string): string {\n return `export const injectedHeadScripts = ${scripts ? JSON.stringify(scripts) : 'undefined'}`\n}\n\n// ---------------------------------------------------------------------------\n// RSC virtual module codegen\n// ---------------------------------------------------------------------------\n\n/**\n * Generate virtual:tanstack-rsc-runtime content.\n * In the RSC layer this re-exports from react-server-dom-rspack/server.\n * In other layers it provides stubs that throw.\n */\nfunction generateRscRuntimeModule(isRscLayer: boolean): string {\n if (isRscLayer) {\n // Re-export the RSC runtime functions from react-server-dom-rspack/server.\n // NOTE: `createFromReadableStream` is a CLIENT-side API — it's NOT exported\n // by react-server-dom-rspack/server. The RSC layer never needs it (RSC\n // renders TO streams, doesn't decode FROM them). We provide a stub that\n // throws so the export surface stays consistent across bundlers.\n return `export { renderToReadableStream, createTemporaryReferenceSet, decodeReply, decodeAction, decodeFormState } from 'react-server-dom-rspack/server'\nexport function createFromReadableStream() { throw new Error('createFromReadableStream is not available in RSC environment (use SSR or browser decode instead)'); }\n// loadServerAction is provided by the RSC entry, not react-server-dom-rspack\nimport { getServerFnById } from '#tanstack-start-server-fn-resolver'\nexport const loadServerAction = async (id) => getServerFnById(id, { origin: 'server' })`\n }\n\n // In other layers, provide stubs that throw\n return `\nexport function renderToReadableStream() { throw new Error('renderToReadableStream can only be used in RSC environment'); }\nexport function createFromReadableStream() { throw new Error('createFromReadableStream can only be used in RSC environment'); }\nexport function createTemporaryReferenceSet() { throw new Error('createTemporaryReferenceSet can only be used in RSC environment'); }\nexport function decodeReply() { throw new Error('decodeReply can only be used in RSC environment'); }\nexport function loadServerAction() { throw new Error('loadServerAction can only be used in RSC environment'); }\nexport function decodeAction() { throw new Error('decodeAction can only be used in RSC environment'); }\nexport function decodeFormState() { throw new Error('decodeFormState can only be used in RSC environment'); }\n`\n}\n\n/**\n * Generate virtual:tanstack-rsc-hmr content.\n * In the client env during dev, listens for rsc:update WebSocket events\n * and invalidates the router. In all other contexts, exports nothing.\n */\nfunction generateRscHmrModule(isClientEnv: boolean, isDev: boolean): string {\n if (!isClientEnv || !isDev) {\n return 'export function setupRscHmr() {}'\n }\n\n // Rsbuild dev server delivers custom WebSocket events through\n // import.meta.webpackHot.on(event, cb). The server-side\n // sockWrite('custom', { event: 'rsc:update' }) maps directly to that.\n return `\n// RSC HMR listener for rsbuild dev server\n// Listens for 'rsc:update' custom events sent via sockWrite\nexport function setupRscHmr() {\n let __invalidateQueued = false\n\n function __queueInvalidate() {\n if (__invalidateQueued) return\n __invalidateQueued = true\n queueMicrotask(async () => {\n __invalidateQueued = false\n try {\n const router = window.__TSR_ROUTER__\n if (!router) {\n console.warn('[rsc:hmr] No router found on window.__TSR_ROUTER__')\n return\n }\n await router.invalidate()\n } catch (e) {\n console.warn('[rsc:hmr] Failed to invalidate router:', e)\n }\n })\n }\n\n if (import.meta.webpackHot) {\n import.meta.webpackHot.on('rsc:update', () => {\n __queueInvalidate()\n })\n }\n}\n`\n}\n\n// ---------------------------------------------------------------------------\n// Main registration\n// ---------------------------------------------------------------------------\n\nexport interface RegisterVirtualModulesOptions {\n root: string\n getConfig: GetConfigFn\n serverFnsById: Record<string, ServerFn>\n providerEnvName: string\n ssrIsProvider: boolean\n serializationAdapters: Array<SerializationAdapterConfig> | undefined\n /**\n * Get the URL at which the rsbuild dev server serves the client entry JS.\n * Called lazily inside modifyRspackConfig when getConfig() is available.\n * Example return: '/static/js/index.js'\n */\n getDevClientEntryUrl: (publicBase: string) => string\n /** Whether RSC virtual modules should be registered. */\n rscEnabled?: boolean | undefined\n}\n\n/**\n * Registers virtual modules for the rsbuild adapter using VirtualModulesPlugin.\n *\n * Creates one VirtualModulesPlugin per environment and registers them via\n * `modifyBundlerChain`. Provides update functions to refresh content dynamically.\n */\nexport function registerVirtualModules(\n api: RsbuildPluginAPI,\n opts: RegisterVirtualModulesOptions,\n): VirtualModuleState {\n const isDev = api.context.action === 'dev'\n const root = opts.root\n\n // Virtual module paths keyed by module ID\n const paths = {\n manifest: virtualPath(root, VIRTUAL_MODULES.startManifest),\n injectedHeadScripts: virtualPath(root, VIRTUAL_MODULES.injectedHeadScripts),\n serverFnResolver: virtualPath(root, VIRTUAL_MODULES.serverFnResolver),\n pluginAdapters: virtualPath(root, VIRTUAL_MODULES.pluginAdapters),\n }\n\n // RSC virtual module paths (only defined when RSC is enabled)\n const rscPaths = opts.rscEnabled\n ? {\n rscRuntime: virtualPath(root, RSC_RUNTIME_VIRTUAL_ID),\n rscHmr: virtualPath(root, RSC_HMR_VIRTUAL_ID),\n rscBrowserDecode: virtualPath(root, RSC_BROWSER_DECODE_VIRTUAL_ID),\n rscSsrDecode: virtualPath(root, RSC_SSR_DECODE_VIRTUAL_ID),\n }\n : null\n\n // Track VirtualModulesPlugin instances per environment for dynamic updates\n const vmPlugins: Record<string, RspackVirtualModulesPlugin> = {}\n const readyVmPlugins: Record<string, boolean> = {}\n const pendingWrites = new Map<string, Map<string, string>>()\n\n let clientBuild: NormalizedClientBuild | undefined\n const lastResolverContentByEnvironment: Record<string, string | undefined> =\n {}\n const hasSeparateProviderEnvironment =\n !opts.rscEnabled &&\n opts.providerEnvName !== RSBUILD_ENVIRONMENT_NAMES.server\n\n function isProviderEnvironment(environmentName: string): boolean {\n return environmentName === opts.providerEnvName\n }\n\n function needsServerFnResolver(environmentName: string): boolean {\n return (\n environmentName === RSBUILD_ENVIRONMENT_NAMES.server ||\n (hasSeparateProviderEnvironment && isProviderEnvironment(environmentName))\n )\n }\n\n function generateResolverContent(environmentName: string): string {\n return generateServerFnResolverModule({\n serverFnsById: opts.serverFnsById,\n includeClientReferencedCheck: !isProviderEnvironment(environmentName),\n useStaticImports: Boolean(opts.rscEnabled && isDev),\n })\n }\n\n function writeResolverContent(environmentName: string, content: string) {\n if (\n !isDev ||\n content !== lastResolverContentByEnvironment[environmentName]\n ) {\n lastResolverContentByEnvironment[environmentName] = content\n tryWriteModule(environmentName, paths.serverFnResolver, content)\n }\n }\n\n function queuePendingWrite(\n environmentName: string,\n filePath: string,\n content: string,\n ) {\n let writes = pendingWrites.get(environmentName)\n if (!writes) {\n writes = new Map()\n pendingWrites.set(environmentName, writes)\n }\n writes.set(filePath, content)\n }\n\n function tryWriteModule(\n environmentName: string,\n filePath: string,\n content: string,\n ) {\n const vmPlugin = vmPlugins[environmentName]\n if (!vmPlugin || !readyVmPlugins[environmentName]) {\n queuePendingWrite(environmentName, filePath, content)\n return false\n }\n\n vmPlugin.writeModule(filePath, content)\n return true\n }\n\n function flushPendingWrites(environmentName: string) {\n if (!readyVmPlugins[environmentName]) {\n return\n }\n\n const writes = pendingWrites.get(environmentName)\n if (!writes?.size) {\n return\n }\n\n for (const [filePath, content] of writes) {\n if (!tryWriteModule(environmentName, filePath, content)) {\n return\n }\n writes.delete(filePath)\n }\n\n if (writes.size === 0) {\n pendingWrites.delete(environmentName)\n }\n }\n\n // NOTE: getConfig() is deferred — it must NOT be called until modifyRsbuildConfig\n // has resolved (which sets resolvedStartConfig.root). All access to resolvedStartConfig\n // happens inside modifyRspackConfig (which runs after modifyRsbuildConfig) or\n // inside update callbacks (which run even later during/after compilation).\n\n // Generate initial content for each virtual module per environment\n function getInitialContent(environmentName: string): Record<string, string> {\n // Safe to call getConfig() here — this runs inside modifyRspackConfig\n const { resolvedStartConfig, startConfig } = opts.getConfig()\n const isServerEnv = environmentName === RSBUILD_ENVIRONMENT_NAMES.server\n const isClientEnv = environmentName === RSBUILD_ENVIRONMENT_NAMES.client\n const content: Record<string, string> = {}\n\n // Manifest — only meaningful for server env\n if (isServerEnv) {\n const devClientEntryUrl = opts.getDevClientEntryUrl(\n resolvedStartConfig.basePaths.publicBase,\n )\n content[paths.manifest] = isDev\n ? generateManifestModuleDev(devClientEntryUrl)\n : generateManifestModuleBuild(\n clientBuild,\n resolvedStartConfig.basePaths.publicBase,\n devClientEntryUrl,\n startConfig.server.build.inlineCss,\n )\n } else {\n content[paths.manifest] = 'export default {}'\n }\n\n // Injected head scripts — only server\n content[paths.injectedHeadScripts] = generateInjectedHeadScripts()\n\n // Server fn resolver — SSR and provider environments\n if (needsServerFnResolver(environmentName)) {\n content[paths.serverFnResolver] = generateResolverContent(environmentName)\n } else {\n // Client doesn't need the resolver but needs a valid module\n content[paths.serverFnResolver] = 'export {}'\n }\n\n // Plugin adapters — both environments get environment-specific content\n content[paths.pluginAdapters] = generateSerializationAdaptersModule({\n adapters: opts.serializationAdapters,\n runtime:\n environmentName === RSBUILD_ENVIRONMENT_NAMES.client\n ? 'client'\n : 'server',\n })\n\n // --- RSC virtual modules ---\n if (rscPaths) {\n // virtual:tanstack-rsc-runtime\n // In the server env, this provides the RSC runtime for the RSC layer.\n // The virtual module content is the same regardless of layer since\n // rspack layers handle module isolation. The RSC entry imports this\n // and the react-server condition on the RSC layer resolves\n // react-server-dom-rspack/server correctly.\n if (isServerEnv) {\n // Server env gets the real RSC runtime (used by RSC layer)\n content[rscPaths.rscRuntime] = generateRscRuntimeModule(true)\n } else {\n // Client env gets stubs\n content[rscPaths.rscRuntime] = generateRscRuntimeModule(false)\n }\n\n // virtual:tanstack-rsc-hmr\n content[rscPaths.rscHmr] = generateRscHmrModule(isClientEnv, isDev)\n content[rscPaths.rscBrowserDecode] = isClientEnv\n ? `export * from '@tanstack/react-start/rsbuild/browser-decode'`\n : `export function createFromReadableStream() { throw new Error('RSC browser decode is only available in the client environment') }\nexport function createFromFetch() { throw new Error('RSC browser decode is only available in the client environment') }`\n content[rscPaths.rscSsrDecode] = isServerEnv\n ? `export * from '@tanstack/react-start/rsbuild/ssr-decode'`\n : `export function setOnClientReference() {}\nexport function createFromReadableStream() { throw new Error('RSC SSR decode is only available in the server environment') }`\n }\n\n return content\n }\n\n // Build a map from virtual module IDs to their virtual file paths.\n // Scheme-like IDs are rewritten with NormalModuleReplacementPlugin because\n // rspack validates request schemes before normal alias resolution.\n const aliasMap: Record<string, string> = {\n [VIRTUAL_MODULES.startManifest]: paths.manifest,\n [VIRTUAL_MODULES.injectedHeadScripts]: paths.injectedHeadScripts,\n [VIRTUAL_MODULES.serverFnResolver]: paths.serverFnResolver,\n [VIRTUAL_MODULES.pluginAdapters]: paths.pluginAdapters,\n }\n\n // Add RSC virtual module aliases\n if (rscPaths) {\n aliasMap[RSC_RUNTIME_VIRTUAL_ID] = rscPaths.rscRuntime\n aliasMap[RSC_HMR_VIRTUAL_ID] = rscPaths.rscHmr\n aliasMap[RSC_BROWSER_DECODE_VIRTUAL_ID] = rscPaths.rscBrowserDecode\n aliasMap[RSC_SSR_DECODE_VIRTUAL_ID] = rscPaths.rscSsrDecode\n }\n\n // Register VirtualModulesPlugin per environment via modifyRspackConfig\n api.modifyRspackConfig((config, utils) => {\n const envName = utils.environment.name\n const initialContent = getInitialContent(envName)\n\n // Create VirtualModulesPlugin instance\n const VMP = utils.rspack.experiments.VirtualModulesPlugin\n const vmPlugin = new VMP(initialContent)\n vmPlugins[envName] = vmPlugin\n readyVmPlugins[envName] = false\n config.plugins.push(vmPlugin)\n config.plugins.push({\n apply(compiler: {\n hooks: {\n thisCompilation: { tap: (name: string, handler: () => void) => void }\n }\n }) {\n compiler.hooks.thisCompilation.tap(\n 'TanStackStartFlushPendingVirtualModules',\n () => {\n readyVmPlugins[envName] = true\n flushPendingWrites(envName)\n },\n )\n },\n })\n\n // Rewrite scheme-like IDs to the VirtualModulesPlugin-backed file paths.\n for (const [moduleId, virtualFilePath] of Object.entries(aliasMap)) {\n const escaped = moduleId.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const NMR = utils.rspack.NormalModuleReplacementPlugin\n config.plugins.push(new NMR(new RegExp(`^${escaped}$`), virtualFilePath))\n }\n\n const resolve = config.resolve\n const resolveAlias = (resolve.alias ??= {}) as Record<string, string>\n resolveAlias[VIRTUAL_MODULES.serverFnResolver] = paths.serverFnResolver\n resolveAlias[VIRTUAL_MODULES.pluginAdapters] = paths.pluginAdapters\n\n // Add RSC-specific resolve aliases\n if (rscPaths) {\n resolveAlias[RSC_RUNTIME_VIRTUAL_ID] = rscPaths.rscRuntime\n resolveAlias[RSC_HMR_VIRTUAL_ID] = rscPaths.rscHmr\n resolveAlias[RSC_BROWSER_DECODE_VIRTUAL_ID] = rscPaths.rscBrowserDecode\n resolveAlias[RSC_SSR_DECODE_VIRTUAL_ID] = rscPaths.rscSsrDecode\n }\n })\n\n return {\n serverFnResolverPath: paths.serverFnResolver,\n manifestPath: paths.manifest,\n vmPlugins,\n\n generateCurrentResolverContent(forProvider?: boolean): string {\n return generateResolverContent(\n forProvider ? opts.providerEnvName : RSBUILD_ENVIRONMENT_NAMES.server,\n )\n },\n\n generateManifestContent(newClientBuild: NormalizedClientBuild): string {\n const { resolvedStartConfig, startConfig } = opts.getConfig()\n const devClientEntryUrl = opts.getDevClientEntryUrl(\n resolvedStartConfig.basePaths.publicBase,\n )\n return generateManifestModuleBuild(\n newClientBuild,\n resolvedStartConfig.basePaths.publicBase,\n devClientEntryUrl,\n !isDev && startConfig.server.build.inlineCss,\n )\n },\n\n generateManifestValueLiteral(\n newClientBuild: NormalizedClientBuild,\n ): string {\n const { resolvedStartConfig, startConfig } = opts.getConfig()\n return serializeStartManifestData(\n newClientBuild,\n resolvedStartConfig.basePaths.publicBase,\n !isDev && startConfig.server.build.inlineCss,\n )\n },\n\n updateManifest(newClientBuild: NormalizedClientBuild) {\n clientBuild = newClientBuild\n // Safe to call getConfig() here — runs after client build\n const { resolvedStartConfig } = opts.getConfig()\n if (isDev) {\n ;(\n globalThis as typeof globalThis & {\n [DEV_START_MANIFEST_GLOBAL]?: ReturnType<typeof buildStartManifest>\n }\n )[DEV_START_MANIFEST_GLOBAL] = buildStartManifestData(\n clientBuild,\n resolvedStartConfig.basePaths.publicBase,\n false,\n )\n }\n },\n\n updateServerFnResolver() {\n for (const environmentName of new Set([\n RSBUILD_ENVIRONMENT_NAMES.server,\n ...(hasSeparateProviderEnvironment ? [opts.providerEnvName] : []),\n ])) {\n if (!needsServerFnResolver(environmentName)) {\n continue\n }\n\n writeResolverContent(\n environmentName,\n generateResolverContent(environmentName),\n )\n }\n },\n\n tryUpdateServerFnResolver(content: string) {\n lastResolverContentByEnvironment[RSBUILD_ENVIRONMENT_NAMES.server] =\n content\n tryWriteModule(\n RSBUILD_ENVIRONMENT_NAMES.server,\n paths.serverFnResolver,\n content,\n )\n },\n\n getVirtualPath(moduleId: string): string {\n return virtualPath(root, moduleId)\n },\n }\n}\n"],"mappings":"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"}