@@ -837,7 +837,8 @@ window.__vite_plugin_react_preamble_installed__ = true;
837837 const resolvedEntry = await this . resolve ( source )
838838 assert ( resolvedEntry , `[vite-rsc] failed to resolve entry '${ source } '` )
839839 code += `await import(${ JSON . stringify ( resolvedEntry . id ) } );`
840- // TODO: this doesn't have to wait for "vite:beforeUpdate" and should do it right after browser css import.
840+ // server css is normally removed via `RemoveDuplicateServerCss` on useEffect.
841+ // this also makes sure they are removed on hmr in case initial rendering failed.
841842 code += /* js */ `
842843const ssrCss = document.querySelectorAll("link[rel='stylesheet']");
843844import.meta.hot.on("vite:beforeUpdate", () => {
@@ -1910,6 +1911,36 @@ export function vitePluginRscCss(
19101911 }
19111912 } ,
19121913 } ,
1914+ createVirtualPlugin (
1915+ 'vite-rsc/remove-duplicate-server-css' ,
1916+ async function ( ) {
1917+ // Remove duplicate css during dev due to server rendered <link> and client inline <style>
1918+ // https://github.com/remix-run/react-router/blob/166fd940e7d5df9ed005ca68e12de53b1d88324a/packages/react-router/lib/dom-export/hydrated-router.tsx#L245-L274
1919+ assert . equal ( this . environment . mode , 'dev' )
1920+ function removeFn ( ) {
1921+ document
1922+ . querySelectorAll ( "link[rel='stylesheet']" )
1923+ . forEach ( ( node ) => {
1924+ if (
1925+ node instanceof HTMLElement &&
1926+ node . dataset . precedence ?. startsWith ( 'vite-rsc/' )
1927+ ) {
1928+ node . remove ( )
1929+ }
1930+ } )
1931+ }
1932+ return `\
1933+ "use client"
1934+ import React from "react";
1935+ export default function RemoveDuplicateServerCss() {
1936+ React.useEffect(() => {
1937+ (${ removeFn . toString ( ) } )();
1938+ }, []);
1939+ return null;
1940+ }
1941+ `
1942+ } ,
1943+ ) ,
19131944 ]
19141945}
19151946
@@ -1940,6 +1971,7 @@ function generateResourcesCode(depsCode: string) {
19401971 const ResourcesFn = (
19411972 React : typeof import ( 'react' ) ,
19421973 deps : ResolvedAssetDeps ,
1974+ RemoveDuplicateServerCss ?: React . FC ,
19431975 ) => {
19441976 return function Resources ( ) {
19451977 return React . createElement ( React . Fragment , null , [
@@ -1960,14 +1992,29 @@ function generateResourcesCode(depsCode: string) {
19601992 src : href ,
19611993 } ) ,
19621994 ) ,
1995+ RemoveDuplicateServerCss &&
1996+ React . createElement ( RemoveDuplicateServerCss , {
1997+ key : 'remove-duplicate-css' ,
1998+ } ) ,
19631999 ] )
19642000 }
19652001 }
19662002
19672003 return `
1968- import __vite_rsc_react__ from "react";
1969- export const Resources = (${ ResourcesFn . toString ( ) } )(__vite_rsc_react__, ${ depsCode } );
1970- `
2004+ import __vite_rsc_react__ from "react";
2005+
2006+ ${
2007+ config . command === 'serve'
2008+ ? `import RemoveDuplicateServerCss from "virtual:vite-rsc/remove-duplicate-server-css";`
2009+ : `const RemoveDuplicateServerCss = undefined;`
2010+ }
2011+
2012+ export const Resources = (${ ResourcesFn . toString ( ) } )(
2013+ __vite_rsc_react__,
2014+ ${ depsCode } ,
2015+ RemoveDuplicateServerCss,
2016+ );
2017+ `
19712018}
19722019
19732020export async function transformRscCssExport ( options : {
0 commit comments