@@ -884,7 +884,8 @@ window.__vite_plugin_react_preamble_installed__ = true;
884884 const resolvedEntry = await this . resolve ( source )
885885 assert ( resolvedEntry , `[vite-rsc] failed to resolve entry '${ source } '` )
886886 code += `await import(${ JSON . stringify ( resolvedEntry . id ) } );`
887- // TODO: this doesn't have to wait for "vite:beforeUpdate" and should do it right after browser css import.
887+ // server css is normally removed via `RemoveDuplicateServerCss` on useEffect.
888+ // this also makes sure they are removed on hmr in case initial rendering failed.
888889 code += /* js */ `
889890const ssrCss = document.querySelectorAll("link[rel='stylesheet']");
890891import.meta.hot.on("vite:beforeUpdate", () => {
@@ -1992,6 +1993,36 @@ export function vitePluginRscCss(
19921993 }
19931994 } ,
19941995 } ,
1996+ createVirtualPlugin (
1997+ 'vite-rsc/remove-duplicate-server-css' ,
1998+ async function ( ) {
1999+ // Remove duplicate css during dev due to server rendered <link> and client inline <style>
2000+ // https://github.com/remix-run/react-router/blob/166fd940e7d5df9ed005ca68e12de53b1d88324a/packages/react-router/lib/dom-export/hydrated-router.tsx#L245-L274
2001+ assert . equal ( this . environment . mode , 'dev' )
2002+ function removeFn ( ) {
2003+ document
2004+ . querySelectorAll ( "link[rel='stylesheet']" )
2005+ . forEach ( ( node ) => {
2006+ if (
2007+ node instanceof HTMLElement &&
2008+ node . dataset . precedence ?. startsWith ( 'vite-rsc/' )
2009+ ) {
2010+ node . remove ( )
2011+ }
2012+ } )
2013+ }
2014+ return `\
2015+ "use client"
2016+ import React from "react";
2017+ export default function RemoveDuplicateServerCss() {
2018+ React.useEffect(() => {
2019+ (${ removeFn . toString ( ) } )();
2020+ }, []);
2021+ return null;
2022+ }
2023+ `
2024+ } ,
2025+ ) ,
19952026 ]
19962027}
19972028
@@ -2022,6 +2053,7 @@ function generateResourcesCode(depsCode: string) {
20222053 const ResourcesFn = (
20232054 React : typeof import ( 'react' ) ,
20242055 deps : ResolvedAssetDeps ,
2056+ RemoveDuplicateServerCss ?: React . FC ,
20252057 ) => {
20262058 return function Resources ( ) {
20272059 return React . createElement ( React . Fragment , null , [
@@ -2042,14 +2074,29 @@ function generateResourcesCode(depsCode: string) {
20422074 src : href ,
20432075 } ) ,
20442076 ) ,
2077+ RemoveDuplicateServerCss &&
2078+ React . createElement ( RemoveDuplicateServerCss , {
2079+ key : 'remove-duplicate-css' ,
2080+ } ) ,
20452081 ] )
20462082 }
20472083 }
20482084
20492085 return `
2050- import __vite_rsc_react__ from "react";
2051- export const Resources = (${ ResourcesFn . toString ( ) } )(__vite_rsc_react__, ${ depsCode } );
2052- `
2086+ import __vite_rsc_react__ from "react";
2087+
2088+ ${
2089+ config . command === 'serve'
2090+ ? `import RemoveDuplicateServerCss from "virtual:vite-rsc/remove-duplicate-server-css";`
2091+ : `const RemoveDuplicateServerCss = undefined;`
2092+ }
2093+
2094+ export const Resources = (${ ResourcesFn . toString ( ) } )(
2095+ __vite_rsc_react__,
2096+ ${ depsCode } ,
2097+ RemoveDuplicateServerCss,
2098+ );
2099+ `
20532100}
20542101
20552102export async function transformRscCssExport ( options : {
0 commit comments