Skip to content
Closed
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
101 changes: 36 additions & 65 deletions packages/plugin-rsc/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,10 @@ export default function vitePluginRsc(
if (id === '\0virtual:vite-rsc/assets-manifest') {
assert(this.environment.name !== 'client')
assert(this.environment.mode === 'dev')
const entryUrl = assetsURL('@id/__x00__' + VIRTUAL_ENTRIES.browser)
const entryUrl = assetsURL(
'@id/__x00__' + VIRTUAL_ENTRIES.browser,
this.environment.config,
)
const manifest: AssetsManifest = {
bootstrapScriptContent: `import(${serializeValueWithRuntime(entryUrl)})`,
clientReferenceDeps: {},
Expand All @@ -697,7 +700,8 @@ export default function vitePluginRsc(
if (this.environment.name === 'client') {
const filterAssets =
rscPluginOptions.copyServerAssetsToClient ?? (() => true)
const rscBuildOptions = config.environments.rsc!.build
const rscBuildOptions =
this.environment.config.environments.rsc!.build
const rscViteManifest =
typeof rscBuildOptions.manifest === 'string'
? rscBuildOptions.manifest
Expand All @@ -716,23 +720,30 @@ export default function vitePluginRsc(
const serverResources: Record<string, AssetDeps> = {}
const rscAssetDeps = collectAssetDeps(rscBundle)
for (const [id, meta] of Object.entries(serverResourcesMetaMap)) {
serverResources[meta.key] = assetsURLOfDeps({
js: [],
css: rscAssetDeps[id]?.deps.css ?? [],
})
serverResources[meta.key] = assetsURLOfDeps(
{
js: [],
css: rscAssetDeps[id]?.deps.css ?? [],
},
this.environment.config,
)
}

const assetDeps = collectAssetDeps(bundle)
const entry = Object.values(assetDeps).find(
(v) => v.chunk.name === 'index',
)
assert(entry)
const entryUrl = assetsURL(entry.chunk.fileName)
const entryUrl = assetsURL(
entry.chunk.fileName,
this.environment.config,
)
const clientReferenceDeps: Record<string, AssetDeps> = {}
for (const [id, meta] of Object.entries(clientReferenceMetaMap)) {
const deps: AssetDeps = assetDeps[id]?.deps ?? { js: [], css: [] }
clientReferenceDeps[meta.referenceKey] = assetsURLOfDeps(
mergeAssetDeps(deps, entry.deps),
this.environment.config,
)
}
let bootstrapScriptContent: string | RuntimeAsset
Expand Down Expand Up @@ -837,8 +848,7 @@ window.__vite_plugin_react_preamble_installed__ = true;
const resolvedEntry = await this.resolve(source)
assert(resolvedEntry, `[vite-rsc] failed to resolve entry '${source}'`)
code += `await import(${JSON.stringify(resolvedEntry.id)});`
// server css is normally removed via `RemoveDuplicateServerCss` on useEffect.
// this also makes sure they are removed on hmr in case initial rendering failed.
// TODO: this doesn't have to wait for "vite:beforeUpdate" and should do it right after browser css import.
code += /* js */ `
const ssrCss = document.querySelectorAll("link[rel='stylesheet']");
import.meta.hot.on("vite:beforeUpdate", () => {
Expand Down Expand Up @@ -1422,7 +1432,7 @@ function serializeValueWithRuntime(value: any) {
return result
}

function assetsURL(url: string) {
function assetsURL(url: string, config: ResolvedConfig) {
if (
config.command === 'build' &&
typeof config.experimental?.renderBuiltUrl === 'function'
Expand Down Expand Up @@ -1452,15 +1462,15 @@ function assetsURL(url: string) {
return config.base + url
}

function assetsURLOfDeps(deps: AssetDeps) {
function assetsURLOfDeps(deps: AssetDeps, config: ResolvedConfig) {
return {
js: deps.js.map((href) => {
assert(typeof href === 'string')
return assetsURL(href)
return assetsURL(href, config)
}),
css: deps.css.map((href) => {
assert(typeof href === 'string')
return assetsURL(href)
return assetsURL(href, config)
}),
}
}
Expand Down Expand Up @@ -1769,7 +1779,9 @@ export function vitePluginRscCss(
for (const file of [mod.file, ...result.visitedFiles]) {
this.addWatchFile(file)
}
const hrefs = result.hrefs.map((href) => assetsURL(href.slice(1)))
const hrefs = result.hrefs.map((href) =>
assetsURL(href.slice(1), this.environment.config),
)
return `export default ${serializeValueWithRuntime(hrefs)}`
}
},
Expand Down Expand Up @@ -1856,10 +1868,15 @@ export function vitePluginRscCss(
'@id/__x00__virtual:vite-rsc/importer-resources-browser?importer=' +
encodeURIComponent(importer),
]
const deps = assetsURLOfDeps({ css: cssHrefs, js: jsHrefs })
const deps = assetsURLOfDeps(
{ css: cssHrefs, js: jsHrefs },
this.environment.config,
)
return generateResourcesCode(serializeValueWithRuntime(deps))
} else {
const key = normalizePath(path.relative(config.root, importer))
const key = normalizePath(
path.relative(this.environment.config.root, importer),
)
serverResourcesMetaMap[importer] = { key }
return `
import __vite_rsc_assets_manifest__ from "virtual:vite-rsc/assets-manifest";
Expand Down Expand Up @@ -1911,36 +1928,6 @@ export function vitePluginRscCss(
}
},
},
createVirtualPlugin(
'vite-rsc/remove-duplicate-server-css',
async function () {
// Remove duplicate css during dev due to server rendered <link> and client inline <style>
// https://github.com/remix-run/react-router/blob/166fd940e7d5df9ed005ca68e12de53b1d88324a/packages/react-router/lib/dom-export/hydrated-router.tsx#L245-L274
assert.equal(this.environment.mode, 'dev')
function removeFn() {
document
.querySelectorAll("link[rel='stylesheet']")
.forEach((node) => {
if (
node instanceof HTMLElement &&
node.dataset.precedence?.startsWith('vite-rsc/')
) {
node.remove()
}
})
}
return `\
"use client"
import React from "react";
export default function RemoveDuplicateServerCss() {
React.useEffect(() => {
(${removeFn.toString()})();
}, []);
return null;
}
`
},
),
]
}

Expand Down Expand Up @@ -1971,7 +1958,6 @@ function generateResourcesCode(depsCode: string) {
const ResourcesFn = (
React: typeof import('react'),
deps: ResolvedAssetDeps,
RemoveDuplicateServerCss?: React.FC,
) => {
return function Resources() {
return React.createElement(React.Fragment, null, [
Expand All @@ -1992,29 +1978,14 @@ function generateResourcesCode(depsCode: string) {
src: href,
}),
),
RemoveDuplicateServerCss &&
React.createElement(RemoveDuplicateServerCss, {
key: 'remove-duplicate-css',
}),
])
}
}

return `
import __vite_rsc_react__ from "react";

${
config.command === 'serve'
? `import RemoveDuplicateServerCss from "virtual:vite-rsc/remove-duplicate-server-css";`
: `const RemoveDuplicateServerCss = undefined;`
}

export const Resources = (${ResourcesFn.toString()})(
__vite_rsc_react__,
${depsCode},
RemoveDuplicateServerCss,
);
`
import __vite_rsc_react__ from "react";
export const Resources = (${ResourcesFn.toString()})(__vite_rsc_react__, ${depsCode});
`
}

export async function transformRscCssExport(options: {
Expand Down