@octanejs/tanstack-start 0.1.28 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +19 -1
  2. package/THIRD_PARTY_NOTICES.md +6 -5
  3. package/package.json +18 -6
  4. package/src/client-only-server-strip-loader.js +7 -0
  5. package/src/client-only-server-strip.js +34 -25
  6. package/src/internal/README.md +7 -7
  7. package/src/internal/start-plugin-core/rsbuild/import-protection.d.ts +27 -0
  8. package/src/internal/start-plugin-core/rsbuild/import-protection.js +1193 -0
  9. package/src/internal/start-plugin-core/rsbuild/index.d.ts +9 -0
  10. package/src/internal/start-plugin-core/rsbuild/index.js +3 -0
  11. package/src/internal/start-plugin-core/rsbuild/normalized-client-build.d.ts +20 -0
  12. package/src/internal/start-plugin-core/rsbuild/normalized-client-build.js +261 -0
  13. package/src/internal/start-plugin-core/rsbuild/planning.d.ts +56 -0
  14. package/src/internal/start-plugin-core/rsbuild/planning.js +173 -0
  15. package/src/internal/start-plugin-core/rsbuild/plugin.d.ts +7 -0
  16. package/src/internal/start-plugin-core/rsbuild/plugin.js +504 -0
  17. package/src/internal/start-plugin-core/rsbuild/post-build.d.ts +10 -0
  18. package/src/internal/start-plugin-core/rsbuild/post-build.js +59 -0
  19. package/src/internal/start-plugin-core/rsbuild/schema.d.ts +2441 -0
  20. package/src/internal/start-plugin-core/rsbuild/schema.js +28 -0
  21. package/src/internal/start-plugin-core/rsbuild/server-middleware.d.ts +32 -0
  22. package/src/internal/start-plugin-core/rsbuild/server-middleware.js +139 -0
  23. package/src/internal/start-plugin-core/rsbuild/start-compiler-host.d.ts +36 -0
  24. package/src/internal/start-plugin-core/rsbuild/start-compiler-host.js +322 -0
  25. package/src/internal/start-plugin-core/rsbuild/start-compiler-metadata-loader.d.ts +10 -0
  26. package/src/internal/start-plugin-core/rsbuild/start-compiler-metadata-loader.js +12 -0
  27. package/src/internal/start-plugin-core/rsbuild/start-compiler-metadata.d.ts +14 -0
  28. package/src/internal/start-plugin-core/rsbuild/start-compiler-metadata.js +5 -0
  29. package/src/internal/start-plugin-core/rsbuild/start-router-plugin.d.ts +19 -0
  30. package/src/internal/start-plugin-core/rsbuild/start-router-plugin.js +69 -0
  31. package/src/internal/start-plugin-core/rsbuild/swc-rsc.d.ts +17 -0
  32. package/src/internal/start-plugin-core/rsbuild/swc-rsc.js +118 -0
  33. package/src/internal/start-plugin-core/rsbuild/types.d.ts +17 -0
  34. package/src/internal/start-plugin-core/rsbuild/types.js +0 -0
  35. package/src/internal/start-plugin-core/rsbuild/virtual-modules.d.ts +60 -0
  36. package/src/internal/start-plugin-core/rsbuild/virtual-modules.js +359 -0
  37. package/src/plugin-rsbuild.d.ts +25 -0
  38. package/src/plugin-rsbuild.js +79 -0
@@ -0,0 +1,28 @@
1
+ import {
2
+ parseStartConfig as parseStartConfig$1,
3
+ tanstackStartOptionsObjectSchema,
4
+ } from '../schema.js';
5
+ import { z } from 'zod';
6
+ //#region src/rsbuild/schema.ts
7
+ var rsbuildClientOutputSchema = z.enum(['module', 'iife']);
8
+ var tanstackStartRsbuildOptionsSchema = tanstackStartOptionsObjectSchema
9
+ .extend({
10
+ rsbuild: z
11
+ .object({
12
+ installDevServerMiddleware: z.boolean().optional(),
13
+ client: z
14
+ .object({ output: rsbuildClientOutputSchema.optional().default('module') })
15
+ .optional()
16
+ .prefault({}),
17
+ })
18
+ .optional(),
19
+ })
20
+ .optional()
21
+ .prefault({});
22
+ function parseStartConfig(opts, corePluginOpts, root) {
23
+ tanstackStartRsbuildOptionsSchema.parse(opts);
24
+ const { rsbuild: _rsbuild, ...coreOptions } = opts ?? {};
25
+ return parseStartConfig$1(coreOptions, corePluginOpts, root);
26
+ }
27
+ //#endregion
28
+ export { parseStartConfig, rsbuildClientOutputSchema };
@@ -0,0 +1,32 @@
1
+ import { RsbuildConfig } from '@rsbuild/core';
2
+ type ServerSetupFn = Extract<
3
+ NonNullable<NonNullable<RsbuildConfig['server']>['setup']>,
4
+ (...args: Array<any>) => any
5
+ >;
6
+ /**
7
+ * Returns a `server.setup` function for rsbuild v2.
8
+ *
9
+ * Two middleware positions are used:
10
+ *
11
+ * 1. **Setup body** (BEFORE built-ins): Intercepts `/_serverFn/` URLs so
12
+ * they never reach rsbuild's htmlFallback/htmlCompletion middleware,
13
+ * which can swallow long base64 function IDs.
14
+ *
15
+ * 2. **Returned callback** (AFTER built-ins, BEFORE fallback): Handles
16
+ * all remaining SSR requests (page navigations). This position lets
17
+ * rsbuild's asset middleware serve compiled JS/CSS first.
18
+ *
19
+ * The middleware choreography is shared by dev and preview. The server entry
20
+ * loader differs: dev reads from Rsbuild's in-memory environment so rebuilds
21
+ * are reflected immediately, while preview lazy-imports the production server
22
+ * bundle from disk.
23
+ *
24
+ * See rsbuild source: devMiddlewares.ts `applyDefaultMiddlewares()` and
25
+ * previewServer.ts `startPreviewServer()`.
26
+ */
27
+ export declare function createServerSetup(opts: {
28
+ serverFnBasePath: string;
29
+ serverOutputDirectory: string;
30
+ publicBase: string;
31
+ }): ServerSetupFn;
32
+ export {};
@@ -0,0 +1,139 @@
1
+ import { RSBUILD_ENVIRONMENT_NAMES } from './planning.js';
2
+ import { resolve } from 'node:path';
3
+ import { NodeRequest, sendNodeResponse } from 'srvx/node';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { joinURL } from 'ufo';
6
+ //#region src/rsbuild/server-middleware.ts
7
+ function resolveFetchHandler(serverEntry) {
8
+ if (typeof serverEntry === 'function') return serverEntry;
9
+ if (typeof serverEntry.fetch === 'function') return serverEntry.fetch.bind(serverEntry);
10
+ throw new Error('Unable to resolve a request handler from Rsbuild server bundle');
11
+ }
12
+ function getPublicBasePathname(publicBase) {
13
+ try {
14
+ return new URL(publicBase, 'http://localhost').pathname;
15
+ } catch {
16
+ return publicBase;
17
+ }
18
+ }
19
+ function restorePreviewUrl(opts) {
20
+ if (opts.req.originalUrl) opts.req.url = opts.req.originalUrl;
21
+ const publicBasePathname = getPublicBasePathname(opts.publicBase);
22
+ if (publicBasePathname === '/') return;
23
+ const url = opts.req.url ?? '/';
24
+ if (url.startsWith(publicBasePathname)) return;
25
+ opts.req.url = joinURL(publicBasePathname, url);
26
+ }
27
+ async function loadDevFetchHandler(context) {
28
+ if (context.action !== 'dev')
29
+ throw new Error('Cannot load Rsbuild dev SSR bundle outside dev mode');
30
+ const ssrEnv = context.server.environments[RSBUILD_ENVIRONMENT_NAMES.server];
31
+ if (!ssrEnv) throw new Error(`SSR environment "${RSBUILD_ENVIRONMENT_NAMES.server}" not found`);
32
+ return resolveFetchHandler((await ssrEnv.loadBundle('index')).default);
33
+ }
34
+ /**
35
+ * Returns a `server.setup` function for rsbuild v2.
36
+ *
37
+ * Two middleware positions are used:
38
+ *
39
+ * 1. **Setup body** (BEFORE built-ins): Intercepts `/_serverFn/` URLs so
40
+ * they never reach rsbuild's htmlFallback/htmlCompletion middleware,
41
+ * which can swallow long base64 function IDs.
42
+ *
43
+ * 2. **Returned callback** (AFTER built-ins, BEFORE fallback): Handles
44
+ * all remaining SSR requests (page navigations). This position lets
45
+ * rsbuild's asset middleware serve compiled JS/CSS first.
46
+ *
47
+ * The middleware choreography is shared by dev and preview. The server entry
48
+ * loader differs: dev reads from Rsbuild's in-memory environment so rebuilds
49
+ * are reflected immediately, while preview lazy-imports the production server
50
+ * bundle from disk.
51
+ *
52
+ * See rsbuild source: devMiddlewares.ts `applyDefaultMiddlewares()` and
53
+ * previewServer.ts `startPreviewServer()`.
54
+ */
55
+ function createServerSetup(opts) {
56
+ let previewFetchHandlerPromise;
57
+ const getPreviewFetchHandler = () => {
58
+ if (!previewFetchHandlerPromise)
59
+ previewFetchHandlerPromise = loadPreviewFetchHandler(opts.serverOutputDirectory);
60
+ return previewFetchHandlerPromise;
61
+ };
62
+ return (context) => {
63
+ const serverFnBase = opts.serverFnBasePath;
64
+ const handleSSR = async (req, res, next) => {
65
+ try {
66
+ const fetchHandler =
67
+ context.action === 'dev'
68
+ ? await loadDevFetchHandler(context)
69
+ : await getPreviewFetchHandler();
70
+ if (context.action === 'preview')
71
+ restorePreviewUrl({
72
+ req,
73
+ publicBase: opts.publicBase,
74
+ });
75
+ else if (req.originalUrl) req.url = req.originalUrl;
76
+ return sendNodeResponse(
77
+ res,
78
+ await fetchHandler(
79
+ new NodeRequest({
80
+ req,
81
+ res,
82
+ }),
83
+ ),
84
+ );
85
+ } catch (e) {
86
+ console.error('[tanstack-start] SSR error:', e);
87
+ if (
88
+ new NodeRequest({
89
+ req,
90
+ res,
91
+ }).headers
92
+ .get('content-type')
93
+ ?.includes('application/json')
94
+ )
95
+ return sendNodeResponse(
96
+ res,
97
+ new Response(
98
+ JSON.stringify(
99
+ {
100
+ status: 500,
101
+ error: 'Internal Server Error',
102
+ message: 'An unexpected error occurred. Please try again later.',
103
+ timestamp: /* @__PURE__ */ new Date().toISOString(),
104
+ },
105
+ null,
106
+ 2,
107
+ ),
108
+ {
109
+ status: 500,
110
+ headers: { 'Content-Type': 'application/json' },
111
+ },
112
+ ),
113
+ );
114
+ return next(e);
115
+ }
116
+ };
117
+ context.server.middlewares.use(async (req, res, next) => {
118
+ if ((req.url || '/').startsWith(serverFnBase)) return handleSSR(req, res, next);
119
+ return next();
120
+ });
121
+ return () => {
122
+ context.server.middlewares.use(handleSSR);
123
+ };
124
+ };
125
+ }
126
+ async function loadPreviewFetchHandler(serverOutputDirectory) {
127
+ const serverEntryPath = resolve(serverOutputDirectory, 'index.js');
128
+ const imported = await import(pathToFileURL(serverEntryPath).toString());
129
+ try {
130
+ return resolveFetchHandler(imported.default);
131
+ } catch (error) {
132
+ throw new Error(
133
+ `Unable to resolve a request handler from Rsbuild server bundle at ${serverEntryPath}`,
134
+ { cause: error },
135
+ );
136
+ }
137
+ }
138
+ //#endregion
139
+ export { createServerSetup };
@@ -0,0 +1,36 @@
1
+ import { RsbuildPluginAPI } from '@rsbuild/core';
2
+ import {
3
+ CompileStartFrameworkOptions,
4
+ StartCompilerImportTransform,
5
+ StartCompilerPlugin,
6
+ } from '../types.js';
7
+ import { GenerateFunctionIdFnOptional, ServerFn } from '../start-compiler/types.js';
8
+ type StartCompilerEnvironment = {
9
+ name: string;
10
+ type: 'client' | 'server';
11
+ };
12
+ export interface StartCompilerHostOptions {
13
+ framework: CompileStartFrameworkOptions;
14
+ root: string | (() => string);
15
+ environments: Array<StartCompilerEnvironment>;
16
+ providerEnvName: string;
17
+ generateFunctionId?: GenerateFunctionIdFnOptional;
18
+ compilerTransforms?: Array<StartCompilerImportTransform> | undefined;
19
+ compilerPlugins?: Array<StartCompilerPlugin> | undefined;
20
+ serverFnProviderModuleDirectives?: ReadonlyArray<string> | undefined;
21
+ serverFnsById?: Record<string, ServerFn>;
22
+ onServerFnsByIdChange?: () => void;
23
+ }
24
+ /**
25
+ * Registers the shared StartCompiler as rsbuild transforms for client + ssr environments.
26
+ *
27
+ * Uses `api.transform()` to hook into the rsbuild loader pipeline, and the
28
+ * transform context's native `resolve()` for module resolution.
29
+ */
30
+ export declare function registerStartCompilerTransforms(
31
+ api: RsbuildPluginAPI,
32
+ opts: StartCompilerHostOptions,
33
+ ): {
34
+ serverFnsById: Record<string, ServerFn>;
35
+ };
36
+ export {};
@@ -0,0 +1,322 @@
1
+ import { TRANSFORM_ID_REGEX } from '../constants.js';
2
+ import { cleanId } from '../start-compiler/utils.js';
3
+ import { detectKindsInCode } from '../start-compiler/compiler.js';
4
+ import { getTransformCodeFilterForEnv } from '../start-compiler/config.js';
5
+ import {
6
+ createStartCompiler,
7
+ loadCompilerVirtualModule,
8
+ matchesCodeFilters,
9
+ mergeServerFnsById,
10
+ } from '../start-compiler/host.js';
11
+ import { createHydrateCompilerPlugin } from '../hydrate-when-transform.js';
12
+ import {
13
+ SERVER_FN_BUILD_INFO_CONTEXT_KEY,
14
+ SERVER_FN_BUILD_INFO_FIELD,
15
+ } from './start-compiler-metadata.js';
16
+ import { dirname, resolve } from 'node:path';
17
+ import { fileURLToPath, pathToFileURL } from 'node:url';
18
+ import { z } from 'zod';
19
+ import { AsyncLocalStorage } from 'node:async_hooks';
20
+ //#region src/rsbuild/start-compiler-host.ts
21
+ var serverFnSchema = z.object({
22
+ functionName: z.string(),
23
+ functionId: z.string(),
24
+ extractedFilename: z.string(),
25
+ filename: z.string(),
26
+ isClientReferenced: z.boolean().optional(),
27
+ });
28
+ var serverFnBuildInfoSchema = z.object({
29
+ version: z.literal(1),
30
+ serverFnsById: z.record(z.string(), serverFnSchema),
31
+ });
32
+ /**
33
+ * In Rsbuild dev, use file:// URLs for absolute server function paths.
34
+ * These are directly importable by Node's ESM VM runner without any bundler
35
+ * path conventions (unlike Vite's /@id/ prefix).
36
+ */
37
+ var rsbuildDevServerFnModuleSpecifierEncoder = ({ extractedFilename }) =>
38
+ pathToFileURL(extractedFilename).href;
39
+ var currentDir = dirname(fileURLToPath(import.meta.url));
40
+ var metadataLoaderFilename = 'start-compiler-metadata-loader.js';
41
+ var EMPTY_SERVER_FN_BUILD_INFO = {
42
+ version: 1,
43
+ serverFnsById: {},
44
+ };
45
+ function resolveMetadataLoader() {
46
+ return resolve(currentDir, metadataLoaderFilename);
47
+ }
48
+ function readServerFnBuildInfo(module) {
49
+ const result = serverFnBuildInfoSchema.safeParse(module.buildInfo[SERVER_FN_BUILD_INFO_FIELD]);
50
+ if (!result.success) return null;
51
+ return result.data.serverFnsById;
52
+ }
53
+ function setServerFnBuildInfoLoaderContext(loaderContext, module) {
54
+ loaderContext[SERVER_FN_BUILD_INFO_CONTEXT_KEY] = (metadata) => {
55
+ if (metadata) module.buildInfo[SERVER_FN_BUILD_INFO_FIELD] = metadata;
56
+ else if (module.buildInfo['tanstack.start.serverFns'])
57
+ module.buildInfo[SERVER_FN_BUILD_INFO_FIELD] = EMPTY_SERVER_FN_BUILD_INFO;
58
+ };
59
+ }
60
+ function warnTransformContext(ctx, message) {
61
+ ctx.emitWarning?.(new Error(message));
62
+ }
63
+ /**
64
+ * Registers the shared StartCompiler as rsbuild transforms for client + ssr environments.
65
+ *
66
+ * Uses `api.transform()` to hook into the rsbuild loader pipeline, and the
67
+ * transform context's native `resolve()` for module resolution.
68
+ */
69
+ function registerStartCompilerTransforms(api, opts) {
70
+ const compilers = /* @__PURE__ */ new Map();
71
+ const compilerQueues = /* @__PURE__ */ new Map();
72
+ const inputFileSystems = /* @__PURE__ */ new Map();
73
+ const transformContextStorage = new AsyncLocalStorage();
74
+ const serverFnMetadataByEnvironment = /* @__PURE__ */ new Map();
75
+ const serverFnsByEnvironment = /* @__PURE__ */ new Map();
76
+ const serverFnsById = opts.serverFnsById ?? {};
77
+ const getRoot = () => (typeof opts.root === 'function' ? opts.root() : opts.root);
78
+ const getServerFnMetadata = (environmentName) => {
79
+ let metadataById = serverFnMetadataByEnvironment.get(environmentName);
80
+ if (!metadataById) {
81
+ metadataById = /* @__PURE__ */ new Map();
82
+ serverFnMetadataByEnvironment.set(environmentName, metadataById);
83
+ }
84
+ return metadataById;
85
+ };
86
+ const runCompilerTask = async (environmentName, task) => {
87
+ const next = (compilerQueues.get(environmentName) ?? Promise.resolve())
88
+ .catch(() => void 0)
89
+ .then(task);
90
+ compilerQueues.set(
91
+ environmentName,
92
+ next.then(
93
+ () => void 0,
94
+ () => void 0,
95
+ ),
96
+ );
97
+ return next;
98
+ };
99
+ const replaceServerFnsByIdFromEnvironmentSnapshots = () => {
100
+ const nextServerFnsById = {};
101
+ for (const snapshot of serverFnsByEnvironment.values())
102
+ mergeServerFnsById(nextServerFnsById, snapshot);
103
+ for (const key of Object.keys(serverFnsById)) delete serverFnsById[key];
104
+ Object.assign(serverFnsById, nextServerFnsById);
105
+ opts.onServerFnsByIdChange?.();
106
+ };
107
+ const compilerPlugins = [createHydrateCompilerPlugin(), ...(opts.compilerPlugins ?? [])];
108
+ const isDev = api.context.action === 'dev';
109
+ const mode = isDev ? 'dev' : 'build';
110
+ const metadataLoader = resolveMetadataLoader();
111
+ const environments = opts.environments;
112
+ api.modifyRspackConfig((config, utils) => {
113
+ if (!environments.some((env) => env.name === utils.environment.name)) return;
114
+ const rules = config.module.rules ?? [];
115
+ rules.push({
116
+ test: TRANSFORM_ID_REGEX[0],
117
+ enforce: 'post',
118
+ use: [
119
+ {
120
+ loader: metadataLoader,
121
+ options: { metadataById: getServerFnMetadata(utils.environment.name) },
122
+ },
123
+ ],
124
+ });
125
+ config.module.rules = rules;
126
+ });
127
+ for (const env of environments) {
128
+ const compilerTransforms = env.name === opts.providerEnvName ? opts.compilerTransforms : void 0;
129
+ const envCodeFilters = getTransformCodeFilterForEnv(env.type, {
130
+ compilerTransforms,
131
+ compilerPlugins,
132
+ });
133
+ const serverFnProviderModuleDirectives =
134
+ env.name === opts.providerEnvName ? opts.serverFnProviderModuleDirectives : void 0;
135
+ let activeServerFnMetadata;
136
+ const onServerFnsById = (d) => {
137
+ mergeServerFnsById(serverFnsById, d);
138
+ if (activeServerFnMetadata) mergeServerFnsById(activeServerFnMetadata, d);
139
+ opts.onServerFnsByIdChange?.();
140
+ };
141
+ api.transform(
142
+ {
143
+ test: TRANSFORM_ID_REGEX[0],
144
+ environments: [env.name],
145
+ order: 'pre',
146
+ },
147
+ async (ctx) => {
148
+ return transformContextStorage.run(ctx, async () => {
149
+ const code = ctx.code;
150
+ let nextCode = code;
151
+ let previousResult = null;
152
+ const id = ctx.resource;
153
+ const root = getRoot();
154
+ const virtualResult = loadCompilerVirtualModule(compilerPlugins, {
155
+ code,
156
+ id,
157
+ root,
158
+ env: env.type,
159
+ envName: env.name,
160
+ });
161
+ if (virtualResult) {
162
+ nextCode = virtualResult.code;
163
+ previousResult = {
164
+ code: virtualResult.code,
165
+ map: virtualResult.map ?? null,
166
+ };
167
+ }
168
+ if (!matchesCodeFilters(nextCode, envCodeFilters)) return previousResult ?? nextCode;
169
+ let compiler = compilers.get(env.name);
170
+ if (!compiler) {
171
+ compiler = createStartCompiler({
172
+ env: env.type,
173
+ envName: env.name,
174
+ root,
175
+ mode,
176
+ framework: opts.framework,
177
+ providerEnvName: opts.providerEnvName,
178
+ generateFunctionId: opts.generateFunctionId,
179
+ compilerTransforms,
180
+ compilerPlugins,
181
+ serverFnProviderModuleDirectives,
182
+ onServerFnsById,
183
+ getKnownServerFns: () => serverFnsById,
184
+ encodeModuleSpecifierInDev: isDev ? rsbuildDevServerFnModuleSpecifierEncoder : void 0,
185
+ loadModule: async (moduleId) => {
186
+ const activeCtx = transformContextStorage.getStore();
187
+ if (!activeCtx)
188
+ throw new Error(
189
+ `could not load module ${moduleId}: missing active rsbuild transform context for ${env.name}`,
190
+ );
191
+ const inputFileSystem = inputFileSystems.get(env.name);
192
+ if (!inputFileSystem)
193
+ throw new Error(
194
+ `could not load module ${moduleId}: missing rspack input filesystem for ${env.name}`,
195
+ );
196
+ const cleanedId = cleanId(moduleId);
197
+ activeCtx.addDependency(cleanedId);
198
+ const loaded = await readFileFromInputFileSystem(inputFileSystem, cleanedId);
199
+ const moduleCode = Buffer.isBuffer(loaded) ? loaded.toString('utf8') : loaded;
200
+ compiler.ingestModule({
201
+ code: moduleCode,
202
+ id: cleanedId,
203
+ });
204
+ },
205
+ resolveId: async (source, importer) => {
206
+ const activeCtx = transformContextStorage.getStore();
207
+ if (!activeCtx)
208
+ throw new Error(
209
+ `could not resolve ${source}: missing active rsbuild transform context for ${env.name}`,
210
+ );
211
+ const context = importer ? importer.replace(/[/\\][^/\\]*$/, '') : getRoot();
212
+ return await new Promise((resolve, reject) => {
213
+ activeCtx.resolve(context, source, (error, resolved) => {
214
+ if (error) {
215
+ reject(error);
216
+ return;
217
+ }
218
+ if (!resolved) {
219
+ resolve(null);
220
+ return;
221
+ }
222
+ resolve(cleanId(resolved));
223
+ });
224
+ });
225
+ },
226
+ });
227
+ compilers.set(env.name, compiler);
228
+ }
229
+ const detectedKinds = detectKindsInCode(nextCode, env.type, { compilerTransforms });
230
+ const discoveredServerFnsById = {};
231
+ const result = await runCompilerTask(env.name, async () => {
232
+ activeServerFnMetadata = discoveredServerFnsById;
233
+ try {
234
+ return await compiler.compile({
235
+ id,
236
+ code: nextCode,
237
+ detectedKinds,
238
+ warn: (message) => warnTransformContext(ctx, message),
239
+ });
240
+ } finally {
241
+ activeServerFnMetadata = void 0;
242
+ }
243
+ });
244
+ getServerFnMetadata(env.name).set(id, {
245
+ version: 1,
246
+ serverFnsById: discoveredServerFnsById,
247
+ });
248
+ if (result)
249
+ return {
250
+ code: result.code,
251
+ map: result.map ?? null,
252
+ };
253
+ return previousResult ?? nextCode;
254
+ });
255
+ },
256
+ );
257
+ }
258
+ api.modifyRspackConfig((config, utils) => {
259
+ if (!environments.some((env) => env.name === utils.environment.name)) return;
260
+ config.plugins.push({
261
+ apply(compiler) {
262
+ if (compiler.inputFileSystem)
263
+ inputFileSystems.set(utils.environment.name, compiler.inputFileSystem);
264
+ compiler.hooks.compilation.tap(
265
+ 'TanStackStartCompilerMetadataLoaderContext',
266
+ (compilation) => {
267
+ utils.rspack.NormalModule.getCompilationHooks(compilation).loader.tap(
268
+ 'TanStackStartCompilerMetadataLoaderContext',
269
+ (loaderContext, module) => {
270
+ setServerFnBuildInfoLoaderContext(loaderContext, module);
271
+ },
272
+ );
273
+ },
274
+ );
275
+ compiler.hooks.compile.tap('TanStackStartCompilerMetadataCleanup', () =>
276
+ getServerFnMetadata(utils.environment.name).clear(),
277
+ );
278
+ compiler.hooks.finishMake.tap(
279
+ {
280
+ name: 'TanStackStartCompilerCachedServerFnMetadata',
281
+ stage: -20,
282
+ },
283
+ (compilation) => {
284
+ const restoredServerFnsById = {};
285
+ for (const module of compilation.modules) {
286
+ const metadata = readServerFnBuildInfo(module);
287
+ if (!metadata) continue;
288
+ mergeServerFnsById(restoredServerFnsById, metadata);
289
+ }
290
+ serverFnsByEnvironment.set(utils.environment.name, restoredServerFnsById);
291
+ replaceServerFnsByIdFromEnvironmentSnapshots();
292
+ },
293
+ );
294
+ compiler.hooks.watchRun.tap('TanStackStartCompilerModuleInvalidation', (watchCompiler) => {
295
+ const startCompiler = compilers.get(utils.environment.name);
296
+ if (!startCompiler) return;
297
+ for (const file of watchCompiler.modifiedFiles ?? [])
298
+ startCompiler.invalidateModule(file);
299
+ for (const file of watchCompiler.removedFiles ?? []) startCompiler.invalidateModule(file);
300
+ });
301
+ },
302
+ });
303
+ });
304
+ return { serverFnsById };
305
+ }
306
+ function readFileFromInputFileSystem(inputFileSystem, file) {
307
+ return new Promise((resolve, reject) => {
308
+ inputFileSystem.readFile(file, (error, data) => {
309
+ if (error) {
310
+ reject(error);
311
+ return;
312
+ }
313
+ if (data == null) {
314
+ reject(/* @__PURE__ */ new Error(`could not read module source for ${file}`));
315
+ return;
316
+ }
317
+ resolve(data);
318
+ });
319
+ });
320
+ }
321
+ //#endregion
322
+ export { registerStartCompilerTransforms };
@@ -0,0 +1,10 @@
1
+ import { Rspack } from '@rsbuild/core';
2
+ import {
3
+ ServerFnBuildInfoLoaderContext,
4
+ ServerFnMetadataLoaderOptions,
5
+ } from './start-compiler-metadata.js';
6
+ declare const tanStackStartCompilerMetadataLoader: Rspack.LoaderDefinition<
7
+ ServerFnMetadataLoaderOptions,
8
+ ServerFnBuildInfoLoaderContext
9
+ >;
10
+ export default tanStackStartCompilerMetadataLoader;
@@ -0,0 +1,12 @@
1
+ import { SERVER_FN_BUILD_INFO_CONTEXT_KEY } from './start-compiler-metadata.js';
2
+ //#region src/rsbuild/start-compiler-metadata-loader.ts
3
+ var tanStackStartCompilerMetadataLoader = function (source, map) {
4
+ const { metadataById } = this.getOptions();
5
+ const id = this.resource;
6
+ const metadata = metadataById.get(id);
7
+ const setBuildInfo = this[SERVER_FN_BUILD_INFO_CONTEXT_KEY];
8
+ setBuildInfo?.(metadata ?? null);
9
+ this.callback(null, source, map);
10
+ };
11
+ //#endregion
12
+ export { tanStackStartCompilerMetadataLoader as default };
@@ -0,0 +1,14 @@
1
+ import { ServerFn } from '../start-compiler/types.js';
2
+ export declare const SERVER_FN_BUILD_INFO_FIELD = 'tanstack.start.serverFns';
3
+ export declare const SERVER_FN_BUILD_INFO_CONTEXT_KEY = 'tanstack.start.setServerFnBuildInfo';
4
+ export type ServerFnBuildInfo = {
5
+ version: 1;
6
+ serverFnsById: Record<string, ServerFn>;
7
+ };
8
+ export type SetServerFnBuildInfo = (metadata: ServerFnBuildInfo | null) => void;
9
+ export type ServerFnBuildInfoLoaderContext = {
10
+ [SERVER_FN_BUILD_INFO_CONTEXT_KEY]?: SetServerFnBuildInfo;
11
+ };
12
+ export type ServerFnMetadataLoaderOptions = {
13
+ metadataById: Map<string, ServerFnBuildInfo>;
14
+ };
@@ -0,0 +1,5 @@
1
+ //#region src/rsbuild/start-compiler-metadata.ts
2
+ var SERVER_FN_BUILD_INFO_FIELD = 'tanstack.start.serverFns';
3
+ var SERVER_FN_BUILD_INFO_CONTEXT_KEY = 'tanstack.start.setServerFnBuildInfo';
4
+ //#endregion
5
+ export { SERVER_FN_BUILD_INFO_CONTEXT_KEY, SERVER_FN_BUILD_INFO_FIELD };
@@ -0,0 +1,19 @@
1
+ import { RsbuildPluginAPI } from '@rsbuild/core';
2
+ import { GetConfigFn, TanStackStartCoreOptions } from '../types.js';
3
+ import { TanStackStartRsbuildInputConfig } from './schema.js';
4
+ /**
5
+ * Registers the TanStack Router generator and code-splitter plugins
6
+ * as rspack plugins via `modifyRspackConfig`.
7
+ *
8
+ * The router-plugin package exports rspack-compatible unplugin wrappers:
9
+ * - TanStackRouterGeneratorRspack: file-based route generation
10
+ * - TanStackRouterCodeSplitterRspack: route code splitting
11
+ */
12
+ export declare function registerRouterPlugins(
13
+ api: RsbuildPluginAPI,
14
+ opts: {
15
+ getConfig: GetConfigFn;
16
+ corePluginOpts: TanStackStartCoreOptions;
17
+ startPluginOpts: TanStackStartRsbuildInputConfig;
18
+ },
19
+ ): void;