From f3658685a5ec846051c72266320dacbe92e04c20 Mon Sep 17 00:00:00 2001 From: sleitor Date: Fri, 20 Mar 2026 10:33:31 +0000 Subject: [PATCH 1/2] fix(start-plugin-core): use duck-type check for RunnableDevEnvironment to avoid dual-package hazard Replace isRunnableDevEnvironment (instanceof-based) with duck-type check 'runner' in serverEnv to avoid false negatives when vite is aliased via pnpm overrides (e.g. vite-plus), which creates a dual-package hazard where two different RunnableDevEnvironment class references exist in memory. The 'runner' property (public getter) is unique to RunnableDevEnvironment and not present on FetchableDevEnvironment or DevEnvironment. Fixes #6982 --- .changeset/fix-6982-duck-type-runnable-dev-env.md | 5 +++++ .../start-plugin-core/src/dev-server-plugin/plugin.ts | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 .changeset/fix-6982-duck-type-runnable-dev-env.md diff --git a/.changeset/fix-6982-duck-type-runnable-dev-env.md b/.changeset/fix-6982-duck-type-runnable-dev-env.md new file mode 100644 index 00000000000..1be9fd558f0 --- /dev/null +++ b/.changeset/fix-6982-duck-type-runnable-dev-env.md @@ -0,0 +1,5 @@ +--- +"@tanstack/start-plugin-core": patch +--- + +fix(start-plugin-core): replace isRunnableDevEnvironment instanceof check with duck-typing to avoid dual-package hazard when vite is aliased (e.g. vite-plus pnpm override) diff --git a/packages/start-plugin-core/src/dev-server-plugin/plugin.ts b/packages/start-plugin-core/src/dev-server-plugin/plugin.ts index d507998109c..cc53bdbfc5f 100644 --- a/packages/start-plugin-core/src/dev-server-plugin/plugin.ts +++ b/packages/start-plugin-core/src/dev-server-plugin/plugin.ts @@ -1,4 +1,3 @@ -import { isRunnableDevEnvironment } from 'vite' import { VIRTUAL_MODULES } from '@tanstack/start-server-core' import { NodeRequest, sendNodeResponse } from 'srvx/node' import { ENTRY_POINTS, VITE_ENVIRONMENT_NAMES } from '../constants' @@ -9,7 +8,7 @@ import { collectDevStyles, normalizeCssModuleCacheKey, } from './dev-styles' -import type { Connect, DevEnvironment, PluginOption } from 'vite' +import type { Connect, DevEnvironment, PluginOption, RunnableDevEnvironment } from 'vite' import type { GetConfigFn } from '../types' export function devServerPlugin({ @@ -145,7 +144,9 @@ export function devServerPlugin({ // do not install middleware if SSR env in case another plugin already did if ( - !isRunnableDevEnvironment(serverEnv) || + // Use duck-type check instead of instanceof/isRunnableDevEnvironment to avoid + // dual-package hazard when vite is aliased (e.g. vite-plus pnpm override) + !('runner' in serverEnv) || // do not check via `isFetchableDevEnvironment` since nitro does implement the `FetchableDevEnvironment` interface but not via inheritance (which this helper checks) 'dispatchFetch' in serverEnv ) { @@ -153,7 +154,7 @@ export function devServerPlugin({ } } - if (!isRunnableDevEnvironment(serverEnv)) { + if (!('runner' in serverEnv)) { throw new Error( 'cannot install vite dev server middleware for TanStack Start since the SSR environment is not a RunnableDevEnvironment', ) @@ -175,7 +176,7 @@ export function devServerPlugin({ * fetch(req: Request): Promise * } */ - const serverEntry = await serverEnv.runner.import( + const serverEntry = await (serverEnv as RunnableDevEnvironment).runner.import( ENTRY_POINTS.server, ) const webRes = await serverEntry['default'].fetch(webReq) From 96eb75d1c8735b5e03637daeb0a553a85a6be2c2 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 10:35:10 +0000 Subject: [PATCH 2/2] ci: apply automated fixes --- .changeset/fix-6982-duck-type-runnable-dev-env.md | 2 +- .../src/dev-server-plugin/plugin.ts | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.changeset/fix-6982-duck-type-runnable-dev-env.md b/.changeset/fix-6982-duck-type-runnable-dev-env.md index 1be9fd558f0..488ba253b43 100644 --- a/.changeset/fix-6982-duck-type-runnable-dev-env.md +++ b/.changeset/fix-6982-duck-type-runnable-dev-env.md @@ -1,5 +1,5 @@ --- -"@tanstack/start-plugin-core": patch +'@tanstack/start-plugin-core': patch --- fix(start-plugin-core): replace isRunnableDevEnvironment instanceof check with duck-typing to avoid dual-package hazard when vite is aliased (e.g. vite-plus pnpm override) diff --git a/packages/start-plugin-core/src/dev-server-plugin/plugin.ts b/packages/start-plugin-core/src/dev-server-plugin/plugin.ts index cc53bdbfc5f..0189b03e6b4 100644 --- a/packages/start-plugin-core/src/dev-server-plugin/plugin.ts +++ b/packages/start-plugin-core/src/dev-server-plugin/plugin.ts @@ -8,7 +8,12 @@ import { collectDevStyles, normalizeCssModuleCacheKey, } from './dev-styles' -import type { Connect, DevEnvironment, PluginOption, RunnableDevEnvironment } from 'vite' +import type { + Connect, + DevEnvironment, + PluginOption, + RunnableDevEnvironment, +} from 'vite' import type { GetConfigFn } from '../types' export function devServerPlugin({ @@ -176,9 +181,9 @@ export function devServerPlugin({ * fetch(req: Request): Promise * } */ - const serverEntry = await (serverEnv as RunnableDevEnvironment).runner.import( - ENTRY_POINTS.server, - ) + const serverEntry = await ( + serverEnv as RunnableDevEnvironment + ).runner.import(ENTRY_POINTS.server) const webRes = await serverEntry['default'].fetch(webReq) return sendNodeResponse(res, webRes)