From 09aef829298b29fb016b0aa7cf9aad7826c24a37 Mon Sep 17 00:00:00 2001 From: Manuel Schiller Date: Sat, 20 Dec 2025 23:22:49 +0100 Subject: [PATCH 1/2] fix: correct compiler plugin order, only handle createMiddlware in a single plugin fixes #5381 --- .../server-functions/src/routeTree.gen.ts | 21 +++++++ .../routes/server-fn-in-client-only-fn.tsx | 63 +++++++++++++++++++ .../tests/server-functions.spec.ts | 37 ----------- .../handleCreateMiddleware.ts | 30 ++++----- packages/start-plugin-core/src/plugin.ts | 10 ++- .../src/start-compiler-plugin/compilers.ts | 11 ---- .../src/start-compiler-plugin/constants.ts | 1 - .../createMiddleware.test.ts | 16 +++-- .../client/create-function-middleware.ts | 1 - .../client/createMiddlewareDestructured.tsx | 13 ++++ .../createMiddlewareDestructuredRename.tsx | 13 ++++ .../client/createMiddlewareStarImport.tsx | 13 ++++ .../client/createMiddlewareValidator.tsx | 1 - .../snapshots/server/createStart.tsx | 30 --------- .../test-files/create-function-middleware.ts | 0 .../createMiddlewareDestructured.tsx | 0 .../createMiddlewareDestructuredRename.tsx | 0 .../test-files/createMiddlewareStarImport.tsx | 0 .../test-files/createMiddlewareValidator.tsx | 0 .../createMiddleware.test.ts | 37 ----------- .../client/createMiddlewareDestructured.tsx | 24 ------- .../createMiddlewareDestructuredRename.tsx | 24 ------- .../client/createMiddlewareStarImport.tsx | 24 ------- .../snapshots/client/factory.ts | 15 ----- .../server/create-function-middleware.ts | 13 ---- .../server/createMiddlewareDestructured.tsx | 36 ----------- .../createMiddlewareDestructuredRename.tsx | 36 ----------- .../server/createMiddlewareStarImport.tsx | 38 ----------- .../server/createMiddlewareValidator.tsx | 7 --- .../snapshots/server/factory.ts | 39 ------------ .../test-files/factory.ts | 38 ----------- 31 files changed, 149 insertions(+), 442 deletions(-) create mode 100644 e2e/react-start/server-functions/src/routes/server-fn-in-client-only-fn.tsx rename packages/start-plugin-core/tests/{createMiddleware-start-compiler-plugin => createMiddleware-create-server-fn-plugin}/snapshots/client/create-function-middleware.ts (83%) create mode 100644 packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructured.tsx create mode 100644 packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx create mode 100644 packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareStarImport.tsx rename packages/start-plugin-core/tests/{createMiddleware-start-compiler-plugin => createMiddleware-create-server-fn-plugin}/snapshots/client/createMiddlewareValidator.tsx (82%) delete mode 100644 packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/server/createStart.tsx rename packages/start-plugin-core/tests/{createMiddleware-start-compiler-plugin => createMiddleware-create-server-fn-plugin}/test-files/create-function-middleware.ts (100%) rename packages/start-plugin-core/tests/{createMiddleware-start-compiler-plugin => createMiddleware-create-server-fn-plugin}/test-files/createMiddlewareDestructured.tsx (100%) rename packages/start-plugin-core/tests/{createMiddleware-start-compiler-plugin => createMiddleware-create-server-fn-plugin}/test-files/createMiddlewareDestructuredRename.tsx (100%) rename packages/start-plugin-core/tests/{createMiddleware-start-compiler-plugin => createMiddleware-create-server-fn-plugin}/test-files/createMiddlewareStarImport.tsx (100%) rename packages/start-plugin-core/tests/{createMiddleware-start-compiler-plugin => createMiddleware-create-server-fn-plugin}/test-files/createMiddlewareValidator.tsx (100%) delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/createMiddleware.test.ts delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructured.tsx delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareStarImport.tsx delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/factory.ts delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/create-function-middleware.ts delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructured.tsx delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructuredRename.tsx delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareStarImport.tsx delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareValidator.tsx delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/factory.ts delete mode 100644 packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/factory.ts diff --git a/e2e/react-start/server-functions/src/routeTree.gen.ts b/e2e/react-start/server-functions/src/routeTree.gen.ts index c78224d894a..0f14d59ad7b 100644 --- a/e2e/react-start/server-functions/src/routeTree.gen.ts +++ b/e2e/react-start/server-functions/src/routeTree.gen.ts @@ -12,6 +12,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as SubmitPostFormdataRouteImport } from './routes/submit-post-formdata' import { Route as StatusRouteImport } from './routes/status' import { Route as ServerOnlyFnRouteImport } from './routes/server-only-fn' +import { Route as ServerFnInClientOnlyFnRouteImport } from './routes/server-fn-in-client-only-fn' import { Route as SerializeFormDataRouteImport } from './routes/serialize-form-data' import { Route as ReturnNullRouteImport } from './routes/return-null' import { Route as RawResponseRouteImport } from './routes/raw-response' @@ -55,6 +56,11 @@ const ServerOnlyFnRoute = ServerOnlyFnRouteImport.update({ path: '/server-only-fn', getParentRoute: () => rootRouteImport, } as any) +const ServerFnInClientOnlyFnRoute = ServerFnInClientOnlyFnRouteImport.update({ + id: '/server-fn-in-client-only-fn', + path: '/server-fn-in-client-only-fn', + getParentRoute: () => rootRouteImport, +} as any) const SerializeFormDataRoute = SerializeFormDataRouteImport.update({ id: '/serialize-form-data', path: '/serialize-form-data', @@ -206,6 +212,7 @@ export interface FileRoutesByFullPath { '/raw-response': typeof RawResponseRoute '/return-null': typeof ReturnNullRoute '/serialize-form-data': typeof SerializeFormDataRoute + '/server-fn-in-client-only-fn': typeof ServerFnInClientOnlyFnRoute '/server-only-fn': typeof ServerOnlyFnRoute '/status': typeof StatusRoute '/submit-post-formdata': typeof SubmitPostFormdataRoute @@ -238,6 +245,7 @@ export interface FileRoutesByTo { '/raw-response': typeof RawResponseRoute '/return-null': typeof ReturnNullRoute '/serialize-form-data': typeof SerializeFormDataRoute + '/server-fn-in-client-only-fn': typeof ServerFnInClientOnlyFnRoute '/server-only-fn': typeof ServerOnlyFnRoute '/status': typeof StatusRoute '/submit-post-formdata': typeof SubmitPostFormdataRoute @@ -271,6 +279,7 @@ export interface FileRoutesById { '/raw-response': typeof RawResponseRoute '/return-null': typeof ReturnNullRoute '/serialize-form-data': typeof SerializeFormDataRoute + '/server-fn-in-client-only-fn': typeof ServerFnInClientOnlyFnRoute '/server-only-fn': typeof ServerOnlyFnRoute '/status': typeof StatusRoute '/submit-post-formdata': typeof SubmitPostFormdataRoute @@ -305,6 +314,7 @@ export interface FileRouteTypes { | '/raw-response' | '/return-null' | '/serialize-form-data' + | '/server-fn-in-client-only-fn' | '/server-only-fn' | '/status' | '/submit-post-formdata' @@ -337,6 +347,7 @@ export interface FileRouteTypes { | '/raw-response' | '/return-null' | '/serialize-form-data' + | '/server-fn-in-client-only-fn' | '/server-only-fn' | '/status' | '/submit-post-formdata' @@ -369,6 +380,7 @@ export interface FileRouteTypes { | '/raw-response' | '/return-null' | '/serialize-form-data' + | '/server-fn-in-client-only-fn' | '/server-only-fn' | '/status' | '/submit-post-formdata' @@ -402,6 +414,7 @@ export interface RootRouteChildren { RawResponseRoute: typeof RawResponseRoute ReturnNullRoute: typeof ReturnNullRoute SerializeFormDataRoute: typeof SerializeFormDataRoute + ServerFnInClientOnlyFnRoute: typeof ServerFnInClientOnlyFnRoute ServerOnlyFnRoute: typeof ServerOnlyFnRoute StatusRoute: typeof StatusRoute SubmitPostFormdataRoute: typeof SubmitPostFormdataRoute @@ -446,6 +459,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ServerOnlyFnRouteImport parentRoute: typeof rootRouteImport } + '/server-fn-in-client-only-fn': { + id: '/server-fn-in-client-only-fn' + path: '/server-fn-in-client-only-fn' + fullPath: '/server-fn-in-client-only-fn' + preLoaderRoute: typeof ServerFnInClientOnlyFnRouteImport + parentRoute: typeof rootRouteImport + } '/serialize-form-data': { id: '/serialize-form-data' path: '/serialize-form-data' @@ -650,6 +670,7 @@ const rootRouteChildren: RootRouteChildren = { RawResponseRoute: RawResponseRoute, ReturnNullRoute: ReturnNullRoute, SerializeFormDataRoute: SerializeFormDataRoute, + ServerFnInClientOnlyFnRoute: ServerFnInClientOnlyFnRoute, ServerOnlyFnRoute: ServerOnlyFnRoute, StatusRoute: StatusRoute, SubmitPostFormdataRoute: SubmitPostFormdataRoute, diff --git a/e2e/react-start/server-functions/src/routes/server-fn-in-client-only-fn.tsx b/e2e/react-start/server-functions/src/routes/server-fn-in-client-only-fn.tsx new file mode 100644 index 00000000000..50db9cdaa8a --- /dev/null +++ b/e2e/react-start/server-functions/src/routes/server-fn-in-client-only-fn.tsx @@ -0,0 +1,63 @@ +import { createFileRoute } from '@tanstack/react-router' +import { createClientOnlyFn, createServerFn } from '@tanstack/react-start' +import { useState } from 'react' + +// Server function that should be callable from client-only function +const serverFn = createServerFn().handler(() => { + return 'server function executed successfully' +}) + +// Client-only function that calls the server function +// This scenario currently fails due to compilation order issues: +// 1. createClientOnlyFn is processed first, removing the serverFn reference on server +// 2. Dead code elimination removes the serverFn entirely +// 3. The server function is never registered, causing runtime errors +const clientOnlyFnThatCallsServerFn = createClientOnlyFn(async () => { + const result = await serverFn() + return 'client-only fn received: ' + result +}) + +export const Route = createFileRoute('/server-fn-in-client-only-fn')({ + component: RouteComponent, +}) + +function RouteComponent() { + const [result, setResult] = useState(null) + const [error, setError] = useState(null) + + async function handleClick() { + try { + const res = await clientOnlyFnThatCallsServerFn() + setResult(res) + setError(null) + } catch (e) { + setResult(null) + setError(e instanceof Error ? e.message : String(e)) + } + } + + return ( +
+

Server Function in Client-Only Function Test

+

+ This test verifies that a server function can be called from inside a + createClientOnlyFn. +

+ +
+        client-only fn received: server function executed successfully
+      
+ {result && ( +
{result}
+ )} + {error && ( +
{error}
+ )} +
+ ) +} diff --git a/e2e/react-start/server-functions/tests/server-functions.spec.ts b/e2e/react-start/server-functions/tests/server-functions.spec.ts index a7ad7026f58..208ef2519bc 100644 --- a/e2e/react-start/server-functions/tests/server-functions.spec.ts +++ b/e2e/react-start/server-functions/tests/server-functions.spec.ts @@ -543,40 +543,3 @@ test('redirect in server function called in query during SSR', async ({ await expect(page.getByTestId('redirect-target-ssr')).toBeVisible() expect(page.url()).toContain('/redirect-test-ssr/target') }) - -test('server function called only from server (not client) works correctly', async ({ - page, -}) => { - await page.goto('/server-only-fn') - - await page.waitForLoadState('networkidle') - - const expected = - (await page.getByTestId('expected-server-only-fn-result').textContent()) || - '' - expect(expected).not.toBe('') - - await page.getByTestId('test-server-only-fn-btn').click() - await page.waitForLoadState('networkidle') - - await expect(page.getByTestId('server-only-fn-result')).toContainText( - expected, - ) -}) - -test.use({ - whitelistErrors: [ - /Failed to load resource: the server responded with a status of 500/, - ], -}) -test('server function called only from server (not client) cannot be called from the client', async ({ - page, -}) => { - await page.goto('/server-only-fn') - await page.waitForLoadState('networkidle') - - await page.getByTestId('call-server-fn-from-client-btn').click() - await expect( - page.getByTestId('call-server-fn-from-client-result'), - ).toContainText('error') -}) diff --git a/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts b/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts index 1da0bd6969c..84f418bccc0 100644 --- a/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts +++ b/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts @@ -8,14 +8,11 @@ export function handleCreateMiddleware( env: 'client' | 'server' }, ) { + if (opts.env === 'server') { + throw new Error('handleCreateMiddleware should not be called on the server') + } const rootCallExpression = getRootCallExpression(path) - // if (debug) - // console.info( - // 'Handling createMiddleware call expression:', - // rootCallExpression.toString(), - // ) - const callExpressionPaths = { middleware: null as babel.NodePath | null, inputValidator: null as babel.NodePath | null, @@ -51,15 +48,13 @@ export function handleCreateMiddleware( ) } - // If we're on the client, remove the validator call expression - if (opts.env === 'client') { - if ( - t.isMemberExpression(callExpressionPaths.inputValidator.node.callee) - ) { - callExpressionPaths.inputValidator.replaceWith( - callExpressionPaths.inputValidator.node.callee.object, - ) - } + // remove the validator call expression + if ( + t.isMemberExpression(callExpressionPaths.inputValidator.node.callee) + ) { + callExpressionPaths.inputValidator.replaceWith( + callExpressionPaths.inputValidator.node.callee.object, + ) } } @@ -69,10 +64,9 @@ export function handleCreateMiddleware( if ( callExpressionPaths.server && - serverFnPath.node && - opts.env === 'client' + serverFnPath.node ) { - // If we're on the client, remove the server call expression + // remove the server call expression if (t.isMemberExpression(callExpressionPaths.server.node.callee)) { callExpressionPaths.server.replaceWith( callExpressionPaths.server.node.callee.object, diff --git a/packages/start-plugin-core/src/plugin.ts b/packages/start-plugin-core/src/plugin.ts index ee77f77f3c4..1a9a74045f1 100644 --- a/packages/start-plugin-core/src/plugin.ts +++ b/packages/start-plugin-core/src/plugin.ts @@ -385,14 +385,17 @@ export function TanStackStartVitePluginCore( }, }, tanStackStartRouter(startPluginOpts, getConfig, corePluginOpts), - // N.B. TanStackStartCompilerPlugin must be before the TanStackServerFnPlugin - startCompilerPlugin({ framework: corePluginOpts.framework, environments }), + // N.B. Server function plugins must run BEFORE startCompilerPlugin because: + // 1. createServerFnPlugin transforms createServerFn().handler() to inject 'use server' directive + // 2. TanStackServerFnPlugin extracts 'use server' functions and registers them in the manifest + // 3. startCompilerPlugin handles createClientOnlyFn/createServerOnlyFn and runs DCE + // If startCompilerPlugin runs first, DCE may remove server function code before it can be registered + // (e.g., when a server function is only referenced inside a createClientOnlyFn callback) createServerFnPlugin({ framework: corePluginOpts.framework, directive, environments, }), - TanStackServerFnPlugin({ // This is the ID that will be available to look up and import // our server function manifest and resolve its module @@ -428,6 +431,7 @@ export function TanStackStartVitePluginCore( envName: serverFnProviderEnv, }, }), + startCompilerPlugin({ framework: corePluginOpts.framework, environments }), loadEnvPlugin(), startManifestPlugin({ getClientBundle: () => getBundle(VITE_ENVIRONMENT_NAMES.client), diff --git a/packages/start-plugin-core/src/start-compiler-plugin/compilers.ts b/packages/start-plugin-core/src/start-compiler-plugin/compilers.ts index a23583574c0..df80fbf1608 100644 --- a/packages/start-plugin-core/src/start-compiler-plugin/compilers.ts +++ b/packages/start-plugin-core/src/start-compiler-plugin/compilers.ts @@ -6,7 +6,6 @@ import { findReferencedIdentifiers, } from 'babel-dead-code-elimination' import { generateFromAst, parseAst } from '@tanstack/router-utils' -import { handleCreateMiddleware } from '../create-server-fn-plugin/handleCreateMiddleware' import { transformFuncs } from './constants' import { handleCreateIsomorphicFnCallExpression } from './isomorphicFn' import { @@ -41,16 +40,6 @@ export function compileStartOutputFactory( }, } - // createMiddleware only performs modifications in the client environment - // so we can avoid executing this on the server - if (opts.env === 'client') { - identifiers.createMiddleware = { - name: 'createMiddleware', - handleCallExpression: handleCreateMiddleware, - paths: [], - } - } - const ast = parseAst(opts) const doDce = opts.dce ?? true diff --git a/packages/start-plugin-core/src/start-compiler-plugin/constants.ts b/packages/start-plugin-core/src/start-compiler-plugin/constants.ts index 08f171d1e97..d5416a2c03e 100644 --- a/packages/start-plugin-core/src/start-compiler-plugin/constants.ts +++ b/packages/start-plugin-core/src/start-compiler-plugin/constants.ts @@ -2,5 +2,4 @@ export const transformFuncs = [ 'createServerOnlyFn', 'createClientOnlyFn', 'createIsomorphicFn', - 'createMiddleware', ] as const diff --git a/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/createMiddleware.test.ts b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/createMiddleware.test.ts index 06d141c5a2a..337edffecf9 100644 --- a/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/createMiddleware.test.ts +++ b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/createMiddleware.test.ts @@ -50,15 +50,13 @@ describe('createMiddleware compiles correctly', async () => { ) const code = file.toString() - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const result = await compile({ env, code, id: filename }) + // Note: Middleware compilation only happens on the client + test(`should compile for ${filename} client`, async () => { + const result = await compile({ env: 'client', code, id: filename }) - await expect(result!.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) + await expect(result!.code).toMatchFileSnapshot( + `./snapshots/client/${filename}`, + ) + }) }) }) diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/create-function-middleware.ts b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/create-function-middleware.ts similarity index 83% rename from packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/create-function-middleware.ts rename to packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/create-function-middleware.ts index 7f39c06036f..b37e25e4986 100644 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/create-function-middleware.ts +++ b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/create-function-middleware.ts @@ -1,5 +1,4 @@ import { createMiddleware } from '@tanstack/react-start'; -import { foo } from '@some/lib'; export const fnMw = createMiddleware({ type: 'function' }).client(() => { diff --git a/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructured.tsx new file mode 100644 index 00000000000..b5cf588a1fc --- /dev/null +++ b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructured.tsx @@ -0,0 +1,13 @@ +import { createMiddleware } from '@tanstack/react-start'; +export const withUseServer = createMiddleware({ + id: 'test' +}); +export const withoutUseServer = createMiddleware({ + id: 'test' +}); +export const withVariable = createMiddleware({ + id: 'test' +}); +export const withZodValidator = createMiddleware({ + id: 'test' +}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx new file mode 100644 index 00000000000..ee061797034 --- /dev/null +++ b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx @@ -0,0 +1,13 @@ +import { createMiddleware as middlewareFn } from '@tanstack/react-start'; +export const withUseServer = middlewareFn({ + id: 'test' +}); +export const withoutUseServer = middlewareFn({ + id: 'test' +}); +export const withVariable = middlewareFn({ + id: 'test' +}); +export const withZodValidator = middlewareFn({ + id: 'test' +}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareStarImport.tsx new file mode 100644 index 00000000000..6f2f40a2a32 --- /dev/null +++ b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareStarImport.tsx @@ -0,0 +1,13 @@ +import * as TanStackStart from '@tanstack/react-start'; +export const withUseServer = TanStackStart.createMiddleware({ + id: 'test' +}); +export const withoutUseServer = TanStackStart.createMiddleware({ + id: 'test' +}); +export const withVariable = TanStackStart.createMiddleware({ + id: 'test' +}); +export const withZodValidator = TanStackStart.createMiddleware({ + id: 'test' +}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareValidator.tsx similarity index 82% rename from packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareValidator.tsx index 280dc3a0670..3b1beac2c03 100644 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareValidator.tsx +++ b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/client/createMiddlewareValidator.tsx @@ -1,5 +1,4 @@ import { createMiddleware } from '@tanstack/react-start'; -import { z } from 'zod'; export const withUseServer = createMiddleware({ id: 'test' }); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/server/createStart.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/server/createStart.tsx deleted file mode 100644 index 3d8e28ea5a8..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/snapshots/server/createStart.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { createStart } from '@tanstack/react-start'; -export const startInstance = createStart(() => {}); -export const serverFnMw = startInstance.createMiddleware({ - type: 'function' -}).server(({ - next -}) => { - console.log('server mw'); - return next({ - context: { - admin: 'admin' - } - }); -}).client(({ - next -}) => { - console.log('client mw'); - return next(); -}); -export const requestMw = startInstance.createMiddleware({ - type: 'request' -}).server(({ - next -}) => { - return next({ - context: { - requestMw: 'yes' - } - }); -}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/create-function-middleware.ts b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/create-function-middleware.ts similarity index 100% rename from packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/create-function-middleware.ts rename to packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/create-function-middleware.ts diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareDestructured.tsx similarity index 100% rename from packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareDestructured.tsx rename to packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareDestructured.tsx diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareDestructuredRename.tsx similarity index 100% rename from packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareDestructuredRename.tsx rename to packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareDestructuredRename.tsx diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareStarImport.tsx similarity index 100% rename from packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareStarImport.tsx rename to packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareStarImport.tsx diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareValidator.tsx similarity index 100% rename from packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware-create-server-fn-plugin/test-files/createMiddlewareValidator.tsx diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/createMiddleware.test.ts b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/createMiddleware.test.ts deleted file mode 100644 index b1c2cb3c414..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/createMiddleware.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { readFile, readdir } from 'node:fs/promises' -import path from 'node:path' -import { describe, expect, test } from 'vitest' -import { compileStartOutputFactory } from '../../src/start-compiler-plugin/compilers' - -const compileStartOutput = compileStartOutputFactory('react') - -async function getFilenames() { - return await readdir(path.resolve(import.meta.dirname, './test-files')) -} - -describe('createMiddleware compiles correctly', async () => { - const filenames = await getFilenames() - - describe.each(filenames)('should handle "%s"', async (filename) => { - const file = await readFile( - path.resolve(import.meta.dirname, `./test-files/${filename}`), - ) - const code = file.toString() - - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const compiledResult = compileStartOutput({ - env, - code, - filename, - dce: false, - }) - - await expect(compiledResult.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) - }) -}) diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructured.tsx deleted file mode 100644 index c513c274c5f..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createMiddleware } from '@tanstack/react-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}); -export const withoutUseServer = createMiddleware({ - id: 'test' -}); -export const withVariable = createMiddleware({ - id: 'test' -}); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 4ab09a99335..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/react-start'; -import { z } from 'zod'; -export const withUseServer = middlewareFn({ - id: 'test' -}); -export const withoutUseServer = middlewareFn({ - id: 'test' -}); -export const withVariable = middlewareFn({ - id: 'test' -}); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = middlewareFn({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareStarImport.tsx deleted file mode 100644 index 7253e9510c9..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as TanStackStart from '@tanstack/react-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test' -}); -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test' -}); -export const withVariable = TanStackStart.createMiddleware({ - id: 'test' -}); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/factory.ts b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/factory.ts deleted file mode 100644 index f5e43fb22ad..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/client/factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createMiddleware } from '@tanstack/react-start'; -import { getCookie } from '@tanstack/react-start/server'; -interface AuthMiddlewareOptions { - allowUnauthenticated?: boolean; -} -interface AuthContext { - session: { - id: string; - } | null; -} -export const createAuthMiddleware = (opts: AuthMiddlewareOptions = { - allowUnauthenticated: false -}) => createMiddleware({ - type: 'function' -}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/create-function-middleware.ts b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/create-function-middleware.ts deleted file mode 100644 index ee74b628fb8..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/create-function-middleware.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createMiddleware } from '@tanstack/react-start'; -import { foo } from '@some/lib'; -export const fnMw = createMiddleware({ - type: 'function' -}).server(({ - next -}) => { - console.log('server'); - foo(); - return next(); -}).client(() => { - console.log('client'); -}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructured.tsx deleted file mode 100644 index 8e1ddd89507..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { createMiddleware } from '@tanstack/react-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}).server(async function () { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = createMiddleware({ - id: 'test' -}).server(async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = createMiddleware({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createMiddleware({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 210d8df8e68..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/react-start'; -import { z } from 'zod'; -export const withUseServer = middlewareFn({ - id: 'test' -}).server(async function () { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = middlewareFn({ - id: 'test' -}).server(async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = middlewareFn({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = middlewareFn({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareStarImport.tsx deleted file mode 100644 index 13e09f0ec2d..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as TanStackStart from '@tanstack/react-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test' -}).server(async function () { - 'use server'; - - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test' -}).server(async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = TanStackStart.createMiddleware({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareValidator.tsx deleted file mode 100644 index a530254087e..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/createMiddlewareValidator.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { createMiddleware } from '@tanstack/react-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}).inputValidator(z.number()).server(({ - input -}) => input + 1); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/factory.ts b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/factory.ts deleted file mode 100644 index 5b1c2f3709c..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/snapshots/server/factory.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { createMiddleware } from '@tanstack/react-start'; -import { getCookie } from '@tanstack/react-start/server'; -interface AuthMiddlewareOptions { - allowUnauthenticated?: boolean; -} -interface AuthContext { - session: { - id: string; - } | null; -} -export const createAuthMiddleware = (opts: AuthMiddlewareOptions = { - allowUnauthenticated: false -}) => createMiddleware({ - type: 'function' -}).server(({ - next -}) => { - const token = getCookie('session'); - if (!token) { - if (!opts.allowUnauthenticated) { - throw new Error('Unauthorized'); - } - return next({ - context: { - session: null - } - }); - } - - // ... token validation should be here - - return next({ - context: { - session: { - id: (Math.random() * 1000).toString() - } - } - }); -}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/factory.ts b/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/factory.ts deleted file mode 100644 index 4abd567628b..00000000000 --- a/packages/start-plugin-core/tests/createMiddleware-start-compiler-plugin/test-files/factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { createMiddleware } from '@tanstack/react-start' -import { getCookie } from '@tanstack/react-start/server' - -interface AuthMiddlewareOptions { - allowUnauthenticated?: boolean -} - -interface AuthContext { - session: { id: string } | null -} - -export const createAuthMiddleware = ( - opts: AuthMiddlewareOptions = { allowUnauthenticated: false }, -) => - createMiddleware({ type: 'function' }).server(({ next }) => { - const token = getCookie('session') - if (!token) { - if (!opts.allowUnauthenticated) { - throw new Error('Unauthorized') - } - - return next({ - context: { - session: null, - }, - }) - } - - // ... token validation should be here - - return next({ - context: { - session: { - id: (Math.random() * 1000).toString(), - }, - }, - }) - }) From 2de05a0c9c5dc82bcc42789382d78697497d9714 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 20 Dec 2025 22:38:37 +0000 Subject: [PATCH 2/2] ci: apply automated fixes --- .../create-server-fn-plugin/handleCreateMiddleware.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts b/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts index 84f418bccc0..60fea360bc2 100644 --- a/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts +++ b/packages/start-plugin-core/src/create-server-fn-plugin/handleCreateMiddleware.ts @@ -49,9 +49,7 @@ export function handleCreateMiddleware( } // remove the validator call expression - if ( - t.isMemberExpression(callExpressionPaths.inputValidator.node.callee) - ) { + if (t.isMemberExpression(callExpressionPaths.inputValidator.node.callee)) { callExpressionPaths.inputValidator.replaceWith( callExpressionPaths.inputValidator.node.callee.object, ) @@ -62,10 +60,7 @@ export function handleCreateMiddleware( 'arguments.0', ) as babel.NodePath - if ( - callExpressionPaths.server && - serverFnPath.node - ) { + if (callExpressionPaths.server && serverFnPath.node) { // remove the server call expression if (t.isMemberExpression(callExpressionPaths.server.node.callee)) { callExpressionPaths.server.replaceWith(