Skip to content

Commit e04a393

Browse files
fix: generic env handling (#5811)
1 parent 1b75808 commit e04a393

File tree

4 files changed

+135
-132
lines changed

4 files changed

+135
-132
lines changed

packages/start-plugin-core/src/create-server-fn-plugin/handleCreateServerFn.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export function handleCreateServerFn(
146146
),
147147
),
148148
],
149-
[t.directive(t.directiveLiteral('use server'))],
149+
[t.directive(t.directiveLiteral(opts.directive))],
150150
),
151151
),
152152
)

packages/start-plugin-core/src/create-server-fn-plugin/plugin.ts

Lines changed: 45 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { TRANSFORM_ID_REGEX, VITE_ENVIRONMENT_NAMES } from '../constants'
1+
import { TRANSFORM_ID_REGEX } from '../constants'
22
import { ServerFnCompiler } from './compiler'
33
import type { LookupConfig, LookupKind } from './compiler'
44
import type { CompileStartFrameworkOptions } from '../start-compiler-plugin/compilers'
5-
import type { ViteEnvironmentNames } from '../constants'
65
import type { PluginOption } from 'vite'
76

87
function cleanId(id: string): string {
@@ -39,44 +38,29 @@ const getLookupConfigurationsForEnv = (
3938
return [createServerFnConfig]
4039
}
4140
}
41+
const SERVER_FN_LOOKUP = 'server-fn-module-lookup'
4242
export function createServerFnPlugin(opts: {
4343
framework: CompileStartFrameworkOptions
4444
directive: string
45+
environments: Array<{ name: string; type: 'client' | 'server' }>
4546
}): PluginOption {
46-
const SERVER_FN_LOOKUP = 'server-fn-module-lookup'
47+
const compilers: Record<string /* envName */, ServerFnCompiler> = {}
4748

48-
const compilers: Partial<Record<ViteEnvironmentNames, ServerFnCompiler>> = {}
49-
return [
50-
{
51-
name: 'tanstack-start-core:capture-server-fn-module-lookup',
52-
// we only need this plugin in dev mode
53-
apply: 'serve',
54-
applyToEnvironment(env) {
55-
return [
56-
VITE_ENVIRONMENT_NAMES.client,
57-
VITE_ENVIRONMENT_NAMES.server,
58-
].includes(env.name as ViteEnvironmentNames)
59-
},
60-
transform: {
61-
filter: {
62-
id: new RegExp(`${SERVER_FN_LOOKUP}$`),
63-
},
64-
handler(code, id) {
65-
const compiler =
66-
compilers[this.environment.name as ViteEnvironmentNames]
67-
compiler?.ingestModule({ code, id: cleanId(id) })
68-
},
69-
},
70-
},
71-
{
72-
name: 'tanstack-start-core::server-fn',
73-
enforce: 'pre',
49+
function perEnvServerFnPlugin(environment: {
50+
name: string
51+
type: 'client' | 'server'
52+
}): PluginOption {
53+
// in server environments, we don't transform middleware calls
54+
const transformCodeFilter =
55+
environment.type === 'client'
56+
? [/\.\s*handler\(/, /\.\s*createMiddleware\(\)/]
57+
: [/\.\s*handler\(/]
7458

59+
return {
60+
name: `tanstack-start-core::server-fn:${environment.name}`,
61+
enforce: 'pre',
7562
applyToEnvironment(env) {
76-
return [
77-
VITE_ENVIRONMENT_NAMES.client,
78-
VITE_ENVIRONMENT_NAMES.server,
79-
].includes(env.name as ViteEnvironmentNames)
63+
return env.name === environment.name
8064
},
8165
transform: {
8266
filter: {
@@ -85,32 +69,18 @@ export function createServerFnPlugin(opts: {
8569
include: TRANSFORM_ID_REGEX,
8670
},
8771
code: {
88-
// TODO apply this plugin with a different filter per environment so that .createMiddleware() calls are not scanned in server env
89-
// only scan files that mention `.handler(` | `.createMiddleware()`
90-
include: [/\.\s*handler\(/, /\.\s*createMiddleware\(\)/],
72+
include: transformCodeFilter,
9173
},
9274
},
9375
async handler(code, id) {
94-
let compiler =
95-
compilers[this.environment.name as ViteEnvironmentNames]
76+
let compiler = compilers[this.environment.name]
9677
if (!compiler) {
97-
const env =
98-
this.environment.name === VITE_ENVIRONMENT_NAMES.client
99-
? 'client'
100-
: this.environment.name === VITE_ENVIRONMENT_NAMES.server
101-
? 'server'
102-
: (() => {
103-
throw new Error(
104-
`Environment ${this.environment.name} not configured`,
105-
)
106-
})()
107-
10878
compiler = new ServerFnCompiler({
109-
env,
79+
env: environment.type,
11080
directive: opts.directive,
111-
lookupKinds: LookupKindsPerEnv[env],
81+
lookupKinds: LookupKindsPerEnv[environment.type],
11282
lookupConfigurations: getLookupConfigurationsForEnv(
113-
env,
83+
environment.type,
11484
opts.framework,
11585
),
11686
loadModule: async (id: string) => {
@@ -147,7 +117,7 @@ export function createServerFnPlugin(opts: {
147117
return null
148118
},
149119
})
150-
compilers[this.environment.name as ViteEnvironmentNames] = compiler
120+
compilers[this.environment.name] = compiler
151121
}
152122

153123
id = cleanId(id)
@@ -157,8 +127,7 @@ export function createServerFnPlugin(opts: {
157127
},
158128

159129
hotUpdate(ctx) {
160-
const compiler =
161-
compilers[this.environment.name as ViteEnvironmentNames]
130+
const compiler = compilers[this.environment.name]
162131

163132
ctx.modules.forEach((m) => {
164133
if (m.id) {
@@ -173,6 +142,27 @@ export function createServerFnPlugin(opts: {
173142
}
174143
})
175144
},
145+
}
146+
}
147+
148+
return [
149+
...opts.environments.map(perEnvServerFnPlugin),
150+
{
151+
name: 'tanstack-start-core:capture-server-fn-module-lookup',
152+
// we only need this plugin in dev mode
153+
apply: 'serve',
154+
applyToEnvironment(env) {
155+
return !!opts.environments.find((e) => e.name === env.name)
156+
},
157+
transform: {
158+
filter: {
159+
id: new RegExp(`${SERVER_FN_LOOKUP}$`),
160+
},
161+
handler(code, id) {
162+
const compiler = compilers[this.environment.name]
163+
compiler?.ingestModule({ code, id: cleanId(id) })
164+
},
165+
},
176166
},
177167
]
178168
}

packages/start-plugin-core/src/plugin.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface TanStackStartVitePluginCoreOptions {
3939
ssr?: {
4040
getServerFnById?: string
4141
}
42+
providerEnv?: string
4243
}
4344
}
4445

@@ -105,6 +106,19 @@ export function TanStackStartVitePluginCore(
105106
return bundle
106107
}
107108

109+
const environments: Array<{ name: string; type: 'client' | 'server' }> = [
110+
{ name: VITE_ENVIRONMENT_NAMES.client, type: 'client' },
111+
{ name: VITE_ENVIRONMENT_NAMES.server, type: 'server' },
112+
]
113+
if (
114+
corePluginOpts.serverFn?.providerEnv &&
115+
!environments.find((e) => e.name === corePluginOpts.serverFn?.providerEnv)
116+
) {
117+
environments.push({
118+
name: corePluginOpts.serverFn.providerEnv,
119+
type: 'server',
120+
})
121+
}
108122
return [
109123
{
110124
name: 'tanstack-start-core:config',
@@ -341,8 +355,12 @@ export function TanStackStartVitePluginCore(
341355
},
342356
tanStackStartRouter(startPluginOpts, getConfig, corePluginOpts),
343357
// N.B. TanStackStartCompilerPlugin must be before the TanStackServerFnPlugin
344-
startCompilerPlugin(corePluginOpts.framework),
345-
createServerFnPlugin({ framework: corePluginOpts.framework, directive }),
358+
startCompilerPlugin({ framework: corePluginOpts.framework, environments }),
359+
createServerFnPlugin({
360+
framework: corePluginOpts.framework,
361+
directive,
362+
environments,
363+
}),
346364

347365
TanStackServerFnPlugin({
348366
// This is the ID that will be available to look up and import
@@ -371,7 +389,8 @@ export function TanStackStartVitePluginCore(
371389
getRuntimeCode: () =>
372390
`import { createServerRpc } from '@tanstack/${corePluginOpts.framework}-start/server-rpc'`,
373391
replacer: (d) => `createServerRpc('${d.functionId}', ${d.fn})`,
374-
envName: VITE_ENVIRONMENT_NAMES.server,
392+
envName:
393+
corePluginOpts.serverFn?.providerEnv || VITE_ENVIRONMENT_NAMES.server,
375394
},
376395
}),
377396
loadEnvPlugin(),

packages/start-plugin-core/src/start-compiler-plugin/plugin.ts

Lines changed: 67 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ import { VIRTUAL_MODULES } from '@tanstack/start-server-core'
66
import { normalizePath } from 'vite'
77
import path from 'pathe'
88
import { makeIdFiltersToMatchWithQuery } from '@rolldown/pluginutils'
9-
import { TRANSFORM_ID_REGEX, VITE_ENVIRONMENT_NAMES } from '../constants'
9+
import { TRANSFORM_ID_REGEX } from '../constants'
1010
import { compileStartOutputFactory } from './compilers'
1111
import { transformFuncs } from './constants'
12-
import type { ViteEnvironmentNames } from '../constants'
13-
import type { Plugin } from 'vite'
12+
import type { Plugin, PluginOption } from 'vite'
1413
import type { CompileStartFrameworkOptions } from './compilers'
1514

1615
const debug =
@@ -36,82 +35,77 @@ function resolvePackage(packageName: string): string {
3635
return pkgRoot
3736
}
3837

39-
export function startCompilerPlugin(
40-
framework: CompileStartFrameworkOptions,
41-
): Plugin {
42-
const compileStartOutput = compileStartOutputFactory(framework)
43-
44-
return {
45-
name: 'tanstack-start-core:compiler',
46-
enforce: 'pre',
47-
applyToEnvironment(env) {
48-
return [
49-
VITE_ENVIRONMENT_NAMES.client,
50-
VITE_ENVIRONMENT_NAMES.server,
51-
].includes(env.name as ViteEnvironmentNames)
52-
},
53-
transform: {
54-
filter: {
55-
code: tokenRegex,
56-
id: {
57-
include: TRANSFORM_ID_REGEX,
58-
exclude: [
59-
VIRTUAL_MODULES.serverFnManifest,
60-
// N.B. the following files either just re-export or provide the runtime implementation of those functions
61-
// we do not want to include them in the transformation
62-
// however, those packages (especially start-client-core ATM) also USE these functions
63-
// (namely `createIsomorphicFn` in `packages/start-client-core/src/getRouterInstance.ts`) and thus need to be transformed
64-
...makeIdFiltersToMatchWithQuery([
65-
...resolveRuntimeFiles({
66-
package: '@tanstack/start-client-core',
67-
files: [
68-
'index.js',
69-
'createIsomorphicFn.js',
70-
'envOnly.js',
71-
'serverFnFetcher.js',
72-
'createStart.js',
73-
'createMiddleware.js',
74-
],
75-
}),
76-
...resolveRuntimeFiles({
77-
package: '@tanstack/start-server-core',
78-
files: ['index.js', 'server-functions-handler.js'],
79-
}),
80-
]),
38+
const transformFilter = {
39+
code: tokenRegex,
40+
id: {
41+
include: TRANSFORM_ID_REGEX,
42+
exclude: [
43+
VIRTUAL_MODULES.serverFnManifest,
44+
// N.B. the following files either just re-export or provide the runtime implementation of those functions
45+
// we do not want to include them in the transformation
46+
// however, those packages (especially start-client-core ATM) also USE these functions
47+
// (namely `createIsomorphicFn` in `packages/start-client-core/src/getRouterInstance.ts`) and thus need to be transformed
48+
...makeIdFiltersToMatchWithQuery([
49+
...resolveRuntimeFiles({
50+
package: '@tanstack/start-client-core',
51+
files: [
52+
'index.js',
53+
'createIsomorphicFn.js',
54+
'envOnly.js',
55+
'serverFnFetcher.js',
56+
'createStart.js',
57+
'createMiddleware.js',
8158
],
82-
},
83-
},
84-
handler(code, id) {
85-
const env =
86-
this.environment.name === VITE_ENVIRONMENT_NAMES.client
87-
? 'client'
88-
: this.environment.name === VITE_ENVIRONMENT_NAMES.server
89-
? 'server'
90-
: (() => {
91-
throw new Error(
92-
`Environment ${this.environment.name} not configured`,
93-
)
94-
})()
59+
}),
60+
...resolveRuntimeFiles({
61+
package: '@tanstack/start-server-core',
62+
files: ['index.js', 'server-functions-handler.js'],
63+
}),
64+
]),
65+
],
66+
},
67+
}
9568

96-
const url = pathToFileURL(id)
97-
url.searchParams.delete('v')
98-
id = fileURLToPath(url).replace(/\\/g, '/')
69+
export function startCompilerPlugin(opts: {
70+
framework: CompileStartFrameworkOptions
71+
environments: Array<{ name: string; type: 'client' | 'server' }>
72+
}): PluginOption {
73+
const compileStartOutput = compileStartOutputFactory(opts.framework)
9974

100-
if (debug) console.info(`${env} Compiling Start: `, id)
75+
function perEnvCompilerPlugin(environment: {
76+
name: string
77+
type: 'client' | 'server'
78+
}): Plugin {
79+
return {
80+
name: `tanstack-start-core:compiler:${environment.name}`,
81+
enforce: 'pre',
82+
applyToEnvironment(env) {
83+
return env.name === environment.name
84+
},
85+
transform: {
86+
filter: transformFilter,
87+
handler(code, id) {
88+
const url = pathToFileURL(id)
89+
url.searchParams.delete('v')
90+
id = fileURLToPath(url).replace(/\\/g, '/')
91+
92+
if (debug) console.info(`${environment.name} Compiling Start: `, id)
10193

102-
const compiled = compileStartOutput({
103-
code,
104-
filename: id,
105-
env,
106-
})
94+
const compiled = compileStartOutput({
95+
code,
96+
filename: id,
97+
env: environment.type,
98+
})
10799

108-
if (debug) {
109-
logDiff(code, compiled.code)
110-
console.log('Output:\n', compiled.code + '\n\n')
111-
}
100+
if (debug) {
101+
logDiff(code, compiled.code)
102+
console.log('Output:\n', compiled.code + '\n\n')
103+
}
112104

113-
return compiled
105+
return compiled
106+
},
114107
},
115-
},
108+
}
116109
}
110+
return opts.environments.map(perEnvCompilerPlugin)
117111
}

0 commit comments

Comments
 (0)