Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions e2e/react-start/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"build:vite": "vite build && tsc --noEmit",
"build:rsbuild": "rsbuild build && tsc --noEmit",
"preview": "vite preview",
"preview:rsbuild": "rsbuild preview",
"start": "node server.js",
"test:e2e:startDummyServer": "node -e 'import(\"./tests/setup/global.setup.ts\").then(m => m.default())' & node -e 'import(\"./tests/setup/waitForDummyServer.ts\").then(m => m.default())'",
"test:e2e:stopDummyServer": "node -e 'import(\"./tests/setup/global.teardown.ts\").then(m => m.default())'",
Expand Down Expand Up @@ -78,6 +79,10 @@
{
"toolchain": "rsbuild",
"mode": "prerender"
},
{
"toolchain": "rsbuild",
"mode": "preview"
}
]
}
Expand Down
8 changes: 7 additions & 1 deletion e2e/react-start/basic/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import packageJson from './package.json' with { type: 'json' }

const mode = process.env.MODE ?? 'ssr'
const toolchain = process.env.E2E_TOOLCHAIN ?? 'vite'
const e2ePortKey = process.env.E2E_PORT_KEY ?? packageJson.name
const distDir = process.env.E2E_DIST_DIR ?? 'dist'

Expand All @@ -24,9 +25,13 @@ const PORT = await getTestServerPort(e2ePortKey)
const START_PORT = await getTestServerPort(`${e2ePortKey}_start`)
const EXTERNAL_PORT = await getDummyServerPort(e2ePortKey)
const baseURL = `http://localhost:${PORT}`
const previewCommand =
toolchain === 'rsbuild'
? `pnpm preview:rsbuild --port ${PORT}`
: `pnpm preview --outDir ${distDir} --port ${PORT}`
const commandByMode =
mode === 'preview'
? `pnpm run test:e2e:startDummyServer && pnpm preview --outDir ${distDir} --port ${PORT}`
? `pnpm run test:e2e:startDummyServer && ${previewCommand}`
: `pnpm run test:e2e:startDummyServer && pnpm start`
/**
* See https://playwright.dev/docs/test-configuration.
Expand All @@ -50,6 +55,7 @@ export default defineConfig({
stdout: 'pipe',
env: {
MODE: mode,
E2E_TOOLCHAIN: toolchain,
VITE_NODE_ENV: 'test',
VITE_EXTERNAL_PORT: String(EXTERNAL_PORT),
VITE_SERVER_PORT: String(PORT),
Expand Down
2 changes: 1 addition & 1 deletion e2e/react-start/custom-server-rsbuild/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import { tanstackStart } from '@tanstack/react-start/plugin/rsbuild'
export default defineConfig({
plugins: [
pluginReact({ splitChunks: false }),
tanstackStart({ rsbuild: { installDevServerMiddleware: false } }),
tanstackStart({ rsbuild: { installServerMiddleware: false } }),
],
})
13 changes: 13 additions & 0 deletions packages/react-start/src/plugin/rsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ import type {
} from '@tanstack/start-plugin-core/rsbuild'
import type { RsbuildPlugin } from '@rsbuild/core'

const reactStartRsbuildEnvironmentOverrides = {
all: {
resolve: {
dedupe: ['react', 'react-dom'],
},
},
} satisfies NonNullable<
TanStackStartRsbuildPluginCoreOptions['rsbuild']
>['environments']

export function tanstackStart(
options?: TanStackStartRsbuildInputConfig & { rsc?: { enabled?: boolean } },
): RsbuildPlugin {
Expand All @@ -20,6 +30,9 @@ export function tanstackStart(
defaultEntryPaths: reactStartDefaultEntryPaths,
providerEnvironmentName: RSBUILD_ENVIRONMENT_NAMES.server,
ssrIsProvider: true,
rsbuild: {
environments: reactStartRsbuildEnvironmentOverrides,
},
}

if (rscEnabled) {
Expand Down
129 changes: 0 additions & 129 deletions packages/start-plugin-core/src/rsbuild/dev-server.ts

This file was deleted.

15 changes: 12 additions & 3 deletions packages/start-plugin-core/src/rsbuild/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
START_MANIFEST_PLACEHOLDER,
registerVirtualModules,
} from './virtual-modules'
import { createServerSetup } from './dev-server'
import { createServerSetup } from './server-middleware'
import { registerClientBuildCapture } from './normalized-client-build'
import { registerRouterPlugins } from './start-router-plugin'
import { postBuildWithRsbuild } from './post-build'
Expand Down Expand Up @@ -142,6 +142,8 @@ export function tanStackStartRsbuild(

const resolvedEntryPlan = configContext.resolveEntries()
const isDev = api.context.action === 'dev'
const isPreview = api.context.action === 'preview'
const shouldInstallServerMiddleware = isDev || isPreview

const entryAliases = createRsbuildResolvedEntryAliases({
entryPaths: resolvedEntryPlan.entryPaths,
Expand Down Expand Up @@ -199,6 +201,10 @@ export function tanStackStartRsbuild(
},
},
server: {
...(rsbuildConfig.server?.printUrls === undefined ||
rsbuildConfig.server.printUrls === true
? { printUrls: ({ urls }: { urls: Array<string> }) => urls }
: {}),
// Rsbuild compression currently treats Node's raw header array
// writeHead form as an object, which corrupts SSR response headers.
compress: false,
Expand All @@ -207,11 +213,14 @@ export function tanStackStartRsbuild(
htmlFallback: false,
// server.setup returned callback runs after built-in middleware
// but BEFORE fallback middleware — the ideal slot for SSR.
...(isDev &&
startPluginOpts.rsbuild?.installDevServerMiddleware !== false
...(shouldInstallServerMiddleware &&
startPluginOpts.rsbuild?.installServerMiddleware !== false
? {
setup: createServerSetup({
serverFnBasePath: serverFnBase,
serverOutputDirectory:
resolvedStartConfig.outputDirectories.server,
publicBase: resolvedStartConfig.basePaths.publicBase,
}),
}
: {}),
Expand Down
2 changes: 1 addition & 1 deletion packages/start-plugin-core/src/rsbuild/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const tanstackStartRsbuildOptionsSchema =
tanstackStartOptionsObjectSchema
.extend({
rsbuild: z
.object({ installDevServerMiddleware: z.boolean().optional() })
.object({ installServerMiddleware: z.boolean().optional() })
.optional(),
Comment on lines 11 to 13
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the old option as a deprecated alias for one release.

This rename is currently a breaking change. Existing configs that still set rsbuild.installDevServerMiddleware will silently re-enable the middleware after upgrade, because only installServerMiddleware is recognized now. Please accept both keys for now and prefer the new one when both are present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/start-plugin-core/src/rsbuild/schema.ts` around lines 11 - 13, The
rsbuild schema currently only accepts installServerMiddleware which breaks
configs using the old installDevServerMiddleware key; update the rsbuild zod
object to accept both installServerMiddleware and installDevServerMiddleware as
optional booleans, then normalize to a single canonical property (prefer
installServerMiddleware when both present) by adding a transform/preprocess so
downstream code uses only installServerMiddleware; mark
installDevServerMiddleware as deprecated in the schema/comments/types so it
remains supported for one release.

})
.optional()
Expand Down
Loading