File tree Expand file tree Collapse file tree 4 files changed +39
-15
lines changed Expand file tree Collapse file tree 4 files changed +39
-15
lines changed Original file line number Diff line number Diff line change 1- import { test } from '@playwright/test'
2- import { setupInlineFixture , useFixture } from './fixture'
1+ import { expect , test } from '@playwright/test'
2+ import { setupInlineFixture , useFixture , type Fixture } from './fixture'
33import { defineStarterTest } from './starter'
44
55test . describe ( ( ) => {
@@ -27,17 +27,31 @@ test.describe(() => {
2727
2828 test . describe ( 'dev-base' , ( ) => {
2929 const f = useFixture ( { root, mode : 'dev' } )
30- defineStarterTest ( {
30+ const f2 : Fixture = {
3131 ...f ,
3232 url : ( url ) => new URL ( url ?? './' , f . url ( './custom-base/' ) ) . href ,
33- } )
33+ }
34+ defineStarterTest ( f2 )
35+ testRequestUrl ( f2 )
3436 } )
3537
3638 test . describe ( 'build-base' , ( ) => {
3739 const f = useFixture ( { root, mode : 'build' } )
38- defineStarterTest ( {
40+ const f2 : Fixture = {
3941 ...f ,
4042 url : ( url ) => new URL ( url ?? './' , f . url ( './custom-base/' ) ) . href ,
41- } )
43+ }
44+ defineStarterTest ( f2 )
45+ testRequestUrl ( f2 )
4246 } )
47+
48+ function testRequestUrl ( f : Fixture ) {
49+ test ( 'request url' , async ( { page } ) => {
50+ await page . goto ( f . url ( ) )
51+ await page . waitForSelector ( '#root' )
52+ await expect ( page . locator ( '.card' ) . nth ( 2 ) ) . toHaveText (
53+ `Request URL: ${ f . url ( ) } ` ,
54+ )
55+ } )
56+ }
4357} )
Original file line number Diff line number Diff line change @@ -58,14 +58,18 @@ export default async function handler(request: Request): Promise<Response> {
5858 // we render RSC stream after handling server function request
5959 // so that new render reflects updated state from server function call
6060 // to achieve single round trip to mutate and fetch from server.
61- const rscPayload : RscPayload = { root : < Root /> , formState, returnValue }
61+ const url = new URL ( request . url )
62+ const rscPayload : RscPayload = {
63+ root : < Root url = { url } /> ,
64+ formState,
65+ returnValue,
66+ }
6267 const rscOptions = { temporaryReferences }
6368 const rscStream = renderToReadableStream < RscPayload > ( rscPayload , rscOptions )
6469
6570 // respond RSC stream without HTML rendering based on framework's convention.
6671 // here we use request header `content-type`.
6772 // additionally we allow `?__rsc` and `?__html` to easily view payload directly.
68- const url = new URL ( request . url )
6973 const isRscRequest =
7074 ( ! request . headers . get ( 'accept' ) ?. includes ( 'text/html' ) &&
7175 ! url . searchParams . has ( '__html' ) ) ||
Original file line number Diff line number Diff line change @@ -4,7 +4,7 @@ import { getServerCounter, updateServerCounter } from './action.tsx'
44import reactLogo from './assets/react.svg'
55import { ClientCounter } from './client.tsx'
66
7- export function Root ( ) {
7+ export function Root ( props : { url : URL } ) {
88 return (
99 < html lang = "en" >
1010 < head >
@@ -14,13 +14,13 @@ export function Root() {
1414 < title > Vite + RSC</ title >
1515 </ head >
1616 < body >
17- < App />
17+ < App { ... props } />
1818 </ body >
1919 </ html >
2020 )
2121}
2222
23- function App ( ) {
23+ function App ( props : { url : URL } ) {
2424 return (
2525 < div id = "root" >
2626 < div >
@@ -43,6 +43,7 @@ function App() {
4343 < button > Server Counter: { getServerCounter ( ) } </ button >
4444 </ form >
4545 </ div >
46+ < div className = "card" > Request URL: { props . url ?. href } </ div >
4647 < ul className = "read-the-docs" >
4748 < li >
4849 Edit < code > src/client.tsx</ code > to test client HMR.
@@ -52,15 +53,15 @@ function App() {
5253 </ li >
5354 < li >
5455 Visit{ ' ' }
55- < a href = "/ ?__rsc" target = "_blank" >
56- < code > / ?__rsc</ code >
56+ < a href = "?__rsc" target = "_blank" >
57+ < code > ?__rsc</ code >
5758 </ a > { ' ' }
5859 to view RSC stream payload.
5960 </ li >
6061 < li >
6162 Visit{ ' ' }
62- < a href = "/ ?__nojs" target = "_blank" >
63- < code > / ?__nojs</ code >
63+ < a href = "?__nojs" target = "_blank" >
64+ < code > ?__nojs</ code >
6465 </ a > { ' ' }
6566 to test server action without js enabled.
6667 </ li >
Original file line number Diff line number Diff line change @@ -471,6 +471,10 @@ export default function vitePluginRsc(
471471 `[vite-rsc] failed to resolve server handler '${ source } '` ,
472472 )
473473 const mod = await environment . runner . import ( resolved . id )
474+ // expose original request url to server handler.
475+ // for example, this restores `base` which is automatically stripped by Vite.
476+ // https://github.com/vitejs/vite/blob/84079a84ad94de4c1ef4f1bdb2ab448ff2c01196/packages/vite/src/node/server/middlewares/base.ts#L18-L20
477+ req . url = req . originalUrl ?? req . url
474478 // ensure catching rejected promise
475479 // https://github.com/mjackson/remix-the-web/blob/b5aa2ae24558f5d926af576482caf6e9b35461dc/packages/node-fetch-server/src/lib/request-listener.ts#L87
476480 await createRequestListener ( mod . default ) ( req , res )
@@ -506,6 +510,7 @@ export default function vitePluginRsc(
506510 return ( ) => {
507511 server . middlewares . use ( async ( req , res , next ) => {
508512 try {
513+ req . url = req . originalUrl ?? req . url
509514 await handler ( req , res )
510515 } catch ( e ) {
511516 next ( e )
You can’t perform that action at this time.
0 commit comments