@tanstack/start-plugin-core 1.167.35 → 1.169.0
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/import-protection/adapterUtils.d.ts +27 -0
- package/dist/esm/import-protection/adapterUtils.js +31 -0
- package/dist/esm/import-protection/adapterUtils.js.map +1 -0
- package/dist/esm/import-protection/analysis.d.ts +36 -0
- package/dist/esm/import-protection/analysis.js +407 -0
- package/dist/esm/import-protection/analysis.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/ast.js +1 -1
- package/dist/esm/import-protection/ast.js.map +1 -0
- package/dist/esm/import-protection/constants.d.ts +11 -0
- package/dist/esm/{import-protection-plugin → import-protection}/constants.js +7 -2
- package/dist/esm/import-protection/constants.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/defaults.js +1 -1
- package/dist/esm/import-protection/defaults.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.js +2 -2
- package/dist/esm/import-protection/extensionlessAbsoluteIdResolver.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/matchers.js +1 -1
- package/dist/esm/import-protection/matchers.js.map +1 -0
- package/dist/esm/{import-protection-plugin/rewriteDeniedImports.d.ts → import-protection/rewrite.d.ts} +0 -4
- package/dist/esm/import-protection/rewrite.js +121 -0
- package/dist/esm/import-protection/rewrite.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.d.ts +32 -3
- package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.js +65 -10
- package/dist/esm/import-protection/sourceLocation.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/trace.d.ts +0 -1
- package/dist/esm/{import-protection-plugin → import-protection}/trace.js +1 -1
- package/dist/esm/import-protection/trace.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/utils.d.ts +18 -1
- package/dist/esm/{import-protection-plugin → import-protection}/utils.js +13 -20
- package/dist/esm/import-protection/utils.js.map +1 -0
- package/dist/esm/import-protection/virtualModules.d.ts +25 -0
- package/dist/esm/{import-protection-plugin → import-protection}/virtualModules.js +5 -117
- package/dist/esm/import-protection/virtualModules.js.map +1 -0
- package/dist/esm/index.d.ts +1 -5
- package/dist/esm/index.js +2 -4
- package/dist/esm/post-build.d.ts +9 -0
- package/dist/esm/post-build.js +37 -0
- package/dist/esm/post-build.js.map +1 -0
- package/dist/esm/prerender.d.ts +11 -0
- package/dist/esm/prerender.js +159 -0
- package/dist/esm/prerender.js.map +1 -0
- package/dist/esm/rsbuild/dev-server.d.ts +21 -0
- package/dist/esm/rsbuild/dev-server.js +76 -0
- package/dist/esm/rsbuild/dev-server.js.map +1 -0
- package/dist/esm/rsbuild/import-protection.d.ts +10 -0
- package/dist/esm/rsbuild/import-protection.js +775 -0
- package/dist/esm/rsbuild/import-protection.js.map +1 -0
- package/dist/esm/rsbuild/index.d.ts +4 -0
- package/dist/esm/rsbuild/index.js +3 -0
- package/dist/esm/rsbuild/normalized-client-build.d.ts +18 -0
- package/dist/esm/rsbuild/normalized-client-build.js +207 -0
- package/dist/esm/rsbuild/normalized-client-build.js.map +1 -0
- package/dist/esm/rsbuild/planning.d.ts +52 -0
- package/dist/esm/rsbuild/planning.js +108 -0
- package/dist/esm/rsbuild/planning.js.map +1 -0
- package/dist/esm/rsbuild/plugin.d.ts +4 -0
- package/dist/esm/rsbuild/plugin.js +344 -0
- package/dist/esm/rsbuild/plugin.js.map +1 -0
- package/dist/esm/rsbuild/post-build.d.ts +6 -0
- package/dist/esm/rsbuild/post-build.js +57 -0
- package/dist/esm/rsbuild/post-build.js.map +1 -0
- package/dist/esm/rsbuild/schema.d.ts +3372 -0
- package/dist/esm/rsbuild/schema.js +12 -0
- package/dist/esm/rsbuild/schema.js.map +1 -0
- package/dist/esm/rsbuild/start-compiler-host.d.ts +20 -0
- package/dist/esm/rsbuild/start-compiler-host.js +150 -0
- package/dist/esm/rsbuild/start-compiler-host.js.map +1 -0
- package/dist/esm/rsbuild/start-router-plugin.d.ts +18 -0
- package/dist/esm/rsbuild/start-router-plugin.js +63 -0
- package/dist/esm/rsbuild/start-router-plugin.js.map +1 -0
- package/dist/esm/rsbuild/swc-rsc.d.ts +14 -0
- package/dist/esm/rsbuild/swc-rsc.js +93 -0
- package/dist/esm/rsbuild/swc-rsc.js.map +1 -0
- package/dist/esm/rsbuild/types.d.ts +17 -0
- package/dist/esm/rsbuild/types.js +0 -0
- package/dist/esm/rsbuild/virtual-modules.d.ts +53 -0
- package/dist/esm/rsbuild/virtual-modules.js +287 -0
- package/dist/esm/rsbuild/virtual-modules.js.map +1 -0
- package/dist/esm/schema.d.ts +43 -43
- package/dist/esm/start-compiler/compiler.d.ts +1 -1
- package/dist/esm/start-compiler/compiler.js +80 -9
- package/dist/esm/start-compiler/compiler.js.map +1 -1
- package/dist/esm/start-compiler/handleCreateServerFn.js +9 -0
- package/dist/esm/start-compiler/handleCreateServerFn.js.map +1 -1
- package/dist/esm/start-compiler/host.js +5 -1
- package/dist/esm/start-compiler/host.js.map +1 -1
- package/dist/esm/start-compiler/types.d.ts +1 -0
- package/dist/esm/utils.d.ts +1 -0
- package/dist/esm/utils.js +10 -1
- package/dist/esm/utils.js.map +1 -1
- package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.js +41 -92
- package/dist/esm/vite/import-protection-plugin/plugin.js.map +1 -0
- package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/types.d.ts +5 -5
- package/dist/esm/vite/import-protection-plugin/virtualModules.d.ts +8 -0
- package/dist/esm/vite/import-protection-plugin/virtualModules.js +49 -0
- package/dist/esm/vite/import-protection-plugin/virtualModules.js.map +1 -0
- package/dist/esm/vite/index.d.ts +5 -0
- package/dist/esm/vite/index.js +4 -0
- package/dist/esm/vite/plugin.js +1 -1
- package/dist/esm/vite/plugin.js.map +1 -1
- package/dist/esm/vite/post-server-build.js +14 -32
- package/dist/esm/vite/post-server-build.js.map +1 -1
- package/dist/esm/vite/prerender.d.ts +2 -2
- package/dist/esm/vite/prerender.js +17 -147
- package/dist/esm/vite/prerender.js.map +1 -1
- package/dist/esm/vite/schema.d.ts +23 -23
- package/dist/esm/vite/start-compiler-plugin/hot-update.d.ts +2 -0
- package/dist/esm/vite/start-compiler-plugin/hot-update.js +16 -0
- package/dist/esm/vite/start-compiler-plugin/hot-update.js.map +1 -0
- package/dist/esm/vite/start-compiler-plugin/module-specifier.js +9 -4
- package/dist/esm/vite/start-compiler-plugin/module-specifier.js.map +1 -1
- package/dist/esm/vite/start-compiler-plugin/plugin.js +86 -13
- package/dist/esm/vite/start-compiler-plugin/plugin.js.map +1 -1
- package/package.json +32 -4
- package/src/import-protection/INTERNALS.md +266 -0
- package/src/import-protection/adapterUtils.ts +94 -0
- package/src/import-protection/analysis.ts +853 -0
- package/src/{import-protection-plugin → import-protection}/constants.ts +7 -0
- package/src/import-protection/rewrite.ts +229 -0
- package/src/{import-protection-plugin → import-protection}/sourceLocation.ts +125 -9
- package/src/{import-protection-plugin → import-protection}/trace.ts +0 -1
- package/src/{import-protection-plugin → import-protection}/utils.ts +36 -21
- package/src/{import-protection-plugin → import-protection}/virtualModules.ts +30 -177
- package/src/index.ts +1 -8
- package/src/post-build.ts +64 -0
- package/src/prerender.ts +292 -0
- package/src/rsbuild/INTERNALS-import-protection.md +169 -0
- package/src/rsbuild/dev-server.ts +129 -0
- package/src/rsbuild/import-protection.ts +1599 -0
- package/src/rsbuild/index.ts +4 -0
- package/src/rsbuild/normalized-client-build.ts +346 -0
- package/src/rsbuild/planning.ts +234 -0
- package/src/rsbuild/plugin.ts +754 -0
- package/src/rsbuild/post-build.ts +96 -0
- package/src/rsbuild/schema.ts +31 -0
- package/src/rsbuild/start-compiler-host.ts +250 -0
- package/src/rsbuild/start-router-plugin.ts +86 -0
- package/src/rsbuild/swc-rsc.ts +166 -0
- package/src/rsbuild/types.ts +20 -0
- package/src/rsbuild/virtual-modules.ts +565 -0
- package/src/start-compiler/compiler.ts +153 -19
- package/src/start-compiler/handleCreateServerFn.ts +18 -0
- package/src/start-compiler/types.ts +1 -0
- package/src/utils.ts +14 -0
- package/src/vite/import-protection-plugin/INTERNALS.md +187 -0
- package/src/{import-protection-plugin → vite/import-protection-plugin}/plugin.ts +73 -158
- package/src/{import-protection-plugin → vite/import-protection-plugin}/types.ts +5 -5
- package/src/vite/import-protection-plugin/virtualModules.ts +122 -0
- package/src/vite/index.ts +8 -0
- package/src/vite/plugin.ts +1 -1
- package/src/vite/post-server-build.ts +14 -57
- package/src/vite/prerender.ts +19 -260
- package/src/vite/start-compiler-plugin/hot-update.ts +24 -0
- package/src/vite/start-compiler-plugin/module-specifier.ts +15 -5
- package/src/vite/start-compiler-plugin/plugin.ts +193 -18
- package/dist/esm/import-protection-plugin/ast.js.map +0 -1
- package/dist/esm/import-protection-plugin/constants.d.ts +0 -6
- package/dist/esm/import-protection-plugin/constants.js.map +0 -1
- package/dist/esm/import-protection-plugin/defaults.js.map +0 -1
- package/dist/esm/import-protection-plugin/extensionlessAbsoluteIdResolver.js.map +0 -1
- package/dist/esm/import-protection-plugin/matchers.js.map +0 -1
- package/dist/esm/import-protection-plugin/plugin.js.map +0 -1
- package/dist/esm/import-protection-plugin/postCompileUsage.d.ts +0 -13
- package/dist/esm/import-protection-plugin/postCompileUsage.js +0 -63
- package/dist/esm/import-protection-plugin/postCompileUsage.js.map +0 -1
- package/dist/esm/import-protection-plugin/rewriteDeniedImports.js +0 -205
- package/dist/esm/import-protection-plugin/rewriteDeniedImports.js.map +0 -1
- package/dist/esm/import-protection-plugin/sourceLocation.js.map +0 -1
- package/dist/esm/import-protection-plugin/trace.js.map +0 -1
- package/dist/esm/import-protection-plugin/utils.js.map +0 -1
- package/dist/esm/import-protection-plugin/virtualModules.d.ts +0 -78
- package/dist/esm/import-protection-plugin/virtualModules.js.map +0 -1
- package/dist/esm/start-compiler/load-module.d.ts +0 -14
- package/dist/esm/start-compiler/load-module.js +0 -18
- package/dist/esm/start-compiler/load-module.js.map +0 -1
- package/src/import-protection-plugin/INTERNALS.md +0 -700
- package/src/import-protection-plugin/postCompileUsage.ts +0 -100
- package/src/import-protection-plugin/rewriteDeniedImports.ts +0 -379
- package/src/start-compiler/load-module.ts +0 -31
- /package/dist/esm/{import-protection-plugin → import-protection}/ast.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → import-protection}/defaults.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → import-protection}/matchers.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.d.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/ast.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/defaults.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/matchers.ts +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { join } from 'pathe'
|
|
2
|
+
import { postBuild } from '../post-build'
|
|
3
|
+
import { prerender } from '../prerender'
|
|
4
|
+
import type { PrerenderHandler } from '../prerender'
|
|
5
|
+
import type { TanStackStartOutputConfig } from '../schema'
|
|
6
|
+
|
|
7
|
+
export async function postBuildWithRsbuild({
|
|
8
|
+
startConfig,
|
|
9
|
+
clientOutputDirectory,
|
|
10
|
+
serverOutputDirectory,
|
|
11
|
+
}: {
|
|
12
|
+
startConfig: TanStackStartOutputConfig
|
|
13
|
+
clientOutputDirectory: string
|
|
14
|
+
serverOutputDirectory: string
|
|
15
|
+
}) {
|
|
16
|
+
await postBuild({
|
|
17
|
+
startConfig,
|
|
18
|
+
adapter: {
|
|
19
|
+
getClientOutputDirectory() {
|
|
20
|
+
return clientOutputDirectory
|
|
21
|
+
},
|
|
22
|
+
prerender(startConfig) {
|
|
23
|
+
return prerender({
|
|
24
|
+
startConfig,
|
|
25
|
+
handler: createRsbuildPrerenderHandler({
|
|
26
|
+
clientOutputDirectory,
|
|
27
|
+
serverOutputDirectory,
|
|
28
|
+
}),
|
|
29
|
+
})
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function createRsbuildPrerenderHandler({
|
|
36
|
+
clientOutputDirectory,
|
|
37
|
+
serverOutputDirectory,
|
|
38
|
+
}: {
|
|
39
|
+
clientOutputDirectory: string
|
|
40
|
+
serverOutputDirectory: string
|
|
41
|
+
}): PrerenderHandler {
|
|
42
|
+
process.env.TSS_PRERENDERING = 'true'
|
|
43
|
+
process.env.TSS_CLIENT_OUTPUT_DIR = clientOutputDirectory
|
|
44
|
+
|
|
45
|
+
let requestHandlerPromise:
|
|
46
|
+
| Promise<
|
|
47
|
+
(request: Request, opts?: unknown) => Promise<Response> | Response
|
|
48
|
+
>
|
|
49
|
+
| undefined
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
getClientOutputDirectory() {
|
|
53
|
+
return clientOutputDirectory
|
|
54
|
+
},
|
|
55
|
+
async request(path, options) {
|
|
56
|
+
const requestHandler = await getRequestHandler()
|
|
57
|
+
const url = new URL(path, 'http://localhost')
|
|
58
|
+
|
|
59
|
+
return requestHandler(
|
|
60
|
+
new Request(url, {
|
|
61
|
+
...options,
|
|
62
|
+
redirect: 'manual',
|
|
63
|
+
}),
|
|
64
|
+
)
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getRequestHandler() {
|
|
69
|
+
if (!requestHandlerPromise) {
|
|
70
|
+
requestHandlerPromise = loadRequestHandler(serverOutputDirectory)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return requestHandlerPromise
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function loadRequestHandler(serverOutputDirectory: string) {
|
|
78
|
+
const { pathToFileURL } = await import('node:url')
|
|
79
|
+
const serverEntryUrl = pathToFileURL(
|
|
80
|
+
join(serverOutputDirectory, 'index.js'),
|
|
81
|
+
).toString()
|
|
82
|
+
const serverModule = await import(serverEntryUrl)
|
|
83
|
+
const handler = serverModule.default
|
|
84
|
+
|
|
85
|
+
if (typeof handler === 'function') {
|
|
86
|
+
return handler as (request: Request) => Promise<Response> | Response
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (handler && typeof handler.fetch === 'function') {
|
|
90
|
+
return (request: Request) => handler.fetch(request)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Unable to resolve a request handler from Rsbuild server bundle at ${serverEntryUrl}`,
|
|
95
|
+
)
|
|
96
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import {
|
|
3
|
+
parseStartConfig as parseCoreStartConfig,
|
|
4
|
+
tanstackStartOptionsObjectSchema,
|
|
5
|
+
} from '../schema'
|
|
6
|
+
import type { CompileStartFrameworkOptions } from '../types'
|
|
7
|
+
|
|
8
|
+
export const tanstackStartRsbuildOptionsSchema =
|
|
9
|
+
tanstackStartOptionsObjectSchema
|
|
10
|
+
.extend({
|
|
11
|
+
rsbuild: z
|
|
12
|
+
.object({ installDevServerMiddleware: z.boolean().optional() })
|
|
13
|
+
.optional(),
|
|
14
|
+
})
|
|
15
|
+
.optional()
|
|
16
|
+
.default({})
|
|
17
|
+
|
|
18
|
+
export function parseStartConfig(
|
|
19
|
+
opts: z.input<typeof tanstackStartRsbuildOptionsSchema>,
|
|
20
|
+
corePluginOpts: { framework: CompileStartFrameworkOptions },
|
|
21
|
+
root: string,
|
|
22
|
+
) {
|
|
23
|
+
const { rsbuild: _rsbuild, ...coreOptions } =
|
|
24
|
+
tanstackStartRsbuildOptionsSchema.parse(opts)
|
|
25
|
+
|
|
26
|
+
return parseCoreStartConfig(coreOptions, corePluginOpts, root)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type TanStackStartRsbuildInputConfig = z.input<
|
|
30
|
+
typeof tanstackStartRsbuildOptionsSchema
|
|
31
|
+
>
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
|
+
import { pathToFileURL } from 'node:url'
|
|
3
|
+
import { TRANSFORM_ID_REGEX } from '../constants'
|
|
4
|
+
import { detectKindsInCode } from '../start-compiler/compiler'
|
|
5
|
+
import { getTransformCodeFilterForEnv } from '../start-compiler/config'
|
|
6
|
+
import {
|
|
7
|
+
createStartCompiler,
|
|
8
|
+
matchesCodeFilters,
|
|
9
|
+
mergeServerFnsById,
|
|
10
|
+
} from '../start-compiler/host'
|
|
11
|
+
import { cleanId } from '../start-compiler/utils'
|
|
12
|
+
import { RSBUILD_ENVIRONMENT_NAMES } from './planning'
|
|
13
|
+
import type { RsbuildPluginAPI, Rspack } from '@rsbuild/core'
|
|
14
|
+
import type { CompileStartFrameworkOptions } from '../types'
|
|
15
|
+
import type {
|
|
16
|
+
DevServerFnModuleSpecifierEncoder,
|
|
17
|
+
GenerateFunctionIdFnOptional,
|
|
18
|
+
ServerFn,
|
|
19
|
+
} from '../start-compiler/types'
|
|
20
|
+
|
|
21
|
+
type RsbuildTransformContext = Parameters<
|
|
22
|
+
Parameters<RsbuildPluginAPI['transform']>[1]
|
|
23
|
+
>[0]
|
|
24
|
+
type RsbuildInputFileSystem = NonNullable<Rspack.Compiler['inputFileSystem']>
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Rsbuild dev server fn ref strategy: uses file:// URLs for absolute paths.
|
|
28
|
+
* These are directly importable by Node's ESM VM runner without any bundler
|
|
29
|
+
* path conventions (unlike Vite's /@id/ prefix).
|
|
30
|
+
*/
|
|
31
|
+
const rsbuildDevServerFnModuleSpecifierEncoder: DevServerFnModuleSpecifierEncoder =
|
|
32
|
+
({ extractedFilename }) => pathToFileURL(extractedFilename).href
|
|
33
|
+
|
|
34
|
+
export interface StartCompilerHostOptions {
|
|
35
|
+
framework: CompileStartFrameworkOptions
|
|
36
|
+
root: string | (() => string)
|
|
37
|
+
providerEnvName: string
|
|
38
|
+
generateFunctionId?: GenerateFunctionIdFnOptional
|
|
39
|
+
serverFnsById?: Record<string, ServerFn>
|
|
40
|
+
onServerFnsByIdChange?: () => void
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Registers the shared StartCompiler as rsbuild transforms for client + ssr environments.
|
|
45
|
+
*
|
|
46
|
+
* Uses `api.transform()` to hook into the rsbuild loader pipeline, and the
|
|
47
|
+
* transform context's native `resolve()` for module resolution.
|
|
48
|
+
*/
|
|
49
|
+
export function registerStartCompilerTransforms(
|
|
50
|
+
api: RsbuildPluginAPI,
|
|
51
|
+
opts: StartCompilerHostOptions,
|
|
52
|
+
): {
|
|
53
|
+
serverFnsById: Record<string, ServerFn>
|
|
54
|
+
} {
|
|
55
|
+
const compilers = new Map<string, ReturnType<typeof createStartCompiler>>()
|
|
56
|
+
const inputFileSystems = new Map<string, RsbuildInputFileSystem>()
|
|
57
|
+
const transformContextStorage =
|
|
58
|
+
new AsyncLocalStorage<RsbuildTransformContext>()
|
|
59
|
+
const serverFnsById = opts.serverFnsById ?? {}
|
|
60
|
+
const getRoot = () =>
|
|
61
|
+
typeof opts.root === 'function' ? opts.root() : opts.root
|
|
62
|
+
|
|
63
|
+
const onServerFnsById = (d: Record<string, ServerFn>) => {
|
|
64
|
+
mergeServerFnsById(serverFnsById, d)
|
|
65
|
+
opts.onServerFnsByIdChange?.()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const isDev = api.context.action === 'dev'
|
|
69
|
+
const mode = isDev ? 'dev' : 'build'
|
|
70
|
+
|
|
71
|
+
const environments: Array<{
|
|
72
|
+
name: string
|
|
73
|
+
type: 'client' | 'server'
|
|
74
|
+
}> = [
|
|
75
|
+
{ name: RSBUILD_ENVIRONMENT_NAMES.client, type: 'client' },
|
|
76
|
+
{ name: RSBUILD_ENVIRONMENT_NAMES.server, type: 'server' },
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
// Pre-compute code filter patterns per environment type
|
|
80
|
+
const codeFilters: Record<'client' | 'server', Array<RegExp>> = {
|
|
81
|
+
client: getTransformCodeFilterForEnv('client'),
|
|
82
|
+
server: getTransformCodeFilterForEnv('server'),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (const env of environments) {
|
|
86
|
+
const envCodeFilters = codeFilters[env.type]
|
|
87
|
+
|
|
88
|
+
api.transform(
|
|
89
|
+
{
|
|
90
|
+
test: TRANSFORM_ID_REGEX[0],
|
|
91
|
+
environments: [env.name],
|
|
92
|
+
order: 'pre',
|
|
93
|
+
},
|
|
94
|
+
async (ctx: RsbuildTransformContext) => {
|
|
95
|
+
return transformContextStorage.run(ctx, async () => {
|
|
96
|
+
const code = ctx.code
|
|
97
|
+
const id = ctx.resourcePath + (ctx.resourceQuery || '')
|
|
98
|
+
|
|
99
|
+
// Quick string-level check: does this file contain any patterns for this env?
|
|
100
|
+
if (!matchesCodeFilters(code, envCodeFilters)) {
|
|
101
|
+
return code
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let compiler = compilers.get(env.name)
|
|
105
|
+
if (!compiler) {
|
|
106
|
+
const root = getRoot()
|
|
107
|
+
|
|
108
|
+
compiler = createStartCompiler({
|
|
109
|
+
env: env.type,
|
|
110
|
+
envName: env.name,
|
|
111
|
+
root,
|
|
112
|
+
mode,
|
|
113
|
+
framework: opts.framework,
|
|
114
|
+
providerEnvName: opts.providerEnvName,
|
|
115
|
+
generateFunctionId: opts.generateFunctionId,
|
|
116
|
+
onServerFnsById,
|
|
117
|
+
getKnownServerFns: () => serverFnsById,
|
|
118
|
+
encodeModuleSpecifierInDev: isDev
|
|
119
|
+
? rsbuildDevServerFnModuleSpecifierEncoder
|
|
120
|
+
: undefined,
|
|
121
|
+
loadModule: async (moduleId: string) => {
|
|
122
|
+
const activeCtx = transformContextStorage.getStore()
|
|
123
|
+
if (!activeCtx) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`could not load module ${moduleId}: missing active rsbuild transform context for ${env.name}`,
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const inputFileSystem = inputFileSystems.get(env.name)
|
|
130
|
+
if (!inputFileSystem) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`could not load module ${moduleId}: missing rspack input filesystem for ${env.name}`,
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const cleanedId = cleanId(moduleId)
|
|
137
|
+
activeCtx.addDependency(cleanedId)
|
|
138
|
+
const loaded = await readFileFromInputFileSystem(
|
|
139
|
+
inputFileSystem,
|
|
140
|
+
cleanedId,
|
|
141
|
+
)
|
|
142
|
+
const moduleCode = Buffer.isBuffer(loaded)
|
|
143
|
+
? loaded.toString('utf8')
|
|
144
|
+
: loaded
|
|
145
|
+
|
|
146
|
+
compiler!.ingestModule({ code: moduleCode, id: cleanedId })
|
|
147
|
+
},
|
|
148
|
+
resolveId: async (
|
|
149
|
+
source: string,
|
|
150
|
+
importer?: string,
|
|
151
|
+
): Promise<string | null> => {
|
|
152
|
+
const activeCtx = transformContextStorage.getStore()
|
|
153
|
+
if (!activeCtx) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`could not resolve ${source}: missing active rsbuild transform context for ${env.name}`,
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const context = importer
|
|
160
|
+
? importer.replace(/[/\\][^/\\]*$/, '')
|
|
161
|
+
: getRoot()
|
|
162
|
+
|
|
163
|
+
return await new Promise((resolve, reject) => {
|
|
164
|
+
activeCtx.resolve(context, source, (error, resolved) => {
|
|
165
|
+
if (error) {
|
|
166
|
+
reject(error)
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (!resolved) {
|
|
171
|
+
resolve(null)
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
resolve(cleanId(resolved))
|
|
176
|
+
})
|
|
177
|
+
})
|
|
178
|
+
},
|
|
179
|
+
})
|
|
180
|
+
compilers.set(env.name, compiler)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const detectedKinds = detectKindsInCode(code, env.type)
|
|
184
|
+
const result = await compiler.compile({ id, code, detectedKinds })
|
|
185
|
+
|
|
186
|
+
if (!result) {
|
|
187
|
+
return code
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
code: result.code,
|
|
192
|
+
map: result.map ?? null,
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
},
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
api.modifyRspackConfig((config, utils) => {
|
|
200
|
+
config.plugins.push({
|
|
201
|
+
apply(compiler: Rspack.Compiler) {
|
|
202
|
+
if (compiler.inputFileSystem) {
|
|
203
|
+
inputFileSystems.set(utils.environment.name, compiler.inputFileSystem)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
compiler.hooks.watchRun.tap(
|
|
207
|
+
'TanStackStartCompilerModuleInvalidation',
|
|
208
|
+
(watchCompiler) => {
|
|
209
|
+
const startCompiler = compilers.get(utils.environment.name)
|
|
210
|
+
|
|
211
|
+
if (!startCompiler) {
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (const file of watchCompiler.modifiedFiles ?? []) {
|
|
216
|
+
startCompiler.invalidateModule(file)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (const file of watchCompiler.removedFiles ?? []) {
|
|
220
|
+
startCompiler.invalidateModule(file)
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
)
|
|
224
|
+
},
|
|
225
|
+
})
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
return { serverFnsById }
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function readFileFromInputFileSystem(
|
|
232
|
+
inputFileSystem: RsbuildInputFileSystem,
|
|
233
|
+
file: string,
|
|
234
|
+
): Promise<string | Buffer> {
|
|
235
|
+
return new Promise((resolve, reject) => {
|
|
236
|
+
inputFileSystem.readFile(file, (error, data) => {
|
|
237
|
+
if (error) {
|
|
238
|
+
reject(error)
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (data == null) {
|
|
243
|
+
reject(new Error(`could not read module source for ${file}`))
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
resolve(data)
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import path from 'pathe'
|
|
2
|
+
import { routesManifestPlugin } from '../start-router-plugin/generator-plugins/routes-manifest-plugin'
|
|
3
|
+
import { prerenderRoutesPlugin } from '../start-router-plugin/generator-plugins/prerender-routes-plugin'
|
|
4
|
+
import { buildRouteTreeFileFooterFromConfig } from '../start-router-plugin/route-tree-footer'
|
|
5
|
+
import { RSBUILD_ENVIRONMENT_NAMES } from './planning'
|
|
6
|
+
import type { RsbuildPluginAPI } from '@rsbuild/core'
|
|
7
|
+
import type { GetConfigFn, TanStackStartCoreOptions } from '../types'
|
|
8
|
+
import type { TanStackStartRsbuildInputConfig } from './schema'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Registers the TanStack Router generator and code-splitter plugins
|
|
12
|
+
* as rspack plugins via `modifyRspackConfig`.
|
|
13
|
+
*
|
|
14
|
+
* The router-plugin package exports rspack-compatible unplugin wrappers:
|
|
15
|
+
* - TanStackRouterGeneratorRspack: file-based route generation
|
|
16
|
+
* - TanStackRouterCodeSplitterRspack: route code splitting
|
|
17
|
+
*
|
|
18
|
+
* These are dynamically imported to avoid hard dependency on router-plugin/rspack.
|
|
19
|
+
*/
|
|
20
|
+
export function registerRouterPlugins(
|
|
21
|
+
api: RsbuildPluginAPI,
|
|
22
|
+
opts: {
|
|
23
|
+
getConfig: GetConfigFn
|
|
24
|
+
corePluginOpts: TanStackStartCoreOptions
|
|
25
|
+
startPluginOpts: TanStackStartRsbuildInputConfig
|
|
26
|
+
},
|
|
27
|
+
): void {
|
|
28
|
+
api.modifyRspackConfig(async (config, utils) => {
|
|
29
|
+
const envName = utils.environment.name
|
|
30
|
+
const { startConfig } = opts.getConfig()
|
|
31
|
+
const routerConfig = startConfig.router
|
|
32
|
+
|
|
33
|
+
// Generator only runs once — register for the client environment
|
|
34
|
+
if (envName === RSBUILD_ENVIRONMENT_NAMES.client) {
|
|
35
|
+
try {
|
|
36
|
+
const { TanStackRouterGeneratorRspack } =
|
|
37
|
+
await import('@tanstack/router-plugin/rspack')
|
|
38
|
+
const generatorPlugin = TanStackRouterGeneratorRspack({
|
|
39
|
+
...routerConfig,
|
|
40
|
+
target: opts.corePluginOpts.framework,
|
|
41
|
+
routeTreeFileFooter: () => {
|
|
42
|
+
return buildRouteTreeFileFooterFromConfig({
|
|
43
|
+
generatedRouteTreePath: path.resolve(
|
|
44
|
+
routerConfig.generatedRouteTree,
|
|
45
|
+
),
|
|
46
|
+
getConfig: opts.getConfig,
|
|
47
|
+
corePluginOpts: opts.corePluginOpts,
|
|
48
|
+
})
|
|
49
|
+
},
|
|
50
|
+
plugins: [
|
|
51
|
+
routesManifestPlugin(),
|
|
52
|
+
...(opts.startPluginOpts?.prerender?.enabled === true
|
|
53
|
+
? [prerenderRoutesPlugin()]
|
|
54
|
+
: []),
|
|
55
|
+
],
|
|
56
|
+
})
|
|
57
|
+
utils.appendPlugins(generatorPlugin as any)
|
|
58
|
+
} catch {
|
|
59
|
+
// router-plugin/rspack not available — skip
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
envName === RSBUILD_ENVIRONMENT_NAMES.client ||
|
|
65
|
+
envName === RSBUILD_ENVIRONMENT_NAMES.server
|
|
66
|
+
) {
|
|
67
|
+
const isClient = envName === RSBUILD_ENVIRONMENT_NAMES.client
|
|
68
|
+
try {
|
|
69
|
+
const { TanStackRouterCodeSplitterRspack } =
|
|
70
|
+
await import('@tanstack/router-plugin/rspack')
|
|
71
|
+
const splitterPlugin = TanStackRouterCodeSplitterRspack({
|
|
72
|
+
...routerConfig,
|
|
73
|
+
target: opts.corePluginOpts.framework,
|
|
74
|
+
codeSplittingOptions: {
|
|
75
|
+
...routerConfig.codeSplittingOptions,
|
|
76
|
+
deleteNodes: isClient ? ['ssr', 'server', 'headers'] : undefined,
|
|
77
|
+
addHmr: isClient,
|
|
78
|
+
},
|
|
79
|
+
})
|
|
80
|
+
utils.appendPlugins(splitterPlugin as any)
|
|
81
|
+
} catch {
|
|
82
|
+
// router-plugin/rspack not available — skip
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { RSBUILD_RSC_LAYERS } from './planning'
|
|
2
|
+
import type { ModifyRspackConfigFn, Rspack } from '@rsbuild/core'
|
|
3
|
+
|
|
4
|
+
type RspackConfig = Parameters<ModifyRspackConfigFn>[0]
|
|
5
|
+
type RspackRule = Rspack.RuleSetRule
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Walk the rspack config's module.rules and inject
|
|
9
|
+
* `rspackExperiments.reactServerComponents: true` into SWC loaders.
|
|
10
|
+
*
|
|
11
|
+
* Recurses into `oneOf` arrays because rsbuild nests the main SWC loader
|
|
12
|
+
* inside a `oneOf` rule (e.g. separate branches for asset/source vs
|
|
13
|
+
* javascript/auto). Without recursion, only the mimetype-based fallback
|
|
14
|
+
* SWC rule gets the flag, leaving most .js/.ts files without RSC
|
|
15
|
+
* directive detection.
|
|
16
|
+
*/
|
|
17
|
+
export function enableSwcReactServerComponents(
|
|
18
|
+
config: RspackConfig,
|
|
19
|
+
scope: 'all' | 'rsc-subtree',
|
|
20
|
+
): void {
|
|
21
|
+
const isRspackRule = (
|
|
22
|
+
rule: NonNullable<RspackConfig['module']['rules']>[number],
|
|
23
|
+
): rule is RspackRule => !!rule && rule !== '...'
|
|
24
|
+
const getRuleLoaders = (rule: RspackRule) => {
|
|
25
|
+
const { use } = rule
|
|
26
|
+
if (!use) {
|
|
27
|
+
return []
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return typeof use === 'function' ? [] : Array.isArray(use) ? use : [use]
|
|
31
|
+
}
|
|
32
|
+
const getLoaderPath = (
|
|
33
|
+
loader: ReturnType<typeof getRuleLoaders>[number],
|
|
34
|
+
): string | undefined => (typeof loader === 'string' ? loader : loader.loader)
|
|
35
|
+
const cloneLoader = (
|
|
36
|
+
loader: ReturnType<typeof getRuleLoaders>[number],
|
|
37
|
+
): ReturnType<typeof getRuleLoaders>[number] => {
|
|
38
|
+
if (typeof loader === 'string') {
|
|
39
|
+
return loader
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const options = loader.options
|
|
43
|
+
return {
|
|
44
|
+
...loader,
|
|
45
|
+
...(options && typeof options === 'object' && !Array.isArray(options)
|
|
46
|
+
? {
|
|
47
|
+
options: {
|
|
48
|
+
...options,
|
|
49
|
+
...(options.rspackExperiments &&
|
|
50
|
+
typeof options.rspackExperiments === 'object' &&
|
|
51
|
+
!Array.isArray(options.rspackExperiments)
|
|
52
|
+
? {
|
|
53
|
+
rspackExperiments: {
|
|
54
|
+
...options.rspackExperiments,
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
: {}),
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
: {}),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const cloneRuleUse = (use: RspackRule['use']): RspackRule['use'] => {
|
|
64
|
+
if (!use || typeof use === 'function') {
|
|
65
|
+
return use
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (Array.isArray(use)) {
|
|
69
|
+
return use.map((loader) => cloneLoader(loader)) as RspackRule['use']
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return cloneLoader(use) as RspackRule['use']
|
|
73
|
+
}
|
|
74
|
+
const cloneRspackRule = (rule: RspackRule): RspackRule => {
|
|
75
|
+
return {
|
|
76
|
+
...rule,
|
|
77
|
+
use: cloneRuleUse(rule.use),
|
|
78
|
+
resolve: rule.resolve ? { ...rule.resolve } : rule.resolve,
|
|
79
|
+
oneOf: Array.isArray(rule.oneOf)
|
|
80
|
+
? rule.oneOf.map((childRule) =>
|
|
81
|
+
isRspackRule(childRule) ? cloneRspackRule(childRule) : childRule,
|
|
82
|
+
)
|
|
83
|
+
: rule.oneOf,
|
|
84
|
+
} as unknown as RspackRule
|
|
85
|
+
}
|
|
86
|
+
const rootRules = (config.module.rules ??= []).filter(isRspackRule)
|
|
87
|
+
|
|
88
|
+
function processRules(rules = rootRules): void {
|
|
89
|
+
for (const rule of rules) {
|
|
90
|
+
processRules(
|
|
91
|
+
Array.isArray(rule.oneOf) ? rule.oneOf.filter(isRspackRule) : [],
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
const hasSwcLoader = getRuleLoaders(rule).some((loader) =>
|
|
95
|
+
Boolean(getLoaderPath(loader)?.includes('swc-loader')),
|
|
96
|
+
)
|
|
97
|
+
if (!hasSwcLoader) continue
|
|
98
|
+
|
|
99
|
+
const enableReactServerComponentsOnRule = (nextRule: RspackRule) => {
|
|
100
|
+
for (const loader of getRuleLoaders(nextRule)) {
|
|
101
|
+
if (typeof loader === 'string') {
|
|
102
|
+
continue
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const loaderPath = getLoaderPath(loader)
|
|
106
|
+
if (!loaderPath || !loaderPath.includes('swc-loader')) {
|
|
107
|
+
continue
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const options =
|
|
111
|
+
loader.options && typeof loader.options === 'object'
|
|
112
|
+
? loader.options
|
|
113
|
+
: (loader.options = {})
|
|
114
|
+
const experiments =
|
|
115
|
+
options.rspackExperiments &&
|
|
116
|
+
typeof options.rspackExperiments === 'object'
|
|
117
|
+
? options.rspackExperiments
|
|
118
|
+
: (options.rspackExperiments = {})
|
|
119
|
+
const current = experiments.reactServerComponents
|
|
120
|
+
|
|
121
|
+
experiments.reactServerComponents =
|
|
122
|
+
current === true || current == null
|
|
123
|
+
? {}
|
|
124
|
+
: typeof current === 'object' &&
|
|
125
|
+
current !== null &&
|
|
126
|
+
!Array.isArray(current)
|
|
127
|
+
? { ...current }
|
|
128
|
+
: {}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (scope === 'all') {
|
|
133
|
+
enableReactServerComponentsOnRule(rule)
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const originalRule = cloneRspackRule(rule)
|
|
138
|
+
const providerRule = cloneRspackRule(originalRule)
|
|
139
|
+
providerRule.resourceQuery = /(?:^|[?&])tss-serverfn-split(?:&|$)/
|
|
140
|
+
enableReactServerComponentsOnRule(providerRule)
|
|
141
|
+
|
|
142
|
+
const routeSplitRule = cloneRspackRule(originalRule)
|
|
143
|
+
routeSplitRule.resourceQuery = /(?:^|[?&])tsr-split(?:=|&|$)/
|
|
144
|
+
const routeSplitConditionNames = originalRule.resolve?.conditionNames
|
|
145
|
+
routeSplitRule.resolve = {
|
|
146
|
+
...originalRule.resolve,
|
|
147
|
+
conditionNames: Array.isArray(routeSplitConditionNames)
|
|
148
|
+
? routeSplitConditionNames.includes('...')
|
|
149
|
+
? [...routeSplitConditionNames]
|
|
150
|
+
: ['...', ...routeSplitConditionNames]
|
|
151
|
+
: ['...'],
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const subtreeRule = cloneRspackRule(originalRule)
|
|
155
|
+
subtreeRule.issuerLayer = RSBUILD_RSC_LAYERS.rsc
|
|
156
|
+
enableReactServerComponentsOnRule(subtreeRule)
|
|
157
|
+
|
|
158
|
+
for (const key of Object.keys(rule) as Array<keyof RspackRule>) {
|
|
159
|
+
delete rule[key]
|
|
160
|
+
}
|
|
161
|
+
rule.oneOf = [providerRule, routeSplitRule, subtreeRule, originalRule]
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
processRules()
|
|
166
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EnvironmentConfig } from '@rsbuild/core'
|
|
2
|
+
import type { TanStackStartCoreOptions } from '../types'
|
|
3
|
+
|
|
4
|
+
export interface RsbuildEnvironmentOverrides {
|
|
5
|
+
all?: EnvironmentConfig | undefined
|
|
6
|
+
client?: EnvironmentConfig | undefined
|
|
7
|
+
server?: EnvironmentConfig | undefined
|
|
8
|
+
provider?: EnvironmentConfig | undefined
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RsbuildCoreOptions {
|
|
12
|
+
environments?: RsbuildEnvironmentOverrides | undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type TanStackStartRsbuildPluginCoreOptions = TanStackStartCoreOptions & {
|
|
16
|
+
providerEnvironmentName: string
|
|
17
|
+
ssrIsProvider: boolean
|
|
18
|
+
rsbuild?: RsbuildCoreOptions | undefined
|
|
19
|
+
rsc?: boolean | undefined
|
|
20
|
+
}
|