Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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