@@ -242,10 +242,8 @@ export default function vitePluginRsc(
242
242
serverResourcesMetaMap = sortObject ( serverResourcesMetaMap )
243
243
await builder . build ( builder . environments . client ! )
244
244
245
- const assetsManifestCode = `export default ${ JSON . stringify (
245
+ const assetsManifestCode = `export default ${ serializeValueWithRuntime (
246
246
buildAssetsManifest ,
247
- null ,
248
- 2 ,
249
247
) } `
250
248
const manifestPath = path . join (
251
249
builder . environments ! . rsc ! . config . build ! . outDir ! ,
@@ -586,7 +584,7 @@ export default function vitePluginRsc(
586
584
assert ( this . environment . mode === 'dev' )
587
585
const entryUrl = assetsURL ( '@id/__x00__' + VIRTUAL_ENTRIES . browser )
588
586
const manifest : AssetsManifest = {
589
- bootstrapScriptContent : `import(${ JSON . stringify ( entryUrl ) } )` ,
587
+ bootstrapScriptContent : `import(${ serializeValueWithRuntime ( entryUrl ) } )` ,
590
588
clientReferenceDeps : { } ,
591
589
}
592
590
return `export default ${ JSON . stringify ( manifest , null , 2 ) } `
@@ -640,8 +638,16 @@ export default function vitePluginRsc(
640
638
mergeAssetDeps ( deps , entry . deps ) ,
641
639
)
642
640
}
641
+ let bootstrapScriptContent : string | RuntimeAsset
642
+ if ( typeof entryUrl === 'string' ) {
643
+ bootstrapScriptContent = `import(${ JSON . stringify ( entryUrl ) } )`
644
+ } else {
645
+ bootstrapScriptContent = new RuntimeAsset (
646
+ `"import(" + JSON.stringify(${ entryUrl . runtime } ) + ")"` ,
647
+ )
648
+ }
643
649
buildAssetsManifest = {
644
- bootstrapScriptContent : `import( ${ JSON . stringify ( entryUrl ) } )` ,
650
+ bootstrapScriptContent,
645
651
clientReferenceDeps,
646
652
serverResources,
647
653
}
@@ -671,10 +677,8 @@ export default function vitePluginRsc(
671
677
if ( this . environment . name === 'ssr' ) {
672
678
// output client manifest to non-client build directly.
673
679
// this makes server build to be self-contained and deploy-able for cloudflare.
674
- const assetsManifestCode = `export default ${ JSON . stringify (
680
+ const assetsManifestCode = `export default ${ serializeValueWithRuntime (
675
681
buildAssetsManifest ,
676
- null ,
677
- 2 ,
678
682
) } `
679
683
for ( const name of [ 'ssr' , 'rsc' ] ) {
680
684
const manifestPath = path . join (
@@ -1273,15 +1277,76 @@ function generateDynamicImportCode(map: Record<string, string>) {
1273
1277
return `export default {${ code } };\n`
1274
1278
}
1275
1279
1276
- // // https://github.com/vitejs/vite/blob/2a7473cfed96237711cda9f736465c84d442ddef/packages/vite/src/node/plugins/importAnalysisBuild.ts#L222-L230
1280
+ class RuntimeAsset {
1281
+ runtime : string
1282
+ constructor ( value : string ) {
1283
+ this . runtime = value
1284
+ }
1285
+ }
1286
+
1287
+ function serializeValueWithRuntime ( value : any ) {
1288
+ const replacements : [ string , string ] [ ] = [ ]
1289
+ let result = JSON . stringify (
1290
+ value ,
1291
+ ( _key , value ) => {
1292
+ if ( value instanceof RuntimeAsset ) {
1293
+ const placeholder = `__runtime_placeholder_${ replacements . length } __`
1294
+ replacements . push ( [ placeholder , value . runtime ] )
1295
+ return placeholder
1296
+ }
1297
+
1298
+ return value
1299
+ } ,
1300
+ 2 ,
1301
+ )
1302
+
1303
+ for ( const [ placeholder , runtime ] of replacements ) {
1304
+ result = result . replace ( `"${ placeholder } "` , runtime )
1305
+ }
1306
+
1307
+ return result
1308
+ }
1309
+
1277
1310
function assetsURL ( url : string ) {
1311
+ if (
1312
+ config . command === 'build' &&
1313
+ typeof config . experimental ?. renderBuiltUrl === 'function'
1314
+ ) {
1315
+ // https://github.com/vitejs/vite/blob/bdde0f9e5077ca1a21a04eefc30abad055047226/packages/vite/src/node/build.ts#L1369
1316
+ const result = config . experimental . renderBuiltUrl ( url , {
1317
+ type : 'asset' ,
1318
+ hostType : 'js' ,
1319
+ ssr : true ,
1320
+ hostId : '' ,
1321
+ } )
1322
+
1323
+ if ( typeof result === 'object' ) {
1324
+ if ( result . runtime ) {
1325
+ return new RuntimeAsset ( result . runtime )
1326
+ }
1327
+ assert (
1328
+ ! result . relative ,
1329
+ '"result.relative" not supported on renderBuiltUrl() for RSC' ,
1330
+ )
1331
+ } else if ( result ) {
1332
+ return result satisfies string
1333
+ }
1334
+ }
1335
+
1336
+ // https://github.com/vitejs/vite/blob/2a7473cfed96237711cda9f736465c84d442ddef/packages/vite/src/node/plugins/importAnalysisBuild.ts#L222-L230
1278
1337
return config . base + url
1279
1338
}
1280
1339
1281
1340
function assetsURLOfDeps ( deps : AssetDeps ) {
1282
1341
return {
1283
- js : deps . js . map ( ( href ) => assetsURL ( href ) ) ,
1284
- css : deps . css . map ( ( href ) => assetsURL ( href ) ) ,
1342
+ js : deps . js . map ( ( href ) => {
1343
+ assert ( typeof href === 'string' )
1344
+ return assetsURL ( href )
1345
+ } ) ,
1346
+ css : deps . css . map ( ( href ) => {
1347
+ assert ( typeof href === 'string' )
1348
+ return assetsURL ( href )
1349
+ } ) ,
1285
1350
}
1286
1351
}
1287
1352
@@ -1290,12 +1355,23 @@ function assetsURLOfDeps(deps: AssetDeps) {
1290
1355
//
1291
1356
1292
1357
export type AssetsManifest = {
1293
- bootstrapScriptContent : string
1358
+ bootstrapScriptContent : string | RuntimeAsset
1294
1359
clientReferenceDeps : Record < string , AssetDeps >
1295
- serverResources ?: Record < string , { css : string [ ] } >
1360
+ serverResources ?: Record < string , Pick < AssetDeps , ' css' > >
1296
1361
}
1297
1362
1298
1363
export type AssetDeps = {
1364
+ js : ( string | RuntimeAsset ) [ ]
1365
+ css : ( string | RuntimeAsset ) [ ]
1366
+ }
1367
+
1368
+ export type ResolvedAssetsManifest = {
1369
+ bootstrapScriptContent : string
1370
+ clientReferenceDeps : Record < string , ResolvedAssetDeps >
1371
+ serverResources ?: Record < string , Pick < ResolvedAssetDeps , 'css' > >
1372
+ }
1373
+
1374
+ export type ResolvedAssetDeps = {
1299
1375
js : string [ ]
1300
1376
css : string [ ]
1301
1377
}
@@ -1574,7 +1650,7 @@ export function vitePluginRscCss(
1574
1650
this . addWatchFile ( file )
1575
1651
}
1576
1652
const hrefs = result . hrefs . map ( ( href ) => assetsURL ( href . slice ( 1 ) ) )
1577
- return `export default ${ JSON . stringify ( hrefs ) } `
1653
+ return `export default ${ serializeValueWithRuntime ( hrefs ) } `
1578
1654
}
1579
1655
} ,
1580
1656
} ,
@@ -1661,7 +1737,7 @@ export function vitePluginRscCss(
1661
1737
encodeURIComponent ( importer ) ,
1662
1738
]
1663
1739
const deps = assetsURLOfDeps ( { css : cssHrefs , js : jsHrefs } )
1664
- return generateResourcesCode ( JSON . stringify ( deps , null , 2 ) )
1740
+ return generateResourcesCode ( serializeValueWithRuntime ( deps ) )
1665
1741
} else {
1666
1742
const key = normalizePath ( path . relative ( config . root , importer ) )
1667
1743
serverResourcesMetaMap [ importer ] = { key }
@@ -1742,7 +1818,10 @@ function collectModuleDependents(mods: EnvironmentModuleNode[]) {
1742
1818
}
1743
1819
1744
1820
function generateResourcesCode ( depsCode : string ) {
1745
- const ResourcesFn = ( React : typeof import ( 'react' ) , deps : AssetDeps ) => {
1821
+ const ResourcesFn = (
1822
+ React : typeof import ( 'react' ) ,
1823
+ deps : ResolvedAssetDeps ,
1824
+ ) => {
1746
1825
return function Resources ( ) {
1747
1826
return React . createElement ( React . Fragment , null , [
1748
1827
...deps . css . map ( ( href : string ) =>
0 commit comments