@@ -837,7 +837,8 @@ window.__vite_plugin_react_preamble_installed__ = true;
837
837
const resolvedEntry = await this . resolve ( source )
838
838
assert ( resolvedEntry , `[vite-rsc] failed to resolve entry '${ source } '` )
839
839
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.
841
842
code += /* js */ `
842
843
const ssrCss = document.querySelectorAll("link[rel='stylesheet']");
843
844
import.meta.hot.on("vite:beforeUpdate", () => {
@@ -1910,6 +1911,36 @@ export function vitePluginRscCss(
1910
1911
}
1911
1912
} ,
1912
1913
} ,
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
+ ) ,
1913
1944
]
1914
1945
}
1915
1946
@@ -1940,6 +1971,7 @@ function generateResourcesCode(depsCode: string) {
1940
1971
const ResourcesFn = (
1941
1972
React : typeof import ( 'react' ) ,
1942
1973
deps : ResolvedAssetDeps ,
1974
+ RemoveDuplicateServerCss ?: React . FC ,
1943
1975
) => {
1944
1976
return function Resources ( ) {
1945
1977
return React . createElement ( React . Fragment , null , [
@@ -1960,14 +1992,29 @@ function generateResourcesCode(depsCode: string) {
1960
1992
src : href ,
1961
1993
} ) ,
1962
1994
) ,
1995
+ RemoveDuplicateServerCss &&
1996
+ React . createElement ( RemoveDuplicateServerCss , {
1997
+ key : 'remove-duplicate-css' ,
1998
+ } ) ,
1963
1999
] )
1964
2000
}
1965
2001
}
1966
2002
1967
2003
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
+ `
1971
2018
}
1972
2019
1973
2020
export async function transformRscCssExport ( options : {
0 commit comments