@tanstack/start-plugin-core 1.167.32 → 1.167.34
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.
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/vite/createVirtualModule.d.ts +12 -0
- package/dist/esm/vite/createVirtualModule.js +32 -0
- package/dist/esm/vite/createVirtualModule.js.map +1 -0
- package/dist/esm/vite/dev-server-plugin/plugin.js +6 -14
- package/dist/esm/vite/dev-server-plugin/plugin.js.map +1 -1
- package/dist/esm/vite/plugin.js +2 -1
- package/dist/esm/vite/plugin.js.map +1 -1
- package/dist/esm/vite/plugins.d.ts +3 -0
- package/dist/esm/vite/plugins.js +14 -2
- package/dist/esm/vite/plugins.js.map +1 -1
- package/dist/esm/vite/serialization-adapters-plugin.js +16 -29
- package/dist/esm/vite/serialization-adapters-plugin.js.map +1 -1
- package/dist/esm/vite/start-compiler-plugin/plugin.js +15 -28
- package/dist/esm/vite/start-compiler-plugin/plugin.js.map +1 -1
- package/dist/esm/vite/start-manifest-plugin/plugin.js +16 -27
- package/dist/esm/vite/start-manifest-plugin/plugin.js.map +1 -1
- package/package.json +6 -11
- package/src/index.ts +5 -1
- package/src/vite/createVirtualModule.ts +54 -0
- package/src/vite/dev-server-plugin/plugin.ts +7 -17
- package/src/vite/plugin.ts +4 -0
- package/src/vite/plugins.ts +16 -1
- package/src/vite/serialization-adapters-plugin.ts +22 -50
- package/src/vite/start-compiler-plugin/plugin.ts +30 -47
- package/src/vite/start-manifest-plugin/plugin.ts +26 -45
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type { TanStackStartInputConfig } from './schema.js';
|
|
2
2
|
export type { TanStackStartCoreOptions } from './types.js';
|
|
3
|
-
export type { TanStackStartVitePluginCoreOptions } from './vite/types.js';
|
|
3
|
+
export type { TanStackStartVitePluginCoreOptions, ViteRscForwardSsrResolverStrategy, } from './vite/types.js';
|
|
4
4
|
export type { TanStackStartViteInputConfig } from './vite/schema.js';
|
|
5
5
|
export { START_ENVIRONMENT_NAMES, VITE_ENVIRONMENT_NAMES } from './constants.js';
|
|
6
|
+
export { createVirtualModule } from './vite/createVirtualModule.js';
|
|
6
7
|
export { tanStackStartVite } from './vite/plugin.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { START_ENVIRONMENT_NAMES, VITE_ENVIRONMENT_NAMES } from "./constants.js";
|
|
2
|
+
import { createVirtualModule } from "./vite/createVirtualModule.js";
|
|
2
3
|
import { tanStackStartVite } from "./vite/plugin.js";
|
|
3
|
-
export { START_ENVIRONMENT_NAMES, VITE_ENVIRONMENT_NAMES, tanStackStartVite };
|
|
4
|
+
export { START_ENVIRONMENT_NAMES, VITE_ENVIRONMENT_NAMES, createVirtualModule, tanStackStartVite };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
type VirtualModuleLoadHandler = (this: any, id: string) => string | null | undefined | Promise<string | null | undefined>;
|
|
3
|
+
export declare function createVirtualModule(opts: {
|
|
4
|
+
name: string;
|
|
5
|
+
moduleId: string;
|
|
6
|
+
load: VirtualModuleLoadHandler;
|
|
7
|
+
apply?: Plugin['apply'];
|
|
8
|
+
applyToEnvironment?: Plugin['applyToEnvironment'];
|
|
9
|
+
enforce?: Plugin['enforce'];
|
|
10
|
+
sharedDuringBuild?: boolean;
|
|
11
|
+
}): Plugin;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { resolveViteId } from "../utils.js";
|
|
2
|
+
//#region src/vite/createVirtualModule.ts
|
|
3
|
+
function escapeRegExp(value) {
|
|
4
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
|
+
}
|
|
6
|
+
function createVirtualModule(opts) {
|
|
7
|
+
const resolvedId = resolveViteId(opts.moduleId.replaceAll("#", "%23"));
|
|
8
|
+
return {
|
|
9
|
+
name: opts.name,
|
|
10
|
+
apply: opts.apply,
|
|
11
|
+
applyToEnvironment: opts.applyToEnvironment,
|
|
12
|
+
enforce: opts.enforce,
|
|
13
|
+
sharedDuringBuild: opts.sharedDuringBuild,
|
|
14
|
+
resolveId: {
|
|
15
|
+
filter: { id: new RegExp(escapeRegExp(opts.moduleId)) },
|
|
16
|
+
handler(id) {
|
|
17
|
+
if (id === opts.moduleId) return resolvedId;
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
load: {
|
|
21
|
+
filter: { id: new RegExp(escapeRegExp(resolvedId)) },
|
|
22
|
+
handler(id) {
|
|
23
|
+
if (id !== resolvedId) return;
|
|
24
|
+
return opts.load.call(this, id);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { createVirtualModule };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=createVirtualModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createVirtualModule.js","names":[],"sources":["../../../src/vite/createVirtualModule.ts"],"sourcesContent":["import { resolveViteId } from '../utils'\nimport type { Plugin } from 'vite'\n\ntype VirtualModuleLoadHandler = (\n this: any,\n id: string,\n) => string | null | undefined | Promise<string | null | undefined>\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function createVirtualModule(opts: {\n name: string\n moduleId: string\n load: VirtualModuleLoadHandler\n apply?: Plugin['apply']\n applyToEnvironment?: Plugin['applyToEnvironment']\n enforce?: Plugin['enforce']\n sharedDuringBuild?: boolean\n}): Plugin {\n // Encode '#' as '%23' in the resolved ID to avoid browser treating it as URL fragment.\n // The browser requests /@id/__x00__%23tanstack-start-plugin-adapters instead of\n // /@id/__x00__#tanstack-start-plugin-adapters (which would truncate at #).\n const resolvedId = resolveViteId(opts.moduleId.replaceAll('#', '%23'))\n\n return {\n name: opts.name,\n apply: opts.apply,\n applyToEnvironment: opts.applyToEnvironment,\n enforce: opts.enforce,\n sharedDuringBuild: opts.sharedDuringBuild,\n resolveId: {\n filter: { id: new RegExp(escapeRegExp(opts.moduleId)) },\n handler(id) {\n if (id === opts.moduleId) {\n return resolvedId\n }\n\n return undefined\n },\n },\n load: {\n filter: { id: new RegExp(escapeRegExp(resolvedId)) },\n handler(id) {\n if (id !== resolvedId) {\n return undefined\n }\n\n return opts.load.call(this, id)\n },\n },\n }\n}\n"],"mappings":";;AAQA,SAAS,aAAa,OAAuB;AAC3C,QAAO,MAAM,QAAQ,uBAAuB,OAAO;;AAGrD,SAAgB,oBAAoB,MAQzB;CAIT,MAAM,aAAa,cAAc,KAAK,SAAS,WAAW,KAAK,MAAM,CAAC;AAEtE,QAAO;EACL,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,oBAAoB,KAAK;EACzB,SAAS,KAAK;EACd,mBAAmB,KAAK;EACxB,WAAW;GACT,QAAQ,EAAE,IAAI,IAAI,OAAO,aAAa,KAAK,SAAS,CAAC,EAAE;GACvD,QAAQ,IAAI;AACV,QAAI,OAAO,KAAK,SACd,QAAO;;GAKZ;EACD,MAAM;GACJ,QAAQ,EAAE,IAAI,IAAI,OAAO,aAAa,WAAW,CAAC,EAAE;GACpD,QAAQ,IAAI;AACV,QAAI,OAAO,WACT;AAGF,WAAO,KAAK,KAAK,KAAK,MAAM,GAAG;;GAElC;EACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ENTRY_POINTS, VITE_ENVIRONMENT_NAMES } from "../../constants.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createVirtualModule } from "../createVirtualModule.js";
|
|
3
3
|
import { extractHtmlScripts } from "./extract-html-scripts.js";
|
|
4
4
|
import { CSS_MODULES_REGEX, collectDevStyles, normalizeCssModuleCacheKey } from "./dev-styles.js";
|
|
5
5
|
import { isRunnableDevEnvironment } from "vite";
|
|
@@ -105,24 +105,16 @@ function devServerPlugin({ getConfig: _getConfig, devSsrStylesEnabled, installDe
|
|
|
105
105
|
});
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
-
}, {
|
|
108
|
+
}, createVirtualModule({
|
|
109
109
|
name: "tanstack-start-core:dev-server:injected-head-scripts",
|
|
110
110
|
sharedDuringBuild: true,
|
|
111
111
|
applyToEnvironment: (env) => env.config.consumer === "server",
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return resolveViteId(VIRTUAL_MODULES.injectedHeadScripts);
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
load: {
|
|
119
|
-
filter: { id: new RegExp(resolveViteId(VIRTUAL_MODULES.injectedHeadScripts)) },
|
|
120
|
-
handler() {
|
|
121
|
-
return `
|
|
112
|
+
moduleId: VIRTUAL_MODULES.injectedHeadScripts,
|
|
113
|
+
load() {
|
|
114
|
+
return `
|
|
122
115
|
export const injectedHeadScripts = ${JSON.stringify(injectedHeadScripts) || "undefined"}`;
|
|
123
|
-
}
|
|
124
116
|
}
|
|
125
|
-
}];
|
|
117
|
+
})];
|
|
126
118
|
}
|
|
127
119
|
/**
|
|
128
120
|
* Formats error for SSR message in error overlay
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../src/vite/dev-server-plugin/plugin.ts"],"sourcesContent":["import { isRunnableDevEnvironment } from 'vite'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { NodeRequest, sendNodeResponse } from 'srvx/node'\nimport { ENTRY_POINTS, VITE_ENVIRONMENT_NAMES } from '../../constants'\nimport { resolveViteId } from '../../utils'\nimport { extractHtmlScripts } from './extract-html-scripts'\nimport {\n CSS_MODULES_REGEX,\n collectDevStyles,\n normalizeCssModuleCacheKey,\n} from './dev-styles'\nimport type { Connect, DevEnvironment, PluginOption } from 'vite'\nimport type { GetConfigFn } from '../../types'\n\nexport function devServerPlugin({\n getConfig: _getConfig,\n devSsrStylesEnabled,\n installDevServerMiddleware,\n}: {\n getConfig: GetConfigFn\n devSsrStylesEnabled: boolean\n installDevServerMiddleware: boolean | undefined\n}): PluginOption {\n let isTest = false\n\n let injectedHeadScripts: string | undefined\n\n // Cache CSS modules content during transform hook.\n // For CSS modules, the transform hook receives the raw CSS content before\n // Vite wraps it in JS. We capture this to use during SSR style collection.\n const cssModulesCache: Record<string, string> = {}\n\n return [\n {\n name: 'tanstack-start-core:dev-server',\n config(_userConfig, { mode }) {\n isTest = isTest ? isTest : mode === 'test'\n },\n // Capture CSS modules content during transform\n transform: {\n filter: {\n id: CSS_MODULES_REGEX,\n },\n handler(code, id) {\n cssModulesCache[normalizeCssModuleCacheKey(id)] = code\n },\n },\n async configureServer(viteDevServer) {\n if (isTest) {\n return\n }\n\n // Extract the scripts that Vite plugins would inject into the initial HTML\n const templateHtml = `<html><head></head><body></body></html>`\n const transformedHtml = await viteDevServer.transformIndexHtml(\n '/',\n templateHtml,\n )\n const scripts = extractHtmlScripts(transformedHtml)\n injectedHeadScripts = scripts\n .flatMap((script) => script.content ?? [])\n .join(';')\n\n // CSS middleware registered in PRE-PHASE (before Vite's internal middlewares)\n // This ensures it handles /@tanstack-start/styles.css before any catch-all middleware\n // from other plugins (like nitro) that may be registered in the post-phase.\n // This makes the CSS endpoint work regardless of plugin order in the Vite config.\n // We check pathname.endsWith() to handle basepaths (e.g., /my-app/@tanstack-start/styles.css)\n // since pre-phase runs before Vite's base middleware strips the basepath.\n if (devSsrStylesEnabled) {\n viteDevServer.middlewares.use(async (req, res, next) => {\n const url = req.url ?? ''\n const pathname = url.split('?')[0]\n if (!pathname?.endsWith('/@tanstack-start/styles.css')) {\n return next()\n }\n\n try {\n // Parse route IDs from query param\n const urlObj = new URL(url, 'http://localhost')\n const routesParam = urlObj.searchParams.get('routes')\n const routeIds = routesParam ? routesParam.split(',') : []\n\n // Build entries list from route file paths\n const entries: Array<string> = []\n\n // Look up route file paths from manifest\n // Only routes registered in the manifest are used - this prevents path injection\n const routesManifest = (globalThis as any).TSS_ROUTES_MANIFEST as\n | Record<string, { filePath: string; children?: Array<string> }>\n | undefined\n\n if (routesManifest && routeIds.length > 0) {\n for (const routeId of routeIds) {\n const route = routesManifest[routeId]\n if (route?.filePath) {\n entries.push(route.filePath)\n }\n }\n }\n\n const css =\n entries.length > 0\n ? await collectDevStyles({\n viteDevServer,\n entries,\n cssModulesCache,\n })\n : undefined\n\n res.setHeader('Content-Type', 'text/css')\n res.setHeader('Cache-Control', 'no-store')\n res.end(css ?? '')\n } catch (e) {\n // Log error but still return valid CSS response to avoid MIME type issues\n console.error('[tanstack-start] Error collecting dev styles:', e)\n res.setHeader('Content-Type', 'text/css')\n res.setHeader('Cache-Control', 'no-store')\n res.end(\n `/* Error collecting styles: ${e instanceof Error ? e.message : String(e)} */`,\n )\n }\n })\n }\n\n return () => {\n const serverEnv = viteDevServer.environments[\n VITE_ENVIRONMENT_NAMES.server\n ] as DevEnvironment | undefined\n\n if (!serverEnv) {\n throw new Error(\n `Server environment ${VITE_ENVIRONMENT_NAMES.server} not found`,\n )\n }\n\n const installMiddleware = installDevServerMiddleware\n if (installMiddleware === false) {\n return\n }\n if (installMiddleware == undefined) {\n // do not install middleware in middlewareMode by default\n if (viteDevServer.config.server.middlewareMode) {\n return\n }\n\n // do not install middleware if SSR env in case another plugin already did\n if (\n !isRunnableDevEnvironment(serverEnv) ||\n // do not check via `isFetchableDevEnvironment` since nitro does implement the `FetchableDevEnvironment` interface but not via inheritance (which this helper checks)\n 'dispatchFetch' in serverEnv\n ) {\n return\n }\n }\n\n if (!isRunnableDevEnvironment(serverEnv)) {\n throw new Error(\n 'cannot install vite dev server middleware for TanStack Start since the SSR environment is not a RunnableDevEnvironment',\n )\n }\n\n viteDevServer.middlewares.use(async (req, res) => {\n // fix the request URL to match the original URL\n // otherwise, the request URL will '/index.html'\n if (req.originalUrl) {\n req.url = req.originalUrl\n }\n const webReq = new NodeRequest({ req, res })\n\n try {\n // Import and resolve the request by running the server request entry point\n // this request entry point must implement the `fetch` API as follows:\n /**\n * export default {\n * fetch(req: Request): Promise<Response>\n * }\n */\n const serverEntry = await serverEnv.runner.import(\n ENTRY_POINTS.server,\n )\n const webRes = await serverEntry['default'].fetch(webReq)\n\n return sendNodeResponse(res, webRes)\n } catch (e) {\n console.error(e)\n try {\n viteDevServer.ssrFixStacktrace(e as Error)\n } catch {}\n\n if (\n webReq.headers.get('content-type')?.includes('application/json')\n ) {\n return sendNodeResponse(\n res,\n new Response(\n JSON.stringify(\n {\n status: 500,\n error: 'Internal Server Error',\n message:\n 'An unexpected error occurred. Please try again later.',\n timestamp: new Date().toISOString(),\n },\n null,\n 2,\n ),\n {\n status: 500,\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n ),\n )\n }\n\n return sendNodeResponse(\n res,\n new Response(\n `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Error</title>\n <script type=\"module\">\n import { ErrorOverlay } from '/@vite/client'\n document.body.appendChild(new ErrorOverlay(${JSON.stringify(\n prepareError(req, e),\n ).replace(/</g, '\\\\u003c')}))\n </script>\n </head>\n <body>\n </body>\n </html>\n `,\n {\n status: 500,\n headers: {\n 'Content-Type': 'text/html',\n },\n },\n ),\n )\n }\n })\n }\n },\n },\n {\n name: 'tanstack-start-core:dev-server:injected-head-scripts',\n sharedDuringBuild: true,\n applyToEnvironment: (env) => env.config.consumer === 'server',\n resolveId: {\n filter: { id: new RegExp(VIRTUAL_MODULES.injectedHeadScripts) },\n handler(_id) {\n return resolveViteId(VIRTUAL_MODULES.injectedHeadScripts)\n },\n },\n load: {\n filter: {\n id: new RegExp(resolveViteId(VIRTUAL_MODULES.injectedHeadScripts)),\n },\n handler() {\n const mod = `\n export const injectedHeadScripts = ${JSON.stringify(injectedHeadScripts) || 'undefined'}`\n return mod\n },\n },\n },\n ]\n}\n\n/**\n * Formats error for SSR message in error overlay\n * @param req\n * @param error\n * @returns\n */\nfunction prepareError(req: Connect.IncomingMessage, error: unknown) {\n const e = error as Error\n return {\n message: `An error occurred while server rendering ${req.url}:\\n\\n\\t${\n typeof e === 'string' ? e : e.message\n } `,\n stack: typeof e === 'string' ? '' : e.stack,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../src/vite/dev-server-plugin/plugin.ts"],"sourcesContent":["import { isRunnableDevEnvironment } from 'vite'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { NodeRequest, sendNodeResponse } from 'srvx/node'\nimport { ENTRY_POINTS, VITE_ENVIRONMENT_NAMES } from '../../constants'\nimport { createVirtualModule } from '../createVirtualModule'\nimport { extractHtmlScripts } from './extract-html-scripts'\nimport {\n CSS_MODULES_REGEX,\n collectDevStyles,\n normalizeCssModuleCacheKey,\n} from './dev-styles'\nimport type { Connect, DevEnvironment, PluginOption } from 'vite'\nimport type { GetConfigFn } from '../../types'\n\nexport function devServerPlugin({\n getConfig: _getConfig,\n devSsrStylesEnabled,\n installDevServerMiddleware,\n}: {\n getConfig: GetConfigFn\n devSsrStylesEnabled: boolean\n installDevServerMiddleware: boolean | undefined\n}): PluginOption {\n let isTest = false\n\n let injectedHeadScripts: string | undefined\n\n // Cache CSS modules content during transform hook.\n // For CSS modules, the transform hook receives the raw CSS content before\n // Vite wraps it in JS. We capture this to use during SSR style collection.\n const cssModulesCache: Record<string, string> = {}\n\n return [\n {\n name: 'tanstack-start-core:dev-server',\n config(_userConfig, { mode }) {\n isTest = isTest ? isTest : mode === 'test'\n },\n // Capture CSS modules content during transform\n transform: {\n filter: {\n id: CSS_MODULES_REGEX,\n },\n handler(code, id) {\n cssModulesCache[normalizeCssModuleCacheKey(id)] = code\n },\n },\n async configureServer(viteDevServer) {\n if (isTest) {\n return\n }\n\n // Extract the scripts that Vite plugins would inject into the initial HTML\n const templateHtml = `<html><head></head><body></body></html>`\n const transformedHtml = await viteDevServer.transformIndexHtml(\n '/',\n templateHtml,\n )\n const scripts = extractHtmlScripts(transformedHtml)\n injectedHeadScripts = scripts\n .flatMap((script) => script.content ?? [])\n .join(';')\n\n // CSS middleware registered in PRE-PHASE (before Vite's internal middlewares)\n // This ensures it handles /@tanstack-start/styles.css before any catch-all middleware\n // from other plugins (like nitro) that may be registered in the post-phase.\n // This makes the CSS endpoint work regardless of plugin order in the Vite config.\n // We check pathname.endsWith() to handle basepaths (e.g., /my-app/@tanstack-start/styles.css)\n // since pre-phase runs before Vite's base middleware strips the basepath.\n if (devSsrStylesEnabled) {\n viteDevServer.middlewares.use(async (req, res, next) => {\n const url = req.url ?? ''\n const pathname = url.split('?')[0]\n if (!pathname?.endsWith('/@tanstack-start/styles.css')) {\n return next()\n }\n\n try {\n // Parse route IDs from query param\n const urlObj = new URL(url, 'http://localhost')\n const routesParam = urlObj.searchParams.get('routes')\n const routeIds = routesParam ? routesParam.split(',') : []\n\n // Build entries list from route file paths\n const entries: Array<string> = []\n\n // Look up route file paths from manifest\n // Only routes registered in the manifest are used - this prevents path injection\n const routesManifest = (globalThis as any).TSS_ROUTES_MANIFEST as\n | Record<string, { filePath: string; children?: Array<string> }>\n | undefined\n\n if (routesManifest && routeIds.length > 0) {\n for (const routeId of routeIds) {\n const route = routesManifest[routeId]\n if (route?.filePath) {\n entries.push(route.filePath)\n }\n }\n }\n\n const css =\n entries.length > 0\n ? await collectDevStyles({\n viteDevServer,\n entries,\n cssModulesCache,\n })\n : undefined\n\n res.setHeader('Content-Type', 'text/css')\n res.setHeader('Cache-Control', 'no-store')\n res.end(css ?? '')\n } catch (e) {\n // Log error but still return valid CSS response to avoid MIME type issues\n console.error('[tanstack-start] Error collecting dev styles:', e)\n res.setHeader('Content-Type', 'text/css')\n res.setHeader('Cache-Control', 'no-store')\n res.end(\n `/* Error collecting styles: ${e instanceof Error ? e.message : String(e)} */`,\n )\n }\n })\n }\n\n return () => {\n const serverEnv = viteDevServer.environments[\n VITE_ENVIRONMENT_NAMES.server\n ] as DevEnvironment | undefined\n\n if (!serverEnv) {\n throw new Error(\n `Server environment ${VITE_ENVIRONMENT_NAMES.server} not found`,\n )\n }\n\n const installMiddleware = installDevServerMiddleware\n if (installMiddleware === false) {\n return\n }\n if (installMiddleware == undefined) {\n // do not install middleware in middlewareMode by default\n if (viteDevServer.config.server.middlewareMode) {\n return\n }\n\n // do not install middleware if SSR env in case another plugin already did\n if (\n !isRunnableDevEnvironment(serverEnv) ||\n // do not check via `isFetchableDevEnvironment` since nitro does implement the `FetchableDevEnvironment` interface but not via inheritance (which this helper checks)\n 'dispatchFetch' in serverEnv\n ) {\n return\n }\n }\n\n if (!isRunnableDevEnvironment(serverEnv)) {\n throw new Error(\n 'cannot install vite dev server middleware for TanStack Start since the SSR environment is not a RunnableDevEnvironment',\n )\n }\n\n viteDevServer.middlewares.use(async (req, res) => {\n // fix the request URL to match the original URL\n // otherwise, the request URL will '/index.html'\n if (req.originalUrl) {\n req.url = req.originalUrl\n }\n const webReq = new NodeRequest({ req, res })\n\n try {\n // Import and resolve the request by running the server request entry point\n // this request entry point must implement the `fetch` API as follows:\n /**\n * export default {\n * fetch(req: Request): Promise<Response>\n * }\n */\n const serverEntry = await serverEnv.runner.import(\n ENTRY_POINTS.server,\n )\n const webRes = await serverEntry['default'].fetch(webReq)\n\n return sendNodeResponse(res, webRes)\n } catch (e) {\n console.error(e)\n try {\n viteDevServer.ssrFixStacktrace(e as Error)\n } catch {}\n\n if (\n webReq.headers.get('content-type')?.includes('application/json')\n ) {\n return sendNodeResponse(\n res,\n new Response(\n JSON.stringify(\n {\n status: 500,\n error: 'Internal Server Error',\n message:\n 'An unexpected error occurred. Please try again later.',\n timestamp: new Date().toISOString(),\n },\n null,\n 2,\n ),\n {\n status: 500,\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n ),\n )\n }\n\n return sendNodeResponse(\n res,\n new Response(\n `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Error</title>\n <script type=\"module\">\n import { ErrorOverlay } from '/@vite/client'\n document.body.appendChild(new ErrorOverlay(${JSON.stringify(\n prepareError(req, e),\n ).replace(/</g, '\\\\u003c')}))\n </script>\n </head>\n <body>\n </body>\n </html>\n `,\n {\n status: 500,\n headers: {\n 'Content-Type': 'text/html',\n },\n },\n ),\n )\n }\n })\n }\n },\n },\n createVirtualModule({\n name: 'tanstack-start-core:dev-server:injected-head-scripts',\n sharedDuringBuild: true,\n applyToEnvironment: (env) => env.config.consumer === 'server',\n moduleId: VIRTUAL_MODULES.injectedHeadScripts,\n load() {\n const mod = `\n export const injectedHeadScripts = ${JSON.stringify(injectedHeadScripts) || 'undefined'}`\n return mod\n },\n }),\n ]\n}\n\n/**\n * Formats error for SSR message in error overlay\n * @param req\n * @param error\n * @returns\n */\nfunction prepareError(req: Connect.IncomingMessage, error: unknown) {\n const e = error as Error\n return {\n message: `An error occurred while server rendering ${req.url}:\\n\\n\\t${\n typeof e === 'string' ? e : e.message\n } `,\n stack: typeof e === 'string' ? '' : e.stack,\n }\n}\n"],"mappings":"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"}
|
package/dist/esm/vite/plugin.js
CHANGED
|
@@ -8,7 +8,7 @@ import { buildStartViteEnvironments, createViteConfigPlan, createViteDefineConfi
|
|
|
8
8
|
import { devServerPlugin } from "./dev-server-plugin/plugin.js";
|
|
9
9
|
import { getClientOutputDirectory, getServerOutputDirectory } from "./output-directory.js";
|
|
10
10
|
import { previewServerPlugin } from "./preview-server-plugin/plugin.js";
|
|
11
|
-
import { createCaptureClientBuildPlugin, createDevBaseRewritePlugin, createPostBuildPlugin } from "./plugins.js";
|
|
11
|
+
import { createCaptureClientBuildPlugin, createDevBaseRewritePlugin, createPostBuildPlugin, createVirtualClientEntryPlugin } from "./plugins.js";
|
|
12
12
|
import { parseStartConfig } from "./schema.js";
|
|
13
13
|
import { startManifestPlugin } from "./start-manifest-plugin/plugin.js";
|
|
14
14
|
import { tanStackStartRouter } from "./start-router-plugin/plugin.js";
|
|
@@ -139,6 +139,7 @@ function tanStackStartVite(corePluginOpts, startPluginOpts) {
|
|
|
139
139
|
}),
|
|
140
140
|
tanStackStartRouter(normalizedStartPluginOpts, getConfig, corePluginOpts),
|
|
141
141
|
loadEnvPlugin(),
|
|
142
|
+
createVirtualClientEntryPlugin({ getClientEntry: () => configContext.resolveEntries().entryPaths.client }),
|
|
142
143
|
startManifestPlugin({
|
|
143
144
|
getClientBuild: () => getClientBuild(START_ENVIRONMENT_NAMES.client),
|
|
144
145
|
getConfig
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../../src/vite/plugin.ts"],"sourcesContent":["import { crawlFrameworkPkgs } from 'vitefu'\nimport {\n applyResolvedBaseAndOutput,\n applyResolvedRouterBasepath,\n createStartConfigContext,\n} from '../config-context'\nimport { START_ENVIRONMENT_NAMES } from '../constants'\nimport { importProtectionPlugin } from '../import-protection-plugin/plugin'\nimport {\n createServerFnBasePath,\n normalizePublicBase,\n shouldRewriteDevBasepath,\n} from '../planning'\nimport { startCompilerPlugin } from './start-compiler-plugin/plugin'\nimport { loadEnvPlugin } from './load-env-plugin/plugin'\nimport {\n buildStartViteEnvironments,\n createViteConfigPlan,\n createViteDefineConfig,\n createViteResolvedEntryAliases,\n} from './planning'\nimport { devServerPlugin } from './dev-server-plugin/plugin'\nimport { previewServerPlugin } from './preview-server-plugin/plugin'\nimport {\n createCaptureClientBuildPlugin,\n createDevBaseRewritePlugin,\n createPostBuildPlugin,\n} from './plugins'\nimport { parseStartConfig } from './schema'\nimport { startManifestPlugin } from './start-manifest-plugin/plugin'\nimport { tanStackStartRouter } from './start-router-plugin/plugin'\nimport {\n getClientOutputDirectory,\n getServerOutputDirectory,\n} from './output-directory'\nimport { postServerBuild } from './post-server-build'\nimport { serializationAdaptersPlugin } from './serialization-adapters-plugin'\nimport type { NormalizedClientBuild } from '../types'\nimport type {\n TanStackStartVitePluginCoreOptions,\n ViteRscForwardSsrResolverStrategy,\n} from './types'\nimport type { StartEnvironmentName } from '../constants'\nimport type { TanStackStartViteInputConfig } from './schema'\nimport type { PluginOption } from 'vite'\n\nexport function tanStackStartVite(\n corePluginOpts: TanStackStartVitePluginCoreOptions,\n startPluginOpts: TanStackStartViteInputConfig | undefined,\n): Array<PluginOption> {\n const normalizedStartPluginOpts = startPluginOpts ?? {}\n\n const configContext = createStartConfigContext({\n corePluginOpts,\n startPluginOpts: normalizedStartPluginOpts,\n parseConfig: parseStartConfig,\n })\n const { getConfig, resolvedStartConfig } = configContext\n const serverFnProviderEnv = corePluginOpts.providerEnvironmentName\n const ssrIsProvider = corePluginOpts.ssrIsProvider\n\n // When the router basepath and vite base are misaligned during dev,\n // we install a URL rewrite middleware instead of erroring.\n let needsDevBaseRewrite = false\n\n const capturedClientBuild: Partial<\n Record<StartEnvironmentName, NormalizedClientBuild>\n > = {}\n\n function getClientBuild(\n envName: StartEnvironmentName,\n ): NormalizedClientBuild | undefined {\n return capturedClientBuild[envName]\n }\n\n const environments: Array<{\n name: string\n type: 'client' | 'server'\n getServerFnById?: string\n }> = [\n { name: START_ENVIRONMENT_NAMES.client, type: 'client' },\n {\n name: START_ENVIRONMENT_NAMES.server,\n type: 'server',\n getServerFnById:\n corePluginOpts.ssrResolverStrategy.type === 'vite-rsc-forward'\n ? createViteRscForwarder(corePluginOpts.ssrResolverStrategy)\n : undefined,\n },\n ]\n if (\n serverFnProviderEnv !== START_ENVIRONMENT_NAMES.server &&\n !environments.find((e) => e.name === serverFnProviderEnv)\n ) {\n environments.push({\n name: serverFnProviderEnv,\n type: 'server',\n })\n }\n return [\n {\n name: 'tanstack-start-core:config',\n enforce: 'pre',\n async config(viteConfig, { command }) {\n const publicBase = normalizePublicBase(viteConfig.base)\n applyResolvedBaseAndOutput({\n resolvedStartConfig,\n root: viteConfig.root || process.cwd(),\n publicBase,\n clientOutputDirectory: getClientOutputDirectory(viteConfig),\n serverOutputDirectory: getServerOutputDirectory(viteConfig),\n })\n const { startConfig } = getConfig()\n const routerBasepath = applyResolvedRouterBasepath({\n resolvedStartConfig,\n startConfig,\n })\n\n if (\n shouldRewriteDevBasepath({\n command,\n middlewareMode: Boolean(viteConfig.server?.middlewareMode),\n routerBasepath,\n publicBase: resolvedStartConfig.basePaths.publicBase,\n })\n ) {\n // The router basepath and vite base are misaligned.\n // Instead of erroring, we install a dev-server middleware that\n // rewrites incoming request URLs to prepend the vite base prefix.\n // This allows users to have e.g. base: '/_ui/' for asset URLs\n // while keeping router basepath at '/' for page navigation.\n needsDevBaseRewrite = true\n }\n\n const TSS_SERVER_FN_BASE = createServerFnBasePath({\n routerBasepath,\n serverFnBase: startConfig.serverFns.base,\n })\n const resolvedEntryPlan = configContext.resolveEntries()\n\n const entryAliases = createViteResolvedEntryAliases({\n entryPaths: resolvedEntryPlan.entryPaths,\n })\n\n const startPackageName =\n `@tanstack/${corePluginOpts.framework}-start` as const\n\n // crawl packages that have start in \"peerDependencies\"\n // see https://github.com/svitejs/vitefu/blob/d8d82fa121e3b2215ba437107093c77bde51b63b/src/index.js#L95-L101\n\n // this is currently uncached; could be implemented similarly as vite handles lock file changes\n // see https://github.com/vitejs/vite/blob/557f797d29422027e8c451ca50dd84bf8c41b5f0/packages/vite/src/node/optimizer/index.ts#L1282\n\n const crawlFrameworkPkgsResult = await crawlFrameworkPkgs({\n root: process.cwd(),\n isBuild: command === 'build',\n isFrameworkPkgByJson(pkgJson) {\n const peerDependencies = pkgJson['peerDependencies']\n\n if (peerDependencies) {\n if (\n startPackageName in peerDependencies ||\n '@tanstack/start-client-core' in peerDependencies\n ) {\n return true\n }\n }\n\n return false\n },\n })\n\n const viteConfigPlan = createViteConfigPlan({\n viteConfig,\n framework: corePluginOpts.framework,\n entryAliases,\n clientOutputDirectory: resolvedStartConfig.outputDirectories.client,\n serverOutputDirectory: resolvedStartConfig.outputDirectories.server,\n serverFnProviderEnv,\n optimizeDepsExclude: crawlFrameworkPkgsResult.optimizeDeps.exclude,\n noExternal: crawlFrameworkPkgsResult.ssr.noExternal.sort(),\n })\n\n return {\n // see https://vite.dev/config/shared-options.html#apptype\n // this will prevent vite from injecting middlewares that we don't want\n appType: viteConfig.appType ?? 'custom',\n environments: viteConfigPlan.environments,\n resolve: viteConfigPlan.resolve,\n define: createViteDefineConfig({\n command,\n mode: viteConfig.mode,\n serverFnBase: TSS_SERVER_FN_BASE,\n routerBasepath,\n spaEnabled: startConfig.spa?.enabled,\n devSsrStylesEnabled: startConfig.dev.ssrStyles.enabled,\n devSsrStylesBasepath:\n startConfig.dev.ssrStyles.basepath ??\n resolvedStartConfig.basePaths.publicBase,\n staticNodeEnv: startConfig.server.build.staticNodeEnv,\n }),\n builder: {\n sharedPlugins: true,\n async buildApp(builder) {\n await buildStartViteEnvironments({\n builder,\n providerEnvironmentName: serverFnProviderEnv,\n ssrIsProvider,\n })\n },\n },\n }\n },\n },\n createPostBuildPlugin({\n getConfig,\n postServerBuild,\n }),\n // Server function plugin handles:\n // 1. Identifying createServerFn().handler() calls\n // 2. Extracting server functions to separate modules\n // 3. Replacing call sites with RPC stubs\n // 4. Generating the server function manifest\n // Also handles createIsomorphicFn, createServerOnlyFn, createClientOnlyFn, createMiddleware\n startCompilerPlugin({\n framework: corePluginOpts.framework,\n environments,\n generateFunctionId:\n normalizedStartPluginOpts.serverFns?.generateFunctionId,\n providerEnvName: serverFnProviderEnv,\n }),\n importProtectionPlugin({\n getConfig,\n framework: corePluginOpts.framework,\n environments,\n providerEnvName: serverFnProviderEnv,\n }),\n tanStackStartRouter(normalizedStartPluginOpts, getConfig, corePluginOpts),\n loadEnvPlugin(),\n startManifestPlugin({\n getClientBuild: () => getClientBuild(START_ENVIRONMENT_NAMES.client),\n getConfig,\n }),\n // When the vite base and router basepath are misaligned (e.g. base: '/_ui/', basepath: '/'),\n // install a middleware that rewrites incoming request URLs to prepend the vite base prefix.\n // This allows Vite's internal base middleware to accept the requests, then strips the prefix\n // before passing to the SSR handler.\n // Registered BEFORE devServerPlugin so this middleware is added to the Connect stack first,\n // ensuring all subsequent middlewares (CSS, SSR, etc.) see the rewritten URL.\n createDevBaseRewritePlugin({\n shouldRewriteDevBase: () => needsDevBaseRewrite,\n resolvedStartConfig,\n }),\n devServerPlugin({\n getConfig,\n devSsrStylesEnabled:\n normalizedStartPluginOpts.dev?.ssrStyles?.enabled ?? true,\n installDevServerMiddleware:\n normalizedStartPluginOpts.vite?.installDevServerMiddleware,\n }),\n previewServerPlugin(),\n serializationAdaptersPlugin({\n adapters: corePluginOpts.serializationAdapters,\n }),\n createCaptureClientBuildPlugin({\n capturedClientBuild,\n }),\n ]\n}\n\nfunction createViteRscForwarder(strategy: ViteRscForwardSsrResolverStrategy) {\n return `export async function getServerFnById(id, access) {\n const m = await import.meta.viteRsc.loadModule(${JSON.stringify(strategy.sourceEnvironmentName)}, ${JSON.stringify(strategy.sourceEntry)})\n return m[${JSON.stringify(strategy.exportName)}](id, access)\n}`\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../../src/vite/plugin.ts"],"sourcesContent":["import { crawlFrameworkPkgs } from 'vitefu'\nimport {\n applyResolvedBaseAndOutput,\n applyResolvedRouterBasepath,\n createStartConfigContext,\n} from '../config-context'\nimport { START_ENVIRONMENT_NAMES } from '../constants'\nimport { importProtectionPlugin } from '../import-protection-plugin/plugin'\nimport {\n createServerFnBasePath,\n normalizePublicBase,\n shouldRewriteDevBasepath,\n} from '../planning'\nimport { startCompilerPlugin } from './start-compiler-plugin/plugin'\nimport { loadEnvPlugin } from './load-env-plugin/plugin'\nimport {\n buildStartViteEnvironments,\n createViteConfigPlan,\n createViteDefineConfig,\n createViteResolvedEntryAliases,\n} from './planning'\nimport { devServerPlugin } from './dev-server-plugin/plugin'\nimport { previewServerPlugin } from './preview-server-plugin/plugin'\nimport {\n createCaptureClientBuildPlugin,\n createDevBaseRewritePlugin,\n createPostBuildPlugin,\n createVirtualClientEntryPlugin,\n} from './plugins'\nimport { parseStartConfig } from './schema'\nimport { startManifestPlugin } from './start-manifest-plugin/plugin'\nimport { tanStackStartRouter } from './start-router-plugin/plugin'\nimport {\n getClientOutputDirectory,\n getServerOutputDirectory,\n} from './output-directory'\nimport { postServerBuild } from './post-server-build'\nimport { serializationAdaptersPlugin } from './serialization-adapters-plugin'\nimport type { NormalizedClientBuild } from '../types'\nimport type {\n TanStackStartVitePluginCoreOptions,\n ViteRscForwardSsrResolverStrategy,\n} from './types'\nimport type { StartEnvironmentName } from '../constants'\nimport type { TanStackStartViteInputConfig } from './schema'\nimport type { PluginOption } from 'vite'\n\nexport function tanStackStartVite(\n corePluginOpts: TanStackStartVitePluginCoreOptions,\n startPluginOpts: TanStackStartViteInputConfig | undefined,\n): Array<PluginOption> {\n const normalizedStartPluginOpts = startPluginOpts ?? {}\n\n const configContext = createStartConfigContext({\n corePluginOpts,\n startPluginOpts: normalizedStartPluginOpts,\n parseConfig: parseStartConfig,\n })\n const { getConfig, resolvedStartConfig } = configContext\n const serverFnProviderEnv = corePluginOpts.providerEnvironmentName\n const ssrIsProvider = corePluginOpts.ssrIsProvider\n\n // When the router basepath and vite base are misaligned during dev,\n // we install a URL rewrite middleware instead of erroring.\n let needsDevBaseRewrite = false\n\n const capturedClientBuild: Partial<\n Record<StartEnvironmentName, NormalizedClientBuild>\n > = {}\n\n function getClientBuild(\n envName: StartEnvironmentName,\n ): NormalizedClientBuild | undefined {\n return capturedClientBuild[envName]\n }\n\n const environments: Array<{\n name: string\n type: 'client' | 'server'\n getServerFnById?: string\n }> = [\n { name: START_ENVIRONMENT_NAMES.client, type: 'client' },\n {\n name: START_ENVIRONMENT_NAMES.server,\n type: 'server',\n getServerFnById:\n corePluginOpts.ssrResolverStrategy.type === 'vite-rsc-forward'\n ? createViteRscForwarder(corePluginOpts.ssrResolverStrategy)\n : undefined,\n },\n ]\n if (\n serverFnProviderEnv !== START_ENVIRONMENT_NAMES.server &&\n !environments.find((e) => e.name === serverFnProviderEnv)\n ) {\n environments.push({\n name: serverFnProviderEnv,\n type: 'server',\n })\n }\n return [\n {\n name: 'tanstack-start-core:config',\n enforce: 'pre',\n async config(viteConfig, { command }) {\n const publicBase = normalizePublicBase(viteConfig.base)\n applyResolvedBaseAndOutput({\n resolvedStartConfig,\n root: viteConfig.root || process.cwd(),\n publicBase,\n clientOutputDirectory: getClientOutputDirectory(viteConfig),\n serverOutputDirectory: getServerOutputDirectory(viteConfig),\n })\n const { startConfig } = getConfig()\n const routerBasepath = applyResolvedRouterBasepath({\n resolvedStartConfig,\n startConfig,\n })\n\n if (\n shouldRewriteDevBasepath({\n command,\n middlewareMode: Boolean(viteConfig.server?.middlewareMode),\n routerBasepath,\n publicBase: resolvedStartConfig.basePaths.publicBase,\n })\n ) {\n // The router basepath and vite base are misaligned.\n // Instead of erroring, we install a dev-server middleware that\n // rewrites incoming request URLs to prepend the vite base prefix.\n // This allows users to have e.g. base: '/_ui/' for asset URLs\n // while keeping router basepath at '/' for page navigation.\n needsDevBaseRewrite = true\n }\n\n const TSS_SERVER_FN_BASE = createServerFnBasePath({\n routerBasepath,\n serverFnBase: startConfig.serverFns.base,\n })\n const resolvedEntryPlan = configContext.resolveEntries()\n\n const entryAliases = createViteResolvedEntryAliases({\n entryPaths: resolvedEntryPlan.entryPaths,\n })\n\n const startPackageName =\n `@tanstack/${corePluginOpts.framework}-start` as const\n\n // crawl packages that have start in \"peerDependencies\"\n // see https://github.com/svitejs/vitefu/blob/d8d82fa121e3b2215ba437107093c77bde51b63b/src/index.js#L95-L101\n\n // this is currently uncached; could be implemented similarly as vite handles lock file changes\n // see https://github.com/vitejs/vite/blob/557f797d29422027e8c451ca50dd84bf8c41b5f0/packages/vite/src/node/optimizer/index.ts#L1282\n\n const crawlFrameworkPkgsResult = await crawlFrameworkPkgs({\n root: process.cwd(),\n isBuild: command === 'build',\n isFrameworkPkgByJson(pkgJson) {\n const peerDependencies = pkgJson['peerDependencies']\n\n if (peerDependencies) {\n if (\n startPackageName in peerDependencies ||\n '@tanstack/start-client-core' in peerDependencies\n ) {\n return true\n }\n }\n\n return false\n },\n })\n\n const viteConfigPlan = createViteConfigPlan({\n viteConfig,\n framework: corePluginOpts.framework,\n entryAliases,\n clientOutputDirectory: resolvedStartConfig.outputDirectories.client,\n serverOutputDirectory: resolvedStartConfig.outputDirectories.server,\n serverFnProviderEnv,\n optimizeDepsExclude: crawlFrameworkPkgsResult.optimizeDeps.exclude,\n noExternal: crawlFrameworkPkgsResult.ssr.noExternal.sort(),\n })\n\n return {\n // see https://vite.dev/config/shared-options.html#apptype\n // this will prevent vite from injecting middlewares that we don't want\n appType: viteConfig.appType ?? 'custom',\n environments: viteConfigPlan.environments,\n resolve: viteConfigPlan.resolve,\n define: createViteDefineConfig({\n command,\n mode: viteConfig.mode,\n serverFnBase: TSS_SERVER_FN_BASE,\n routerBasepath,\n spaEnabled: startConfig.spa?.enabled,\n devSsrStylesEnabled: startConfig.dev.ssrStyles.enabled,\n devSsrStylesBasepath:\n startConfig.dev.ssrStyles.basepath ??\n resolvedStartConfig.basePaths.publicBase,\n staticNodeEnv: startConfig.server.build.staticNodeEnv,\n }),\n builder: {\n sharedPlugins: true,\n async buildApp(builder) {\n await buildStartViteEnvironments({\n builder,\n providerEnvironmentName: serverFnProviderEnv,\n ssrIsProvider,\n })\n },\n },\n }\n },\n },\n createPostBuildPlugin({\n getConfig,\n postServerBuild,\n }),\n // Server function plugin handles:\n // 1. Identifying createServerFn().handler() calls\n // 2. Extracting server functions to separate modules\n // 3. Replacing call sites with RPC stubs\n // 4. Generating the server function manifest\n // Also handles createIsomorphicFn, createServerOnlyFn, createClientOnlyFn, createMiddleware\n startCompilerPlugin({\n framework: corePluginOpts.framework,\n environments,\n generateFunctionId:\n normalizedStartPluginOpts.serverFns?.generateFunctionId,\n providerEnvName: serverFnProviderEnv,\n }),\n importProtectionPlugin({\n getConfig,\n framework: corePluginOpts.framework,\n environments,\n providerEnvName: serverFnProviderEnv,\n }),\n tanStackStartRouter(normalizedStartPluginOpts, getConfig, corePluginOpts),\n loadEnvPlugin(),\n createVirtualClientEntryPlugin({\n getClientEntry: () => configContext.resolveEntries().entryPaths.client,\n }),\n startManifestPlugin({\n getClientBuild: () => getClientBuild(START_ENVIRONMENT_NAMES.client),\n getConfig,\n }),\n // When the vite base and router basepath are misaligned (e.g. base: '/_ui/', basepath: '/'),\n // install a middleware that rewrites incoming request URLs to prepend the vite base prefix.\n // This allows Vite's internal base middleware to accept the requests, then strips the prefix\n // before passing to the SSR handler.\n // Registered BEFORE devServerPlugin so this middleware is added to the Connect stack first,\n // ensuring all subsequent middlewares (CSS, SSR, etc.) see the rewritten URL.\n createDevBaseRewritePlugin({\n shouldRewriteDevBase: () => needsDevBaseRewrite,\n resolvedStartConfig,\n }),\n devServerPlugin({\n getConfig,\n devSsrStylesEnabled:\n normalizedStartPluginOpts.dev?.ssrStyles?.enabled ?? true,\n installDevServerMiddleware:\n normalizedStartPluginOpts.vite?.installDevServerMiddleware,\n }),\n previewServerPlugin(),\n serializationAdaptersPlugin({\n adapters: corePluginOpts.serializationAdapters,\n }),\n createCaptureClientBuildPlugin({\n capturedClientBuild,\n }),\n ]\n}\n\nfunction createViteRscForwarder(strategy: ViteRscForwardSsrResolverStrategy) {\n return `export async function getServerFnById(id, access) {\n const m = await import.meta.viteRsc.loadModule(${JSON.stringify(strategy.sourceEnvironmentName)}, ${JSON.stringify(strategy.sourceEntry)})\n return m[${JSON.stringify(strategy.exportName)}](id, access)\n}`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA+CA,SAAgB,kBACd,gBACA,iBACqB;CACrB,MAAM,4BAA4B,mBAAmB,EAAE;CAEvD,MAAM,gBAAgB,yBAAyB;EAC7C;EACA,iBAAiB;EACjB,aAAa;EACd,CAAC;CACF,MAAM,EAAE,WAAW,wBAAwB;CAC3C,MAAM,sBAAsB,eAAe;CAC3C,MAAM,gBAAgB,eAAe;CAIrC,IAAI,sBAAsB;CAE1B,MAAM,sBAEF,EAAE;CAEN,SAAS,eACP,SACmC;AACnC,SAAO,oBAAoB;;CAG7B,MAAM,eAID,CACH;EAAE,MAAM,wBAAwB;EAAQ,MAAM;EAAU,EACxD;EACE,MAAM,wBAAwB;EAC9B,MAAM;EACN,iBACE,eAAe,oBAAoB,SAAS,qBACxC,uBAAuB,eAAe,oBAAoB,GAC1D,KAAA;EACP,CACF;AACD,KACE,wBAAwB,wBAAwB,UAChD,CAAC,aAAa,MAAM,MAAM,EAAE,SAAS,oBAAoB,CAEzD,cAAa,KAAK;EAChB,MAAM;EACN,MAAM;EACP,CAAC;AAEJ,QAAO;EACL;GACE,MAAM;GACN,SAAS;GACT,MAAM,OAAO,YAAY,EAAE,WAAW;IACpC,MAAM,aAAa,oBAAoB,WAAW,KAAK;AACvD,+BAA2B;KACzB;KACA,MAAM,WAAW,QAAQ,QAAQ,KAAK;KACtC;KACA,uBAAuB,yBAAyB,WAAW;KAC3D,uBAAuB,yBAAyB,WAAW;KAC5D,CAAC;IACF,MAAM,EAAE,gBAAgB,WAAW;IACnC,MAAM,iBAAiB,4BAA4B;KACjD;KACA;KACD,CAAC;AAEF,QACE,yBAAyB;KACvB;KACA,gBAAgB,QAAQ,WAAW,QAAQ,eAAe;KAC1D;KACA,YAAY,oBAAoB,UAAU;KAC3C,CAAC,CAOF,uBAAsB;IAGxB,MAAM,qBAAqB,uBAAuB;KAChD;KACA,cAAc,YAAY,UAAU;KACrC,CAAC;IAGF,MAAM,eAAe,+BAA+B,EAClD,YAHwB,cAAc,gBAAgB,CAGxB,YAC/B,CAAC;IAEF,MAAM,mBACJ,aAAa,eAAe,UAAU;IAQxC,MAAM,2BAA2B,MAAM,mBAAmB;KACxD,MAAM,QAAQ,KAAK;KACnB,SAAS,YAAY;KACrB,qBAAqB,SAAS;MAC5B,MAAM,mBAAmB,QAAQ;AAEjC,UAAI;WAEA,oBAAoB,oBACpB,iCAAiC,iBAEjC,QAAO;;AAIX,aAAO;;KAEV,CAAC;IAEF,MAAM,iBAAiB,qBAAqB;KAC1C;KACA,WAAW,eAAe;KAC1B;KACA,uBAAuB,oBAAoB,kBAAkB;KAC7D,uBAAuB,oBAAoB,kBAAkB;KAC7D;KACA,qBAAqB,yBAAyB,aAAa;KAC3D,YAAY,yBAAyB,IAAI,WAAW,MAAM;KAC3D,CAAC;AAEF,WAAO;KAGL,SAAS,WAAW,WAAW;KAC/B,cAAc,eAAe;KAC7B,SAAS,eAAe;KACxB,QAAQ,uBAAuB;MAC7B;MACA,MAAM,WAAW;MACjB,cAAc;MACd;MACA,YAAY,YAAY,KAAK;MAC7B,qBAAqB,YAAY,IAAI,UAAU;MAC/C,sBACE,YAAY,IAAI,UAAU,YAC1B,oBAAoB,UAAU;MAChC,eAAe,YAAY,OAAO,MAAM;MACzC,CAAC;KACF,SAAS;MACP,eAAe;MACf,MAAM,SAAS,SAAS;AACtB,aAAM,2BAA2B;QAC/B;QACA,yBAAyB;QACzB;QACD,CAAC;;MAEL;KACF;;GAEJ;EACD,sBAAsB;GACpB;GACA;GACD,CAAC;EAOF,oBAAoB;GAClB,WAAW,eAAe;GAC1B;GACA,oBACE,0BAA0B,WAAW;GACvC,iBAAiB;GAClB,CAAC;EACF,uBAAuB;GACrB;GACA,WAAW,eAAe;GAC1B;GACA,iBAAiB;GAClB,CAAC;EACF,oBAAoB,2BAA2B,WAAW,eAAe;EACzE,eAAe;EACf,+BAA+B,EAC7B,sBAAsB,cAAc,gBAAgB,CAAC,WAAW,QACjE,CAAC;EACF,oBAAoB;GAClB,sBAAsB,eAAe,wBAAwB,OAAO;GACpE;GACD,CAAC;EAOF,2BAA2B;GACzB,4BAA4B;GAC5B;GACD,CAAC;EACF,gBAAgB;GACd;GACA,qBACE,0BAA0B,KAAK,WAAW,WAAW;GACvD,4BACE,0BAA0B,MAAM;GACnC,CAAC;EACF,qBAAqB;EACrB,4BAA4B,EAC1B,UAAU,eAAe,uBAC1B,CAAC;EACF,+BAA+B,EAC7B,qBACD,CAAC;EACH;;AAGH,SAAS,uBAAuB,UAA6C;AAC3E,QAAO;mDAC0C,KAAK,UAAU,SAAS,sBAAsB,CAAC,IAAI,KAAK,UAAU,SAAS,YAAY,CAAC;aAC9H,KAAK,UAAU,SAAS,WAAW,CAAC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { GetConfigFn, NormalizedClientBuild, ResolvedStartConfig } from '../types.js';
|
|
2
2
|
import { StartEnvironmentName } from '../constants.js';
|
|
3
3
|
import { PluginOption, ViteBuilder } from 'vite';
|
|
4
|
+
export declare function createVirtualClientEntryPlugin(opts: {
|
|
5
|
+
getClientEntry: () => string;
|
|
6
|
+
}): PluginOption;
|
|
4
7
|
export declare function createPostBuildPlugin(opts: {
|
|
5
8
|
getConfig: GetConfigFn;
|
|
6
9
|
postServerBuild: (opts: {
|
package/dist/esm/vite/plugins.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import { START_ENVIRONMENT_NAMES } from "../constants.js";
|
|
1
|
+
import { ENTRY_POINTS, START_ENVIRONMENT_NAMES } from "../constants.js";
|
|
2
|
+
import { createVirtualModule } from "./createVirtualModule.js";
|
|
2
3
|
import { normalizeViteClientBuild } from "./start-manifest-plugin/normalized-client-build.js";
|
|
4
|
+
import { normalizePath } from "vite";
|
|
3
5
|
//#region src/vite/plugins.ts
|
|
6
|
+
function createVirtualClientEntryPlugin(opts) {
|
|
7
|
+
return createVirtualModule({
|
|
8
|
+
name: "tanstack-start-core:virtual-client-entry",
|
|
9
|
+
moduleId: ENTRY_POINTS.client,
|
|
10
|
+
enforce: "pre",
|
|
11
|
+
load() {
|
|
12
|
+
return `import ${JSON.stringify(normalizePath(opts.getClientEntry()).replaceAll("\\", "/"))}`;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
4
16
|
function createPostBuildPlugin(opts) {
|
|
5
17
|
return {
|
|
6
18
|
name: "tanstack-start-core:post-build",
|
|
@@ -45,6 +57,6 @@ function createCaptureClientBuildPlugin(opts) {
|
|
|
45
57
|
};
|
|
46
58
|
}
|
|
47
59
|
//#endregion
|
|
48
|
-
export { createCaptureClientBuildPlugin, createDevBaseRewritePlugin, createPostBuildPlugin };
|
|
60
|
+
export { createCaptureClientBuildPlugin, createDevBaseRewritePlugin, createPostBuildPlugin, createVirtualClientEntryPlugin };
|
|
49
61
|
|
|
50
62
|
//# sourceMappingURL=plugins.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.js","names":[],"sources":["../../../src/vite/plugins.ts"],"sourcesContent":["import { START_ENVIRONMENT_NAMES } from '../constants'\nimport { normalizeViteClientBuild } from './start-manifest-plugin/normalized-client-build'\nimport type {\n GetConfigFn,\n NormalizedClientBuild,\n ResolvedStartConfig,\n} from '../types'\nimport type { StartEnvironmentName } from '../constants'\nimport type { PluginOption, ViteBuilder } from 'vite'\n\nexport function createPostBuildPlugin(opts: {\n getConfig: GetConfigFn\n postServerBuild: (opts: {\n startConfig: ReturnType<GetConfigFn>['startConfig']\n builder: ViteBuilder\n }) => Promise<void>\n}): PluginOption {\n return {\n name: 'tanstack-start-core:post-build',\n enforce: 'post',\n buildApp: {\n order: 'post',\n async handler(builder) {\n const { startConfig } = opts.getConfig()\n await opts.postServerBuild({ builder, startConfig })\n },\n },\n }\n}\n\nexport function createDevBaseRewritePlugin(opts: {\n shouldRewriteDevBase: () => boolean\n resolvedStartConfig: ResolvedStartConfig\n}): PluginOption {\n return {\n name: 'tanstack-start-core:dev-base-rewrite',\n configureServer(server) {\n if (!opts.shouldRewriteDevBase()) {\n return\n }\n\n const basePrefix = opts.resolvedStartConfig.basePaths.publicBase.replace(\n /\\/$/,\n '',\n )\n\n server.middlewares.use((req, _res, next) => {\n if (req.url && !req.url.startsWith(basePrefix)) {\n req.url = basePrefix + req.url\n }\n\n next()\n })\n },\n }\n}\n\nexport function createCaptureClientBuildPlugin(opts: {\n capturedClientBuild: Partial<\n Record<StartEnvironmentName, NormalizedClientBuild>\n >\n}): PluginOption {\n return {\n name: 'tanstack-start:core:capture-bundle',\n applyToEnvironment(environment) {\n return environment.name === START_ENVIRONMENT_NAMES.client\n },\n enforce: 'post',\n generateBundle(_options, bundle) {\n const environment = this.environment.name as StartEnvironmentName\n\n if (environment !== START_ENVIRONMENT_NAMES.client) {\n throw new Error(\n `Unexpected environment for client build capture: ${environment}`,\n )\n }\n\n opts.capturedClientBuild[environment] = normalizeViteClientBuild(bundle)\n },\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugins.js","names":[],"sources":["../../../src/vite/plugins.ts"],"sourcesContent":["import { normalizePath } from 'vite'\nimport { ENTRY_POINTS, START_ENVIRONMENT_NAMES } from '../constants'\nimport { createVirtualModule } from './createVirtualModule'\nimport { normalizeViteClientBuild } from './start-manifest-plugin/normalized-client-build'\nimport type {\n GetConfigFn,\n NormalizedClientBuild,\n ResolvedStartConfig,\n} from '../types'\nimport type { StartEnvironmentName } from '../constants'\nimport type { PluginOption, ViteBuilder } from 'vite'\n\nexport function createVirtualClientEntryPlugin(opts: {\n getClientEntry: () => string\n}): PluginOption {\n return createVirtualModule({\n name: 'tanstack-start-core:virtual-client-entry',\n moduleId: ENTRY_POINTS.client,\n enforce: 'pre',\n load() {\n return `import ${JSON.stringify(normalizePath(opts.getClientEntry()).replaceAll('\\\\', '/'))}`\n },\n })\n}\n\nexport function createPostBuildPlugin(opts: {\n getConfig: GetConfigFn\n postServerBuild: (opts: {\n startConfig: ReturnType<GetConfigFn>['startConfig']\n builder: ViteBuilder\n }) => Promise<void>\n}): PluginOption {\n return {\n name: 'tanstack-start-core:post-build',\n enforce: 'post',\n buildApp: {\n order: 'post',\n async handler(builder) {\n const { startConfig } = opts.getConfig()\n await opts.postServerBuild({ builder, startConfig })\n },\n },\n }\n}\n\nexport function createDevBaseRewritePlugin(opts: {\n shouldRewriteDevBase: () => boolean\n resolvedStartConfig: ResolvedStartConfig\n}): PluginOption {\n return {\n name: 'tanstack-start-core:dev-base-rewrite',\n configureServer(server) {\n if (!opts.shouldRewriteDevBase()) {\n return\n }\n\n const basePrefix = opts.resolvedStartConfig.basePaths.publicBase.replace(\n /\\/$/,\n '',\n )\n\n server.middlewares.use((req, _res, next) => {\n if (req.url && !req.url.startsWith(basePrefix)) {\n req.url = basePrefix + req.url\n }\n\n next()\n })\n },\n }\n}\n\nexport function createCaptureClientBuildPlugin(opts: {\n capturedClientBuild: Partial<\n Record<StartEnvironmentName, NormalizedClientBuild>\n >\n}): PluginOption {\n return {\n name: 'tanstack-start:core:capture-bundle',\n applyToEnvironment(environment) {\n return environment.name === START_ENVIRONMENT_NAMES.client\n },\n enforce: 'post',\n generateBundle(_options, bundle) {\n const environment = this.environment.name as StartEnvironmentName\n\n if (environment !== START_ENVIRONMENT_NAMES.client) {\n throw new Error(\n `Unexpected environment for client build capture: ${environment}`,\n )\n }\n\n opts.capturedClientBuild[environment] = normalizeViteClientBuild(bundle)\n },\n }\n}\n"],"mappings":";;;;;AAYA,SAAgB,+BAA+B,MAE9B;AACf,QAAO,oBAAoB;EACzB,MAAM;EACN,UAAU,aAAa;EACvB,SAAS;EACT,OAAO;AACL,UAAO,UAAU,KAAK,UAAU,cAAc,KAAK,gBAAgB,CAAC,CAAC,WAAW,MAAM,IAAI,CAAC;;EAE9F,CAAC;;AAGJ,SAAgB,sBAAsB,MAMrB;AACf,QAAO;EACL,MAAM;EACN,SAAS;EACT,UAAU;GACR,OAAO;GACP,MAAM,QAAQ,SAAS;IACrB,MAAM,EAAE,gBAAgB,KAAK,WAAW;AACxC,UAAM,KAAK,gBAAgB;KAAE;KAAS;KAAa,CAAC;;GAEvD;EACF;;AAGH,SAAgB,2BAA2B,MAG1B;AACf,QAAO;EACL,MAAM;EACN,gBAAgB,QAAQ;AACtB,OAAI,CAAC,KAAK,sBAAsB,CAC9B;GAGF,MAAM,aAAa,KAAK,oBAAoB,UAAU,WAAW,QAC/D,OACA,GACD;AAED,UAAO,YAAY,KAAK,KAAK,MAAM,SAAS;AAC1C,QAAI,IAAI,OAAO,CAAC,IAAI,IAAI,WAAW,WAAW,CAC5C,KAAI,MAAM,aAAa,IAAI;AAG7B,UAAM;KACN;;EAEL;;AAGH,SAAgB,+BAA+B,MAI9B;AACf,QAAO;EACL,MAAM;EACN,mBAAmB,aAAa;AAC9B,UAAO,YAAY,SAAS,wBAAwB;;EAEtD,SAAS;EACT,eAAe,UAAU,QAAQ;GAC/B,MAAM,cAAc,KAAK,YAAY;AAErC,OAAI,gBAAgB,wBAAwB,OAC1C,OAAM,IAAI,MACR,oDAAoD,cACrD;AAGH,QAAK,oBAAoB,eAAe,yBAAyB,OAAO;;EAE3E"}
|
|
@@ -1,40 +1,27 @@
|
|
|
1
1
|
import { START_ENVIRONMENT_NAMES } from "../constants.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createVirtualModule } from "./createVirtualModule.js";
|
|
3
3
|
import { EMPTY_SERIALIZATION_ADAPTERS_MODULE, generateSerializationAdaptersModule } from "../serialization-adapters-module.js";
|
|
4
4
|
import { VIRTUAL_MODULES } from "@tanstack/start-server-core";
|
|
5
5
|
//#region src/vite/serialization-adapters-plugin.ts
|
|
6
|
-
var resolvedModuleId = resolveViteId(VIRTUAL_MODULES.pluginAdapters.replace("#", "%23"));
|
|
7
|
-
function escapeRegex(str) {
|
|
8
|
-
return str.replace(/[.*+?^${}()|[\]\\#]/g, "\\$&");
|
|
9
|
-
}
|
|
10
6
|
function serializationAdaptersPlugin(opts) {
|
|
11
|
-
return {
|
|
7
|
+
return createVirtualModule({
|
|
12
8
|
name: "tanstack-start:plugin-adapters",
|
|
9
|
+
moduleId: VIRTUAL_MODULES.pluginAdapters,
|
|
13
10
|
enforce: "pre",
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (this.environment.name === START_ENVIRONMENT_NAMES.client) return generateSerializationAdaptersModule({
|
|
27
|
-
adapters,
|
|
28
|
-
runtime: "client"
|
|
29
|
-
});
|
|
30
|
-
if (this.environment.name === START_ENVIRONMENT_NAMES.server) return generateSerializationAdaptersModule({
|
|
31
|
-
adapters,
|
|
32
|
-
runtime: "server"
|
|
33
|
-
});
|
|
34
|
-
return EMPTY_SERIALIZATION_ADAPTERS_MODULE;
|
|
35
|
-
}
|
|
11
|
+
load() {
|
|
12
|
+
const adapters = opts.adapters;
|
|
13
|
+
if (!adapters || adapters.length === 0) return EMPTY_SERIALIZATION_ADAPTERS_MODULE;
|
|
14
|
+
if (this.environment.name === START_ENVIRONMENT_NAMES.client) return generateSerializationAdaptersModule({
|
|
15
|
+
adapters,
|
|
16
|
+
runtime: "client"
|
|
17
|
+
});
|
|
18
|
+
if (this.environment.name === START_ENVIRONMENT_NAMES.server) return generateSerializationAdaptersModule({
|
|
19
|
+
adapters,
|
|
20
|
+
runtime: "server"
|
|
21
|
+
});
|
|
22
|
+
return EMPTY_SERIALIZATION_ADAPTERS_MODULE;
|
|
36
23
|
}
|
|
37
|
-
};
|
|
24
|
+
});
|
|
38
25
|
}
|
|
39
26
|
//#endregion
|
|
40
27
|
export { serializationAdaptersPlugin };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialization-adapters-plugin.js","names":[],"sources":["../../../src/vite/serialization-adapters-plugin.ts"],"sourcesContent":["import { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport {\n EMPTY_SERIALIZATION_ADAPTERS_MODULE,\n generateSerializationAdaptersModule,\n} from '../serialization-adapters-module'\nimport { START_ENVIRONMENT_NAMES } from '../constants'\nimport {
|
|
1
|
+
{"version":3,"file":"serialization-adapters-plugin.js","names":[],"sources":["../../../src/vite/serialization-adapters-plugin.ts"],"sourcesContent":["import { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport {\n EMPTY_SERIALIZATION_ADAPTERS_MODULE,\n generateSerializationAdaptersModule,\n} from '../serialization-adapters-module'\nimport { START_ENVIRONMENT_NAMES } from '../constants'\nimport { createVirtualModule } from './createVirtualModule'\nimport type { SerializationAdapterConfig } from '../types'\nimport type { PluginOption } from 'vite'\n\nexport function serializationAdaptersPlugin(opts: {\n adapters: Array<SerializationAdapterConfig> | undefined\n}): PluginOption {\n return createVirtualModule({\n name: 'tanstack-start:plugin-adapters',\n moduleId: VIRTUAL_MODULES.pluginAdapters,\n enforce: 'pre',\n load() {\n const adapters = opts.adapters\n if (!adapters || adapters.length === 0) {\n return EMPTY_SERIALIZATION_ADAPTERS_MODULE\n }\n\n if (this.environment.name === START_ENVIRONMENT_NAMES.client) {\n return generateSerializationAdaptersModule({\n adapters,\n runtime: 'client',\n })\n }\n\n if (this.environment.name === START_ENVIRONMENT_NAMES.server) {\n return generateSerializationAdaptersModule({\n adapters,\n runtime: 'server',\n })\n }\n\n return EMPTY_SERIALIZATION_ADAPTERS_MODULE\n },\n })\n}\n"],"mappings":";;;;;AAUA,SAAgB,4BAA4B,MAE3B;AACf,QAAO,oBAAoB;EACzB,MAAM;EACN,UAAU,gBAAgB;EAC1B,SAAS;EACT,OAAO;GACL,MAAM,WAAW,KAAK;AACtB,OAAI,CAAC,YAAY,SAAS,WAAW,EACnC,QAAO;AAGT,OAAI,KAAK,YAAY,SAAS,wBAAwB,OACpD,QAAO,oCAAoC;IACzC;IACA,SAAS;IACV,CAAC;AAGJ,OAAI,KAAK,YAAY,SAAS,wBAAwB,OACpD,QAAO,oCAAoC;IACzC;IACA,SAAS;IACV,CAAC;AAGJ,UAAO;;EAEV,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { SERVER_FN_LOOKUP, TRANSFORM_ID_REGEX, VITE_ENVIRONMENT_NAMES } from "../../constants.js";
|
|
2
|
+
import { resolveViteId } from "../../utils.js";
|
|
3
|
+
import { createVirtualModule } from "../createVirtualModule.js";
|
|
2
4
|
import { cleanId } from "../../start-compiler/utils.js";
|
|
3
5
|
import { detectKindsInCode } from "../../start-compiler/compiler.js";
|
|
4
6
|
import { getTransformCodeFilterForEnv } from "../../start-compiler/config.js";
|
|
@@ -10,9 +12,6 @@ import { resolve } from "pathe";
|
|
|
10
12
|
import assert from "node:assert";
|
|
11
13
|
import { VIRTUAL_MODULES } from "@tanstack/start-server-core";
|
|
12
14
|
//#region src/vite/start-compiler-plugin/plugin.ts
|
|
13
|
-
function resolveViteId(id) {
|
|
14
|
-
return `\0${id}`;
|
|
15
|
-
}
|
|
16
15
|
var validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`;
|
|
17
16
|
function getDevServerFnValidatorModule() {
|
|
18
17
|
return `
|
|
@@ -44,7 +43,6 @@ function startCompilerPlugin(opts) {
|
|
|
44
43
|
mergeServerFnsById(serverFnsById, d);
|
|
45
44
|
};
|
|
46
45
|
let root = process.cwd();
|
|
47
|
-
const resolvedResolverVirtualImportId = resolveViteId(VIRTUAL_MODULES.serverFnResolver);
|
|
48
46
|
const ssrEnvName = VITE_ENVIRONMENT_NAMES.server;
|
|
49
47
|
const ssrIsProvider = opts.providerEnvName === ssrEnvName;
|
|
50
48
|
const appliedResolverEnvironments = new Set(ssrIsProvider ? [opts.providerEnvName] : [ssrEnvName, opts.providerEnvName]);
|
|
@@ -163,37 +161,26 @@ function startCompilerPlugin(opts) {
|
|
|
163
161
|
}
|
|
164
162
|
}
|
|
165
163
|
},
|
|
166
|
-
{
|
|
164
|
+
createVirtualModule({
|
|
167
165
|
name: "tanstack-start-core:server-fn-resolver",
|
|
166
|
+
moduleId: VIRTUAL_MODULES.serverFnResolver,
|
|
168
167
|
enforce: "pre",
|
|
169
168
|
applyToEnvironment: (env) => {
|
|
170
169
|
return appliedResolverEnvironments.has(env.name);
|
|
171
170
|
},
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
handler() {
|
|
178
|
-
return resolvedResolverVirtualImportId;
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
load: {
|
|
182
|
-
filter: { id: new RegExp(resolvedResolverVirtualImportId) },
|
|
183
|
-
handler() {
|
|
184
|
-
if (this.environment.name !== opts.providerEnvName) {
|
|
185
|
-
const mod = opts.environments.find((e) => e.name === this.environment.name)?.getServerFnById;
|
|
186
|
-
if (mod) return mod;
|
|
187
|
-
else this.error(`No getServerFnById implementation found for caller environment: ${this.environment.name}`);
|
|
188
|
-
}
|
|
189
|
-
if (this.environment.mode !== "build") return getDevServerFnValidatorModule();
|
|
190
|
-
return generateServerFnResolverModule({
|
|
191
|
-
serverFnsById,
|
|
192
|
-
includeClientReferencedCheck: !ssrIsProvider
|
|
193
|
-
});
|
|
171
|
+
load() {
|
|
172
|
+
if (this.environment.name !== opts.providerEnvName) {
|
|
173
|
+
const mod = opts.environments.find((e) => e.name === this.environment.name)?.getServerFnById;
|
|
174
|
+
if (mod) return mod;
|
|
175
|
+
this.error(`No getServerFnById implementation found for caller environment: ${this.environment.name}`);
|
|
194
176
|
}
|
|
177
|
+
if (this.environment.mode !== "build") return getDevServerFnValidatorModule();
|
|
178
|
+
return generateServerFnResolverModule({
|
|
179
|
+
serverFnsById,
|
|
180
|
+
includeClientReferencedCheck: !ssrIsProvider
|
|
181
|
+
});
|
|
195
182
|
}
|
|
196
|
-
}
|
|
183
|
+
})
|
|
197
184
|
];
|
|
198
185
|
}
|
|
199
186
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../src/vite/start-compiler-plugin/plugin.ts"],"sourcesContent":["import assert from 'node:assert'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { resolve as resolvePath } from 'pathe'\nimport {\n SERVER_FN_LOOKUP,\n TRANSFORM_ID_REGEX,\n VITE_ENVIRONMENT_NAMES,\n} from '../../constants'\nimport { detectKindsInCode } from '../../start-compiler/compiler'\nimport { getTransformCodeFilterForEnv } from '../../start-compiler/config'\nimport {\n createStartCompiler,\n mergeServerFnsById,\n} from '../../start-compiler/host'\nimport { loadModuleForViteCompiler } from '../../start-compiler/load-module'\nimport { generateServerFnResolverModule } from '../../start-compiler/server-fn-resolver-module'\nimport { cleanId } from '../../start-compiler/utils'\nimport {\n createViteDevServerFnModuleSpecifierEncoder,\n decodeViteDevServerModuleSpecifier,\n} from './module-specifier'\nimport type { CompileStartFrameworkOptions } from '../../types'\nimport type {\n GenerateFunctionIdFnOptional,\n ServerFn,\n} from '../../start-compiler/types'\nimport type { PluginOption } from 'vite'\n\n// Re-export from shared constants for backwards compatibility\nexport { SERVER_FN_LOOKUP }\n\nfunction resolveViteId(id: string) {\n return `\\0${id}`\n}\n\nconst validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`\n\nfunction getDevServerFnValidatorModule(): string {\n return `\nexport async function getServerFnById(id, _access) {\n const validateIdImport = ${JSON.stringify(validateServerFnIdVirtualModule)} + '?id=' + id\n await import(/* @vite-ignore */ '/@id/__x00__' + validateIdImport)\n const decoded = Buffer.from(id, 'base64url').toString('utf8')\n const devServerFn = JSON.parse(decoded)\n const mod = await import(/* @vite-ignore */ devServerFn.file)\n return mod[devServerFn.export]\n}\n`\n}\n\nfunction parseIdQuery(id: string): {\n filename: string\n query: {\n [k: string]: string\n }\n} {\n if (!id.includes('?')) return { filename: id, query: {} }\n const [filename, rawQuery] = id.split(`?`, 2) as [string, string]\n const query = Object.fromEntries(new URLSearchParams(rawQuery))\n return { filename, query }\n}\n\nexport interface StartCompilerPluginOptions {\n framework: CompileStartFrameworkOptions\n environments: Array<{\n name: string\n type: 'client' | 'server'\n getServerFnById?: string\n }>\n /**\n * Custom function ID generator (optional).\n */\n generateFunctionId?: GenerateFunctionIdFnOptional\n /**\n * The Vite environment name for the server function provider.\n */\n providerEnvName: string\n}\n\nexport function startCompilerPlugin(\n opts: StartCompilerPluginOptions,\n): PluginOption {\n const compilers = new Map<string, ReturnType<typeof createStartCompiler>>()\n\n // Shared registry of server functions across all environments\n const serverFnsById: Record<string, ServerFn> = {}\n\n const onServerFnsById = (d: Record<string, ServerFn>) => {\n mergeServerFnsById(serverFnsById, d)\n }\n\n let root = process.cwd()\n const resolvedResolverVirtualImportId = resolveViteId(\n VIRTUAL_MODULES.serverFnResolver,\n )\n\n // Determine which environments need the resolver (getServerFnById)\n // SSR environment always needs the resolver for server-side calls\n // Provider environment needs it for the actual implementation\n const ssrEnvName = VITE_ENVIRONMENT_NAMES.server\n\n // SSR is the provider when the provider environment is the default server environment\n const ssrIsProvider = opts.providerEnvName === ssrEnvName\n\n // Environments that need the resolver: SSR (for server calls) and provider (for implementation)\n const appliedResolverEnvironments = new Set(\n ssrIsProvider ? [opts.providerEnvName] : [ssrEnvName, opts.providerEnvName],\n )\n\n function perEnvServerFnPlugin(environment: {\n name: string\n type: 'client' | 'server'\n }): PluginOption {\n // Derive transform code filter from KindDetectionPatterns (single source of truth)\n const transformCodeFilter = getTransformCodeFilterForEnv(environment.type)\n return {\n name: `tanstack-start-core::server-fn:${environment.name}`,\n enforce: 'pre',\n applyToEnvironment(env) {\n return env.name === environment.name\n },\n configResolved(config) {\n root = config.root\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n include: TRANSFORM_ID_REGEX,\n },\n code: {\n include: transformCodeFilter,\n },\n },\n async handler(code, id) {\n let compiler = compilers.get(this.environment.name)\n\n if (!compiler) {\n // Default to 'dev' mode for unknown environments (conservative: no caching)\n const mode = this.environment.mode === 'build' ? 'build' : 'dev'\n\n compiler = createStartCompiler({\n env: environment.type,\n envName: environment.name,\n root,\n mode,\n framework: opts.framework,\n providerEnvName: opts.providerEnvName,\n generateFunctionId: opts.generateFunctionId,\n onServerFnsById,\n getKnownServerFns: () => serverFnsById,\n encodeModuleSpecifierInDev:\n mode === 'dev'\n ? createViteDevServerFnModuleSpecifierEncoder(root)\n : undefined,\n loadModule: async (id: string) => {\n await loadModuleForViteCompiler({\n compiler: compiler!,\n mode: this.environment.mode,\n fetchModule:\n this.environment.mode === 'dev'\n ? this.environment.fetchModule.bind(this.environment)\n : undefined,\n loadModule: this.load.bind(this),\n id,\n })\n },\n\n resolveId: async (source: string, importer?: string) => {\n const r = await this.resolve(source, importer)\n\n if (r) {\n if (!r.external) {\n return cleanId(r.id)\n }\n }\n\n return null\n },\n })\n\n compilers.set(this.environment.name, compiler)\n }\n\n // Detect which kinds are present in this file before parsing\n const detectedKinds = detectKindsInCode(code, environment.type)\n\n const result = await compiler.compile({\n id,\n code,\n detectedKinds,\n })\n return result\n },\n },\n\n hotUpdate(ctx) {\n const compiler = compilers.get(this.environment.name)\n\n ctx.modules.forEach((m) => {\n if (m.id) {\n const deleted = compiler?.invalidateModule(m.id)\n if (deleted) {\n m.importers.forEach((importer) => {\n if (importer.id) {\n compiler?.invalidateModule(importer.id)\n }\n })\n }\n }\n })\n },\n }\n }\n\n return [\n ...opts.environments.map(perEnvServerFnPlugin),\n {\n name: 'tanstack-start-core:capture-server-fn-module-lookup',\n // we only need this plugin in dev mode\n apply: 'serve',\n applyToEnvironment(env) {\n return !!opts.environments.find((e) => e.name === env.name)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler = compilers.get(this.environment.name)\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n // Validate server function ID in dev mode\n {\n name: 'tanstack-start-core:validate-server-fn-id',\n apply: 'serve',\n load: {\n filter: {\n id: new RegExp(resolveViteId(validateServerFnIdVirtualModule)),\n },\n async handler(id) {\n const parsed = parseIdQuery(id)\n const fnId = parsed.query.id\n if (fnId && serverFnsById[fnId]) {\n return `export {}`\n }\n\n // ID not yet registered — the source file may not have been\n // transformed in this dev session yet (e.g. cold restart with\n // cached client). Try to decode the ID, discover the source\n // file, trigger its compilation, and re-check.\n if (fnId) {\n try {\n const decoded = JSON.parse(\n Buffer.from(fnId, 'base64url').toString('utf8'),\n )\n if (\n typeof decoded.file === 'string' &&\n typeof decoded.export === 'string'\n ) {\n // Use the Vite strategy to decode the module specifier\n // back to the original source file path.\n const sourceFile = decodeViteDevServerModuleSpecifier(\n decoded.file,\n )\n\n if (sourceFile) {\n // Resolve to absolute path\n const absPath = resolvePath(root, sourceFile)\n\n // Trigger transform of the source file in this environment,\n // which will compile createServerFn calls and populate\n // serverFnsById as a side effect.\n // This plugin only runs in dev (apply: 'serve'), so mode\n // must be 'dev' — assert to narrow to DevEnvironment.\n assert(this.environment.mode === 'dev')\n await this.environment.fetchModule(absPath)\n\n // Re-check after lazy compilation\n if (serverFnsById[fnId]) {\n return `export {}`\n }\n }\n }\n } catch {\n // Decoding or fetching failed — fall through to error\n }\n }\n\n this.error(`Invalid server function ID: ${fnId}`)\n },\n },\n },\n // Manifest plugin for server environments\n {\n name: 'tanstack-start-core:server-fn-resolver',\n enforce: 'pre',\n applyToEnvironment: (env) => {\n return appliedResolverEnvironments.has(env.name)\n },\n configResolved(config) {\n root = config.root\n },\n resolveId: {\n filter: { id: new RegExp(VIRTUAL_MODULES.serverFnResolver) },\n handler() {\n return resolvedResolverVirtualImportId\n },\n },\n load: {\n filter: { id: new RegExp(resolvedResolverVirtualImportId) },\n handler() {\n if (this.environment.name !== opts.providerEnvName) {\n const mod = opts.environments.find(\n (e) => e.name === this.environment.name,\n )?.getServerFnById\n if (mod) {\n return mod\n } else {\n this.error(\n `No getServerFnById implementation found for caller environment: ${this.environment.name}`,\n )\n }\n }\n\n if (this.environment.mode !== 'build') {\n return getDevServerFnValidatorModule()\n }\n\n // When SSR is the provider, server-only-referenced functions aren't in the manifest,\n // so no isClientReferenced check is needed.\n // When SSR is NOT the provider (custom provider env), server-only-referenced\n // functions ARE in the manifest and need the isClientReferenced check to\n // block direct client HTTP requests to server-only-referenced functions.\n return generateServerFnResolverModule({\n serverFnsById,\n includeClientReferencedCheck: !ssrIsProvider,\n })\n },\n },\n },\n ]\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../src/vite/start-compiler-plugin/plugin.ts"],"sourcesContent":["import assert from 'node:assert'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { resolve as resolvePath } from 'pathe'\nimport {\n SERVER_FN_LOOKUP,\n TRANSFORM_ID_REGEX,\n VITE_ENVIRONMENT_NAMES,\n} from '../../constants'\nimport { detectKindsInCode } from '../../start-compiler/compiler'\nimport { getTransformCodeFilterForEnv } from '../../start-compiler/config'\nimport {\n createStartCompiler,\n mergeServerFnsById,\n} from '../../start-compiler/host'\nimport { loadModuleForViteCompiler } from '../../start-compiler/load-module'\nimport { generateServerFnResolverModule } from '../../start-compiler/server-fn-resolver-module'\nimport { cleanId } from '../../start-compiler/utils'\nimport { createVirtualModule } from '../createVirtualModule'\nimport { resolveViteId } from '../../utils'\nimport {\n createViteDevServerFnModuleSpecifierEncoder,\n decodeViteDevServerModuleSpecifier,\n} from './module-specifier'\nimport type { CompileStartFrameworkOptions } from '../../types'\nimport type {\n GenerateFunctionIdFnOptional,\n ServerFn,\n} from '../../start-compiler/types'\nimport type { PluginOption } from 'vite'\n\n// Re-export from shared constants for backwards compatibility\nexport { SERVER_FN_LOOKUP }\n\nconst validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`\n\nfunction getDevServerFnValidatorModule(): string {\n return `\nexport async function getServerFnById(id, _access) {\n const validateIdImport = ${JSON.stringify(validateServerFnIdVirtualModule)} + '?id=' + id\n await import(/* @vite-ignore */ '/@id/__x00__' + validateIdImport)\n const decoded = Buffer.from(id, 'base64url').toString('utf8')\n const devServerFn = JSON.parse(decoded)\n const mod = await import(/* @vite-ignore */ devServerFn.file)\n return mod[devServerFn.export]\n}\n`\n}\n\nfunction parseIdQuery(id: string): {\n filename: string\n query: {\n [k: string]: string\n }\n} {\n if (!id.includes('?')) return { filename: id, query: {} }\n const [filename, rawQuery] = id.split(`?`, 2) as [string, string]\n const query = Object.fromEntries(new URLSearchParams(rawQuery))\n return { filename, query }\n}\n\nexport interface StartCompilerPluginOptions {\n framework: CompileStartFrameworkOptions\n environments: Array<{\n name: string\n type: 'client' | 'server'\n getServerFnById?: string\n }>\n /**\n * Custom function ID generator (optional).\n */\n generateFunctionId?: GenerateFunctionIdFnOptional\n /**\n * The Vite environment name for the server function provider.\n */\n providerEnvName: string\n}\n\nexport function startCompilerPlugin(\n opts: StartCompilerPluginOptions,\n): PluginOption {\n const compilers = new Map<string, ReturnType<typeof createStartCompiler>>()\n\n // Shared registry of server functions across all environments\n const serverFnsById: Record<string, ServerFn> = {}\n\n const onServerFnsById = (d: Record<string, ServerFn>) => {\n mergeServerFnsById(serverFnsById, d)\n }\n\n let root = process.cwd()\n // Determine which environments need the resolver (getServerFnById)\n // SSR environment always needs the resolver for server-side calls\n // Provider environment needs it for the actual implementation\n const ssrEnvName = VITE_ENVIRONMENT_NAMES.server\n\n // SSR is the provider when the provider environment is the default server environment\n const ssrIsProvider = opts.providerEnvName === ssrEnvName\n\n // Environments that need the resolver: SSR (for server calls) and provider (for implementation)\n const appliedResolverEnvironments = new Set(\n ssrIsProvider ? [opts.providerEnvName] : [ssrEnvName, opts.providerEnvName],\n )\n\n function perEnvServerFnPlugin(environment: {\n name: string\n type: 'client' | 'server'\n }): PluginOption {\n // Derive transform code filter from KindDetectionPatterns (single source of truth)\n const transformCodeFilter = getTransformCodeFilterForEnv(environment.type)\n return {\n name: `tanstack-start-core::server-fn:${environment.name}`,\n enforce: 'pre',\n applyToEnvironment(env) {\n return env.name === environment.name\n },\n configResolved(config) {\n root = config.root\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n include: TRANSFORM_ID_REGEX,\n },\n code: {\n include: transformCodeFilter,\n },\n },\n async handler(code, id) {\n let compiler = compilers.get(this.environment.name)\n\n if (!compiler) {\n // Default to 'dev' mode for unknown environments (conservative: no caching)\n const mode = this.environment.mode === 'build' ? 'build' : 'dev'\n\n compiler = createStartCompiler({\n env: environment.type,\n envName: environment.name,\n root,\n mode,\n framework: opts.framework,\n providerEnvName: opts.providerEnvName,\n generateFunctionId: opts.generateFunctionId,\n onServerFnsById,\n getKnownServerFns: () => serverFnsById,\n encodeModuleSpecifierInDev:\n mode === 'dev'\n ? createViteDevServerFnModuleSpecifierEncoder(root)\n : undefined,\n loadModule: async (id: string) => {\n await loadModuleForViteCompiler({\n compiler: compiler!,\n mode: this.environment.mode,\n fetchModule:\n this.environment.mode === 'dev'\n ? this.environment.fetchModule.bind(this.environment)\n : undefined,\n loadModule: this.load.bind(this),\n id,\n })\n },\n\n resolveId: async (source: string, importer?: string) => {\n const r = await this.resolve(source, importer)\n\n if (r) {\n if (!r.external) {\n return cleanId(r.id)\n }\n }\n\n return null\n },\n })\n\n compilers.set(this.environment.name, compiler)\n }\n\n // Detect which kinds are present in this file before parsing\n const detectedKinds = detectKindsInCode(code, environment.type)\n\n const result = await compiler.compile({\n id,\n code,\n detectedKinds,\n })\n return result\n },\n },\n\n hotUpdate(ctx) {\n const compiler = compilers.get(this.environment.name)\n\n ctx.modules.forEach((m) => {\n if (m.id) {\n const deleted = compiler?.invalidateModule(m.id)\n if (deleted) {\n m.importers.forEach((importer) => {\n if (importer.id) {\n compiler?.invalidateModule(importer.id)\n }\n })\n }\n }\n })\n },\n }\n }\n\n return [\n ...opts.environments.map(perEnvServerFnPlugin),\n {\n name: 'tanstack-start-core:capture-server-fn-module-lookup',\n // we only need this plugin in dev mode\n apply: 'serve',\n applyToEnvironment(env) {\n return !!opts.environments.find((e) => e.name === env.name)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler = compilers.get(this.environment.name)\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n // Validate server function ID in dev mode\n {\n name: 'tanstack-start-core:validate-server-fn-id',\n apply: 'serve',\n load: {\n filter: {\n id: new RegExp(resolveViteId(validateServerFnIdVirtualModule)),\n },\n async handler(id) {\n const parsed = parseIdQuery(id)\n const fnId = parsed.query.id\n if (fnId && serverFnsById[fnId]) {\n return `export {}`\n }\n\n // ID not yet registered — the source file may not have been\n // transformed in this dev session yet (e.g. cold restart with\n // cached client). Try to decode the ID, discover the source\n // file, trigger its compilation, and re-check.\n if (fnId) {\n try {\n const decoded = JSON.parse(\n Buffer.from(fnId, 'base64url').toString('utf8'),\n )\n if (\n typeof decoded.file === 'string' &&\n typeof decoded.export === 'string'\n ) {\n // Use the Vite strategy to decode the module specifier\n // back to the original source file path.\n const sourceFile = decodeViteDevServerModuleSpecifier(\n decoded.file,\n )\n\n if (sourceFile) {\n // Resolve to absolute path\n const absPath = resolvePath(root, sourceFile)\n\n // Trigger transform of the source file in this environment,\n // which will compile createServerFn calls and populate\n // serverFnsById as a side effect.\n // This plugin only runs in dev (apply: 'serve'), so mode\n // must be 'dev' — assert to narrow to DevEnvironment.\n assert(this.environment.mode === 'dev')\n await this.environment.fetchModule(absPath)\n\n // Re-check after lazy compilation\n if (serverFnsById[fnId]) {\n return `export {}`\n }\n }\n }\n } catch {\n // Decoding or fetching failed — fall through to error\n }\n }\n\n this.error(`Invalid server function ID: ${fnId}`)\n },\n },\n },\n // Manifest plugin for server environments\n createVirtualModule({\n name: 'tanstack-start-core:server-fn-resolver',\n moduleId: VIRTUAL_MODULES.serverFnResolver,\n enforce: 'pre',\n applyToEnvironment: (env) => {\n return appliedResolverEnvironments.has(env.name)\n },\n load() {\n if (this.environment.name !== opts.providerEnvName) {\n const mod = opts.environments.find(\n (e) => e.name === this.environment.name,\n )?.getServerFnById\n if (mod) {\n return mod\n }\n\n this.error(\n `No getServerFnById implementation found for caller environment: ${this.environment.name}`,\n )\n }\n\n if (this.environment.mode !== 'build') {\n return getDevServerFnValidatorModule()\n }\n\n // When SSR is the provider, server-only-referenced functions aren't in the manifest,\n // so no isClientReferenced check is needed.\n // When SSR is NOT the provider (custom provider env), server-only-referenced\n // functions ARE in the manifest and need the isClientReferenced check to\n // block direct client HTTP requests to server-only-referenced functions.\n return generateServerFnResolverModule({\n serverFnsById,\n includeClientReferencedCheck: !ssrIsProvider,\n })\n },\n }),\n ]\n}\n"],"mappings":"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"}
|
|
@@ -1,45 +1,34 @@
|
|
|
1
1
|
import { ENTRY_POINTS, START_ENVIRONMENT_NAMES } from "../../constants.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createVirtualModule } from "../createVirtualModule.js";
|
|
3
3
|
import { buildStartManifest, serializeStartManifest } from "../../start-manifest-plugin/manifestBuilder.js";
|
|
4
4
|
import { VIRTUAL_MODULES } from "@tanstack/start-server-core";
|
|
5
5
|
import { joinURL } from "ufo";
|
|
6
6
|
//#region src/vite/start-manifest-plugin/plugin.ts
|
|
7
|
-
var resolvedModuleId = resolveViteId(VIRTUAL_MODULES.startManifest);
|
|
8
7
|
function startManifestPlugin(opts) {
|
|
9
|
-
return {
|
|
8
|
+
return createVirtualModule({
|
|
10
9
|
name: "tanstack-start:start-manifest-plugin",
|
|
10
|
+
moduleId: VIRTUAL_MODULES.startManifest,
|
|
11
11
|
enforce: "pre",
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
load: {
|
|
19
|
-
filter: { id: new RegExp(resolvedModuleId) },
|
|
20
|
-
handler(id) {
|
|
21
|
-
const { resolvedStartConfig } = opts.getConfig();
|
|
22
|
-
if (id === resolvedModuleId) {
|
|
23
|
-
if (this.environment.name !== START_ENVIRONMENT_NAMES.server) return "export default {}";
|
|
24
|
-
if (this.environment.config.command === "serve") return `export const tsrStartManifest = () => ({
|
|
12
|
+
load() {
|
|
13
|
+
const { resolvedStartConfig } = opts.getConfig();
|
|
14
|
+
if (this.environment.name !== START_ENVIRONMENT_NAMES.server) return "export default {}";
|
|
15
|
+
if (this.environment.config.command === "serve") return `export const tsrStartManifest = () => ({
|
|
25
16
|
routes: {},
|
|
26
17
|
clientEntry: '${joinURL(resolvedStartConfig.basePaths.publicBase, "@id", ENTRY_POINTS.client)}',
|
|
27
18
|
})`;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST;
|
|
20
|
+
const clientBuild = opts.getClientBuild();
|
|
21
|
+
if (!clientBuild) return `export const tsrStartManifest = () => ({
|
|
31
22
|
routes: {},
|
|
32
23
|
clientEntry: '${joinURL(resolvedStartConfig.basePaths.publicBase, "@id", ENTRY_POINTS.client)}',
|
|
33
24
|
})`;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
}
|
|
25
|
+
return `export const tsrStartManifest = () => (${serializeStartManifest(buildStartManifest({
|
|
26
|
+
clientBuild,
|
|
27
|
+
routeTreeRoutes,
|
|
28
|
+
basePath: resolvedStartConfig.basePaths.publicBase
|
|
29
|
+
}))})`;
|
|
41
30
|
}
|
|
42
|
-
};
|
|
31
|
+
});
|
|
43
32
|
}
|
|
44
33
|
//#endregion
|
|
45
34
|
export { startManifestPlugin };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../src/vite/start-manifest-plugin/plugin.ts"],"sourcesContent":["import { joinURL } from 'ufo'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport {
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../src/vite/start-manifest-plugin/plugin.ts"],"sourcesContent":["import { joinURL } from 'ufo'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { ENTRY_POINTS, START_ENVIRONMENT_NAMES } from '../../constants'\nimport {\n buildStartManifest,\n serializeStartManifest,\n} from '../../start-manifest-plugin/manifestBuilder'\nimport { createVirtualModule } from '../createVirtualModule'\nimport type { GetConfigFn, NormalizedClientBuild } from '../../types'\nimport type { PluginOption } from 'vite'\n\nexport function startManifestPlugin(opts: {\n getClientBuild: () => NormalizedClientBuild | undefined\n getConfig: GetConfigFn\n}): PluginOption {\n return createVirtualModule({\n name: 'tanstack-start:start-manifest-plugin',\n moduleId: VIRTUAL_MODULES.startManifest,\n enforce: 'pre',\n load() {\n const { resolvedStartConfig } = opts.getConfig()\n if (this.environment.name !== START_ENVIRONMENT_NAMES.server) {\n return 'export default {}'\n }\n\n if (this.environment.config.command === 'serve') {\n return `export const tsrStartManifest = () => ({\n routes: {},\n clientEntry: '${joinURL(resolvedStartConfig.basePaths.publicBase, '@id', ENTRY_POINTS.client)}',\n })`\n }\n\n const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST\n const clientBuild = opts.getClientBuild()\n // TODO this needs further discussion with vite-rsc, this is a temporary workaround\n // If the client bundle isn't available yet (e.g., during RSC scan builds),\n // return a dummy manifest. The real manifest will be generated in the actual build.\n if (!clientBuild) {\n return `export const tsrStartManifest = () => ({\n routes: {},\n clientEntry: '${joinURL(resolvedStartConfig.basePaths.publicBase, '@id', ENTRY_POINTS.client)}',\n })`\n }\n const startManifest = buildStartManifest({\n clientBuild,\n routeTreeRoutes,\n basePath: resolvedStartConfig.basePaths.publicBase,\n })\n\n return `export const tsrStartManifest = () => (${serializeStartManifest(startManifest)})`\n },\n })\n}\n"],"mappings":";;;;;;AAWA,SAAgB,oBAAoB,MAGnB;AACf,QAAO,oBAAoB;EACzB,MAAM;EACN,UAAU,gBAAgB;EAC1B,SAAS;EACT,OAAO;GACL,MAAM,EAAE,wBAAwB,KAAK,WAAW;AAChD,OAAI,KAAK,YAAY,SAAS,wBAAwB,OACpD,QAAO;AAGT,OAAI,KAAK,YAAY,OAAO,YAAY,QACtC,QAAO;;4BAEa,QAAQ,oBAAoB,UAAU,YAAY,OAAO,aAAa,OAAO,CAAC;;GAIpG,MAAM,kBAAkB,WAAW;GACnC,MAAM,cAAc,KAAK,gBAAgB;AAIzC,OAAI,CAAC,YACH,QAAO;;8BAEe,QAAQ,oBAAoB,UAAU,YAAY,OAAO,aAAa,OAAO,CAAC;;AAStG,UAAO,0CAA0C,uBAN3B,mBAAmB;IACvC;IACA;IACA,UAAU,oBAAoB,UAAU;IACzC,CAAC,CAEoF,CAAC;;EAE1F,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/start-plugin-core",
|
|
3
|
-
"version": "1.167.
|
|
3
|
+
"version": "1.167.34",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,11 +40,6 @@
|
|
|
40
40
|
"default": "./dist/esm/utils.js"
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
-
"./vite/types": {
|
|
44
|
-
"import": {
|
|
45
|
-
"types": "./dist/esm/vite/types.d.ts"
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
43
|
"./package.json": "./package.json"
|
|
49
44
|
},
|
|
50
45
|
"sideEffects": false,
|
|
@@ -72,12 +67,12 @@
|
|
|
72
67
|
"vitefu": "^1.1.1",
|
|
73
68
|
"xmlbuilder2": "^4.0.3",
|
|
74
69
|
"zod": "^3.24.2",
|
|
75
|
-
"@tanstack/router-core": "1.168.
|
|
76
|
-
"@tanstack/router-generator": "1.166.
|
|
77
|
-
"@tanstack/router-plugin": "1.167.
|
|
70
|
+
"@tanstack/router-core": "1.168.15",
|
|
71
|
+
"@tanstack/router-generator": "1.166.32",
|
|
72
|
+
"@tanstack/router-plugin": "1.167.22",
|
|
78
73
|
"@tanstack/router-utils": "1.161.6",
|
|
79
|
-
"@tanstack/start-client-core": "1.167.
|
|
80
|
-
"@tanstack/start-server-core": "1.167.
|
|
74
|
+
"@tanstack/start-client-core": "1.167.17",
|
|
75
|
+
"@tanstack/start-server-core": "1.167.19"
|
|
81
76
|
},
|
|
82
77
|
"devDependencies": {
|
|
83
78
|
"@types/babel__code-frame": "^7.0.6",
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export type { TanStackStartInputConfig } from './schema'
|
|
2
2
|
export type { TanStackStartCoreOptions } from './types'
|
|
3
|
-
export type {
|
|
3
|
+
export type {
|
|
4
|
+
TanStackStartVitePluginCoreOptions,
|
|
5
|
+
ViteRscForwardSsrResolverStrategy,
|
|
6
|
+
} from './vite/types'
|
|
4
7
|
export type { TanStackStartViteInputConfig } from './vite/schema'
|
|
5
8
|
export { START_ENVIRONMENT_NAMES, VITE_ENVIRONMENT_NAMES } from './constants'
|
|
9
|
+
export { createVirtualModule } from './vite/createVirtualModule'
|
|
6
10
|
export { tanStackStartVite } from './vite/plugin'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { resolveViteId } from '../utils'
|
|
2
|
+
import type { Plugin } from 'vite'
|
|
3
|
+
|
|
4
|
+
type VirtualModuleLoadHandler = (
|
|
5
|
+
this: any,
|
|
6
|
+
id: string,
|
|
7
|
+
) => string | null | undefined | Promise<string | null | undefined>
|
|
8
|
+
|
|
9
|
+
function escapeRegExp(value: string): string {
|
|
10
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createVirtualModule(opts: {
|
|
14
|
+
name: string
|
|
15
|
+
moduleId: string
|
|
16
|
+
load: VirtualModuleLoadHandler
|
|
17
|
+
apply?: Plugin['apply']
|
|
18
|
+
applyToEnvironment?: Plugin['applyToEnvironment']
|
|
19
|
+
enforce?: Plugin['enforce']
|
|
20
|
+
sharedDuringBuild?: boolean
|
|
21
|
+
}): Plugin {
|
|
22
|
+
// Encode '#' as '%23' in the resolved ID to avoid browser treating it as URL fragment.
|
|
23
|
+
// The browser requests /@id/__x00__%23tanstack-start-plugin-adapters instead of
|
|
24
|
+
// /@id/__x00__#tanstack-start-plugin-adapters (which would truncate at #).
|
|
25
|
+
const resolvedId = resolveViteId(opts.moduleId.replaceAll('#', '%23'))
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
name: opts.name,
|
|
29
|
+
apply: opts.apply,
|
|
30
|
+
applyToEnvironment: opts.applyToEnvironment,
|
|
31
|
+
enforce: opts.enforce,
|
|
32
|
+
sharedDuringBuild: opts.sharedDuringBuild,
|
|
33
|
+
resolveId: {
|
|
34
|
+
filter: { id: new RegExp(escapeRegExp(opts.moduleId)) },
|
|
35
|
+
handler(id) {
|
|
36
|
+
if (id === opts.moduleId) {
|
|
37
|
+
return resolvedId
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return undefined
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
load: {
|
|
44
|
+
filter: { id: new RegExp(escapeRegExp(resolvedId)) },
|
|
45
|
+
handler(id) {
|
|
46
|
+
if (id !== resolvedId) {
|
|
47
|
+
return undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return opts.load.call(this, id)
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -2,7 +2,7 @@ import { isRunnableDevEnvironment } from 'vite'
|
|
|
2
2
|
import { VIRTUAL_MODULES } from '@tanstack/start-server-core'
|
|
3
3
|
import { NodeRequest, sendNodeResponse } from 'srvx/node'
|
|
4
4
|
import { ENTRY_POINTS, VITE_ENVIRONMENT_NAMES } from '../../constants'
|
|
5
|
-
import {
|
|
5
|
+
import { createVirtualModule } from '../createVirtualModule'
|
|
6
6
|
import { extractHtmlScripts } from './extract-html-scripts'
|
|
7
7
|
import {
|
|
8
8
|
CSS_MODULES_REGEX,
|
|
@@ -248,27 +248,17 @@ export function devServerPlugin({
|
|
|
248
248
|
}
|
|
249
249
|
},
|
|
250
250
|
},
|
|
251
|
-
{
|
|
251
|
+
createVirtualModule({
|
|
252
252
|
name: 'tanstack-start-core:dev-server:injected-head-scripts',
|
|
253
253
|
sharedDuringBuild: true,
|
|
254
254
|
applyToEnvironment: (env) => env.config.consumer === 'server',
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return resolveViteId(VIRTUAL_MODULES.injectedHeadScripts)
|
|
259
|
-
},
|
|
260
|
-
},
|
|
261
|
-
load: {
|
|
262
|
-
filter: {
|
|
263
|
-
id: new RegExp(resolveViteId(VIRTUAL_MODULES.injectedHeadScripts)),
|
|
264
|
-
},
|
|
265
|
-
handler() {
|
|
266
|
-
const mod = `
|
|
255
|
+
moduleId: VIRTUAL_MODULES.injectedHeadScripts,
|
|
256
|
+
load() {
|
|
257
|
+
const mod = `
|
|
267
258
|
export const injectedHeadScripts = ${JSON.stringify(injectedHeadScripts) || 'undefined'}`
|
|
268
|
-
|
|
269
|
-
},
|
|
259
|
+
return mod
|
|
270
260
|
},
|
|
271
|
-
},
|
|
261
|
+
}),
|
|
272
262
|
]
|
|
273
263
|
}
|
|
274
264
|
|
package/src/vite/plugin.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
createCaptureClientBuildPlugin,
|
|
26
26
|
createDevBaseRewritePlugin,
|
|
27
27
|
createPostBuildPlugin,
|
|
28
|
+
createVirtualClientEntryPlugin,
|
|
28
29
|
} from './plugins'
|
|
29
30
|
import { parseStartConfig } from './schema'
|
|
30
31
|
import { startManifestPlugin } from './start-manifest-plugin/plugin'
|
|
@@ -237,6 +238,9 @@ export function tanStackStartVite(
|
|
|
237
238
|
}),
|
|
238
239
|
tanStackStartRouter(normalizedStartPluginOpts, getConfig, corePluginOpts),
|
|
239
240
|
loadEnvPlugin(),
|
|
241
|
+
createVirtualClientEntryPlugin({
|
|
242
|
+
getClientEntry: () => configContext.resolveEntries().entryPaths.client,
|
|
243
|
+
}),
|
|
240
244
|
startManifestPlugin({
|
|
241
245
|
getClientBuild: () => getClientBuild(START_ENVIRONMENT_NAMES.client),
|
|
242
246
|
getConfig,
|
package/src/vite/plugins.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizePath } from 'vite'
|
|
2
|
+
import { ENTRY_POINTS, START_ENVIRONMENT_NAMES } from '../constants'
|
|
3
|
+
import { createVirtualModule } from './createVirtualModule'
|
|
2
4
|
import { normalizeViteClientBuild } from './start-manifest-plugin/normalized-client-build'
|
|
3
5
|
import type {
|
|
4
6
|
GetConfigFn,
|
|
@@ -8,6 +10,19 @@ import type {
|
|
|
8
10
|
import type { StartEnvironmentName } from '../constants'
|
|
9
11
|
import type { PluginOption, ViteBuilder } from 'vite'
|
|
10
12
|
|
|
13
|
+
export function createVirtualClientEntryPlugin(opts: {
|
|
14
|
+
getClientEntry: () => string
|
|
15
|
+
}): PluginOption {
|
|
16
|
+
return createVirtualModule({
|
|
17
|
+
name: 'tanstack-start-core:virtual-client-entry',
|
|
18
|
+
moduleId: ENTRY_POINTS.client,
|
|
19
|
+
enforce: 'pre',
|
|
20
|
+
load() {
|
|
21
|
+
return `import ${JSON.stringify(normalizePath(opts.getClientEntry()).replaceAll('\\', '/'))}`
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
11
26
|
export function createPostBuildPlugin(opts: {
|
|
12
27
|
getConfig: GetConfigFn
|
|
13
28
|
postServerBuild: (opts: {
|
|
@@ -4,66 +4,38 @@ import {
|
|
|
4
4
|
generateSerializationAdaptersModule,
|
|
5
5
|
} from '../serialization-adapters-module'
|
|
6
6
|
import { START_ENVIRONMENT_NAMES } from '../constants'
|
|
7
|
-
import {
|
|
7
|
+
import { createVirtualModule } from './createVirtualModule'
|
|
8
8
|
import type { SerializationAdapterConfig } from '../types'
|
|
9
9
|
import type { PluginOption } from 'vite'
|
|
10
10
|
|
|
11
|
-
// Encode '#' as '%23' in the resolved ID to avoid browser treating it as URL fragment.
|
|
12
|
-
// The browser requests /@id/__x00__%23tanstack-start-plugin-adapters instead of
|
|
13
|
-
// /@id/__x00__#tanstack-start-plugin-adapters (which would truncate at #).
|
|
14
|
-
const resolvedModuleId = resolveViteId(
|
|
15
|
-
VIRTUAL_MODULES.pluginAdapters.replace('#', '%23'),
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
function escapeRegex(str: string): string {
|
|
19
|
-
return str.replace(/[.*+?^${}()|[\]\\#]/g, '\\$&')
|
|
20
|
-
}
|
|
21
|
-
|
|
22
11
|
export function serializationAdaptersPlugin(opts: {
|
|
23
12
|
adapters: Array<SerializationAdapterConfig> | undefined
|
|
24
13
|
}): PluginOption {
|
|
25
|
-
return {
|
|
14
|
+
return createVirtualModule({
|
|
26
15
|
name: 'tanstack-start:plugin-adapters',
|
|
16
|
+
moduleId: VIRTUAL_MODULES.pluginAdapters,
|
|
27
17
|
enforce: 'pre',
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
return undefined
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
load: {
|
|
38
|
-
filter: {
|
|
39
|
-
id: new RegExp(escapeRegex(resolvedModuleId)),
|
|
40
|
-
},
|
|
41
|
-
handler(this: { environment: { name: string } }, id: string) {
|
|
42
|
-
if (id !== resolvedModuleId) {
|
|
43
|
-
return undefined
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const adapters = opts.adapters
|
|
47
|
-
if (!adapters || adapters.length === 0) {
|
|
48
|
-
return EMPTY_SERIALIZATION_ADAPTERS_MODULE
|
|
49
|
-
}
|
|
18
|
+
load() {
|
|
19
|
+
const adapters = opts.adapters
|
|
20
|
+
if (!adapters || adapters.length === 0) {
|
|
21
|
+
return EMPTY_SERIALIZATION_ADAPTERS_MODULE
|
|
22
|
+
}
|
|
50
23
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
24
|
+
if (this.environment.name === START_ENVIRONMENT_NAMES.client) {
|
|
25
|
+
return generateSerializationAdaptersModule({
|
|
26
|
+
adapters,
|
|
27
|
+
runtime: 'client',
|
|
28
|
+
})
|
|
29
|
+
}
|
|
57
30
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
31
|
+
if (this.environment.name === START_ENVIRONMENT_NAMES.server) {
|
|
32
|
+
return generateSerializationAdaptersModule({
|
|
33
|
+
adapters,
|
|
34
|
+
runtime: 'server',
|
|
35
|
+
})
|
|
36
|
+
}
|
|
64
37
|
|
|
65
|
-
|
|
66
|
-
},
|
|
38
|
+
return EMPTY_SERIALIZATION_ADAPTERS_MODULE
|
|
67
39
|
},
|
|
68
|
-
}
|
|
40
|
+
})
|
|
69
41
|
}
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
import { loadModuleForViteCompiler } from '../../start-compiler/load-module'
|
|
16
16
|
import { generateServerFnResolverModule } from '../../start-compiler/server-fn-resolver-module'
|
|
17
17
|
import { cleanId } from '../../start-compiler/utils'
|
|
18
|
+
import { createVirtualModule } from '../createVirtualModule'
|
|
19
|
+
import { resolveViteId } from '../../utils'
|
|
18
20
|
import {
|
|
19
21
|
createViteDevServerFnModuleSpecifierEncoder,
|
|
20
22
|
decodeViteDevServerModuleSpecifier,
|
|
@@ -29,10 +31,6 @@ import type { PluginOption } from 'vite'
|
|
|
29
31
|
// Re-export from shared constants for backwards compatibility
|
|
30
32
|
export { SERVER_FN_LOOKUP }
|
|
31
33
|
|
|
32
|
-
function resolveViteId(id: string) {
|
|
33
|
-
return `\0${id}`
|
|
34
|
-
}
|
|
35
|
-
|
|
36
34
|
const validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`
|
|
37
35
|
|
|
38
36
|
function getDevServerFnValidatorModule(): string {
|
|
@@ -90,10 +88,6 @@ export function startCompilerPlugin(
|
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
let root = process.cwd()
|
|
93
|
-
const resolvedResolverVirtualImportId = resolveViteId(
|
|
94
|
-
VIRTUAL_MODULES.serverFnResolver,
|
|
95
|
-
)
|
|
96
|
-
|
|
97
91
|
// Determine which environments need the resolver (getServerFnById)
|
|
98
92
|
// SSR environment always needs the resolver for server-side calls
|
|
99
93
|
// Provider environment needs it for the actual implementation
|
|
@@ -294,52 +288,41 @@ export function startCompilerPlugin(
|
|
|
294
288
|
},
|
|
295
289
|
},
|
|
296
290
|
// Manifest plugin for server environments
|
|
297
|
-
{
|
|
291
|
+
createVirtualModule({
|
|
298
292
|
name: 'tanstack-start-core:server-fn-resolver',
|
|
293
|
+
moduleId: VIRTUAL_MODULES.serverFnResolver,
|
|
299
294
|
enforce: 'pre',
|
|
300
295
|
applyToEnvironment: (env) => {
|
|
301
296
|
return appliedResolverEnvironments.has(env.name)
|
|
302
297
|
},
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
load: {
|
|
313
|
-
filter: { id: new RegExp(resolvedResolverVirtualImportId) },
|
|
314
|
-
handler() {
|
|
315
|
-
if (this.environment.name !== opts.providerEnvName) {
|
|
316
|
-
const mod = opts.environments.find(
|
|
317
|
-
(e) => e.name === this.environment.name,
|
|
318
|
-
)?.getServerFnById
|
|
319
|
-
if (mod) {
|
|
320
|
-
return mod
|
|
321
|
-
} else {
|
|
322
|
-
this.error(
|
|
323
|
-
`No getServerFnById implementation found for caller environment: ${this.environment.name}`,
|
|
324
|
-
)
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (this.environment.mode !== 'build') {
|
|
329
|
-
return getDevServerFnValidatorModule()
|
|
298
|
+
load() {
|
|
299
|
+
if (this.environment.name !== opts.providerEnvName) {
|
|
300
|
+
const mod = opts.environments.find(
|
|
301
|
+
(e) => e.name === this.environment.name,
|
|
302
|
+
)?.getServerFnById
|
|
303
|
+
if (mod) {
|
|
304
|
+
return mod
|
|
330
305
|
}
|
|
331
306
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
307
|
+
this.error(
|
|
308
|
+
`No getServerFnById implementation found for caller environment: ${this.environment.name}`,
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (this.environment.mode !== 'build') {
|
|
313
|
+
return getDevServerFnValidatorModule()
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// When SSR is the provider, server-only-referenced functions aren't in the manifest,
|
|
317
|
+
// so no isClientReferenced check is needed.
|
|
318
|
+
// When SSR is NOT the provider (custom provider env), server-only-referenced
|
|
319
|
+
// functions ARE in the manifest and need the isClientReferenced check to
|
|
320
|
+
// block direct client HTTP requests to server-only-referenced functions.
|
|
321
|
+
return generateServerFnResolverModule({
|
|
322
|
+
serverFnsById,
|
|
323
|
+
includeClientReferencedCheck: !ssrIsProvider,
|
|
324
|
+
})
|
|
342
325
|
},
|
|
343
|
-
},
|
|
326
|
+
}),
|
|
344
327
|
]
|
|
345
328
|
}
|
|
@@ -1,72 +1,53 @@
|
|
|
1
1
|
import { joinURL } from 'ufo'
|
|
2
2
|
import { VIRTUAL_MODULES } from '@tanstack/start-server-core'
|
|
3
|
-
import { resolveViteId } from '../../utils'
|
|
4
3
|
import { ENTRY_POINTS, START_ENVIRONMENT_NAMES } from '../../constants'
|
|
5
4
|
import {
|
|
6
5
|
buildStartManifest,
|
|
7
6
|
serializeStartManifest,
|
|
8
7
|
} from '../../start-manifest-plugin/manifestBuilder'
|
|
8
|
+
import { createVirtualModule } from '../createVirtualModule'
|
|
9
9
|
import type { GetConfigFn, NormalizedClientBuild } from '../../types'
|
|
10
10
|
import type { PluginOption } from 'vite'
|
|
11
11
|
|
|
12
|
-
const resolvedModuleId = resolveViteId(VIRTUAL_MODULES.startManifest)
|
|
13
|
-
|
|
14
12
|
export function startManifestPlugin(opts: {
|
|
15
13
|
getClientBuild: () => NormalizedClientBuild | undefined
|
|
16
14
|
getConfig: GetConfigFn
|
|
17
15
|
}): PluginOption {
|
|
18
|
-
return {
|
|
16
|
+
return createVirtualModule({
|
|
19
17
|
name: 'tanstack-start:start-manifest-plugin',
|
|
18
|
+
moduleId: VIRTUAL_MODULES.startManifest,
|
|
20
19
|
enforce: 'pre',
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
return undefined
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
load: {
|
|
31
|
-
filter: {
|
|
32
|
-
id: new RegExp(resolvedModuleId),
|
|
33
|
-
},
|
|
34
|
-
handler(id) {
|
|
35
|
-
const { resolvedStartConfig } = opts.getConfig()
|
|
36
|
-
if (id === resolvedModuleId) {
|
|
37
|
-
if (this.environment.name !== START_ENVIRONMENT_NAMES.server) {
|
|
38
|
-
return 'export default {}'
|
|
39
|
-
}
|
|
20
|
+
load() {
|
|
21
|
+
const { resolvedStartConfig } = opts.getConfig()
|
|
22
|
+
if (this.environment.name !== START_ENVIRONMENT_NAMES.server) {
|
|
23
|
+
return 'export default {}'
|
|
24
|
+
}
|
|
40
25
|
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
if (this.environment.config.command === 'serve') {
|
|
27
|
+
return `export const tsrStartManifest = () => ({
|
|
43
28
|
routes: {},
|
|
44
29
|
clientEntry: '${joinURL(resolvedStartConfig.basePaths.publicBase, '@id', ENTRY_POINTS.client)}',
|
|
45
30
|
})`
|
|
46
|
-
|
|
31
|
+
}
|
|
47
32
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
33
|
+
const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST
|
|
34
|
+
const clientBuild = opts.getClientBuild()
|
|
35
|
+
// TODO this needs further discussion with vite-rsc, this is a temporary workaround
|
|
36
|
+
// If the client bundle isn't available yet (e.g., during RSC scan builds),
|
|
37
|
+
// return a dummy manifest. The real manifest will be generated in the actual build.
|
|
38
|
+
if (!clientBuild) {
|
|
39
|
+
return `export const tsrStartManifest = () => ({
|
|
55
40
|
routes: {},
|
|
56
41
|
clientEntry: '${joinURL(resolvedStartConfig.basePaths.publicBase, '@id', ENTRY_POINTS.client)}',
|
|
57
42
|
})`
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return `export const tsrStartManifest = () => (${serializeStartManifest(startManifest)})`
|
|
66
|
-
}
|
|
43
|
+
}
|
|
44
|
+
const startManifest = buildStartManifest({
|
|
45
|
+
clientBuild,
|
|
46
|
+
routeTreeRoutes,
|
|
47
|
+
basePath: resolvedStartConfig.basePaths.publicBase,
|
|
48
|
+
})
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
},
|
|
50
|
+
return `export const tsrStartManifest = () => (${serializeStartManifest(startManifest)})`
|
|
70
51
|
},
|
|
71
|
-
}
|
|
52
|
+
})
|
|
72
53
|
}
|