Skip to content

feat(rsc): add support for experimental.renderBuiltUrl on assets metadata #612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Jul 24, 2025

Conversation

HenriqueLimas
Copy link
Contributor

@HenriqueLimas HenriqueLimas commented Jul 23, 2025

Description

This PR integrates Vite's renderBuiltUrl experimental hook into the RSC plugin. This change updates how asset URLs are generated in the RSC manifest by enabling support for dynamic, runtime-aware URLs.

We now use devalue instead of JSON.stringify for serialization JSON.stringify with custom serializer, which allows the manifest to include JavaScript expressions for URLs that are resolved at runtime.

Key Changes

renderBuiltInUrl for Dynamic URLs: The RSC plugin now leverages the renderBuiltInUrl experimental hook to construct URLs for the manifest.

Build-Mode Only: This new logic is only active during production builds. In development mode, the behavior is unchanged and falls back to the existing config.base + url concatenation.

Updated E2E Tests: The end-to-end tests have been updated to load the manifest using a dynamic import() instead of JSON.parse(fs.readFile()). This is necessary to correctly test the new dynamic values that devalue can produce.

Copy link
Contributor

@hi-ogawa hi-ogawa left a comment

Choose a reason for hiding this comment

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

Hey, thanks for the PR! I think this is nice to have with your approach but let me confirm a few things.

Technically there's slight conceptual limitation for SSR and renderBuiltUrl runtime mode. I imagine "runtime" means that they are only meant to be evaluated on browser, but for SSR/RSC, they need to be eagerly evaluated on server since react preload/preinit <link href> and <script src> need to be known during SSR render (clientReferenceDeps) and RSC render (serverResources).

Can you explain your concrete use case and how runtime is defined? I'm not familiar with renderBuiltUrl, so knowing the actual use case would probably help me understand better.

@HenriqueLimas
Copy link
Contributor Author

Thanks for the quick review! The use case is that the base path is not known on build time, only on runtime (staging or production has different CDNs path). For example we can have an globalThis.__assetsPath(file) that is defined in the server for SSR that knows the environment and the one on the browser that uses information passed by the server. renderBuiltinUrl is executed in both environments (it passes a ssr Boolean as an argument). We have a react-router app, and that is not possible currently to use and We do some workaround to modify the manifest object before passing to react router. I will update my branch with latest changes.

@hi-ogawa
Copy link
Contributor

For example we can have an globalThis.__assetsPath(file) that is defined in the server for SSR that knows the environment and the one on the browser that uses information passed by the server. renderBuiltinUrl is executed in both environments (it passes a ssr Boolean as an argument).

Thanks for clarification. Yes, I was wondering whether you do globalThis on the server. I think that should work then 👍

It got me more curious, so follow up question if you don't mind 🙂 Are you trying this out by migrating existing react-router ssr app? If so, was it in react rotuer vite framework mode or your own ssr setup? Was renderBuiltUrl working properly in that setup?

@hi-ogawa hi-ogawa added the trigger: preview Trigger pkg.pr.new label Jul 23, 2025
@HenriqueLimas
Copy link
Contributor Author

HenriqueLimas commented Jul 23, 2025

It got me more curious, so follow up question if you don't mind 🙂 Are you trying this out by migrating existing react-router ssr app? If so, was it in react rotuer vite framework mode or your own ssr setup? Was renderBuiltUrl working properly in that setup?

We currently use framework mode and we use renderBuiltUrl() only for dynamic assets like svg and we overwrite the react-router manifest before passing to the RR handler. But we would love to use renderBuiltUrl instead for both. I did propose to do something similar on RR side, but it seems that now with RSC their vision is to delegate assets to the RSC plugin instead of RR maintaining it.
We are currently experimenting with this plugin and the react-router data mode, but eventually when it will be stable we might migrate that.

Copy link

pkg-pr-new bot commented Jul 24, 2025

Open in StackBlitz

npm i https://pkg.pr.new/@vitejs/plugin-react@612
npm i https://pkg.pr.new/@vitejs/plugin-react-oxc@612
npm i https://pkg.pr.new/@vitejs/plugin-rsc@612
npm i https://pkg.pr.new/@vitejs/plugin-react-swc@612

commit: 9626836

@hi-ogawa hi-ogawa changed the title feat(rsc): add support for renderBuiltInUrl on assets metadata feat(rsc): add support for experimental.renderBuiltUrl on assets metadata Jul 24, 2025
Copy link
Contributor

@hi-ogawa hi-ogawa left a comment

Choose a reason for hiding this comment

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

Thanks for the update! I'll tweak a bit myself but it looks good overall. 👍
If I did some bad change, please let me know 😃

Comment on lines +641 to +648
let bootstrapScriptContent: string | RuntimeAsset
if (typeof entryUrl === 'string') {
bootstrapScriptContent = `import(${JSON.stringify(entryUrl)})`
} else {
bootstrapScriptContent = new RuntimeAsset(
`"import(" + JSON.stringify(${entryUrl.runtime}) + ")"`,
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Previously bootstrapScriptContent's import url runtime is resolved on browser:

{
  "bootstrapScriptContent":"import(globalThis.__dynamicBase + \"assets/index-BxtkZ08f.js\")",

But, I think this should be aligned to other assets, so the runtime is resolved on server:

{
  "bootstrapScriptContent": "import(" + JSON.stringify(globalThis.__dynamicBase + "assets/index-BxtkZ08f.js") + ")",

@hi-ogawa
Copy link
Contributor

I've added a test case for dynamic base. Can you check if this looks good for you? If so, I'm ready to merge this.

If you want to test this on your project, you can use a preview package from #612 (comment).

@hi-ogawa hi-ogawa requested a review from Copilot July 24, 2025 09:37
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR integrates Vite's experimental renderBuiltUrl hook into the RSC plugin to enable dynamic, runtime-aware asset URL generation. The implementation replaces static JSON serialization with a more flexible approach that supports JavaScript expressions for URLs resolved at runtime.

  • Adds support for experimental.renderBuiltUrl hook integration in production builds
  • Introduces custom serialization using RuntimeAsset class and serializeValueWithRuntime function
  • Updates type definitions to distinguish between build-time asset dependencies and resolved runtime dependencies

Reviewed Changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

File Description
packages/plugin-rsc/src/plugin.ts Core implementation of renderBuiltUrl support with new RuntimeAsset class and serialization logic
packages/plugin-rsc/src/ssr.tsx Type updates to use ResolvedAssetDeps for runtime-resolved dependencies
packages/plugin-rsc/e2e/starter.test.ts Comprehensive test coverage for both string and runtime URL scenarios
packages/plugin-rsc/e2e/fixture.ts Enhanced fixture setup to support file editing operations

@HenriqueLimas
Copy link
Contributor Author

@hi-ogawa tested the version internally with a globalThis.__assetsPath = (path) => url.resolve(getCDNPath(), path) and it worked perfectly! Thank you for the support on this.

@hi-ogawa
Copy link
Contributor

Thanks for the contribution! Please feel free to reach me if you encounter any issue with Vite RSC.

@hi-ogawa hi-ogawa merged commit 5314ed6 into vitejs:main Jul 24, 2025
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
trigger: preview Trigger pkg.pr.new
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy