@@ -1659,49 +1659,120 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
1659
1659
let ssrViteManifest = await loadViteManifest ( serverBuildDirectory ) ;
1660
1660
let ssrAssetPaths = getViteManifestAssetPaths ( ssrViteManifest ) ;
1661
1661
1662
- // We only move assets that aren't in the client build, otherwise we
1663
- // remove them. These assets only exist because we explicitly set
1664
- // `ssrEmitAssets: true` in the SSR Vite config. These assets
1665
- // typically wouldn't exist by default, which is why we assume it's
1666
- // safe to remove them. We're aiming for a clean build output so that
1667
- // unnecessary assets don't get deployed alongside the server code.
1662
+ // If the consumer has explicitly opted in to keeping the SSR build
1663
+ // assets, we don't remove them. We only copy missing assets from the
1664
+ // SSR to the client build.
1665
+ let userSsrEmitAssets =
1666
+ ( ctx . reactRouterConfig . future . unstable_viteEnvironmentApi
1667
+ ? viteUserConfig . environments ?. ssr ?. build ?. ssrEmitAssets ??
1668
+ viteUserConfig . environments ?. ssr ?. build ?. emitAssets
1669
+ : null ) ??
1670
+ viteUserConfig . build ?. ssrEmitAssets ??
1671
+ false ;
1672
+
1673
+ // We only move/copy assets that aren't in the client build, otherwise
1674
+ // we remove them if the consumer hasn't explicitly enabled
1675
+ // `ssrEmitAssets` in their Vite config. These assets only exist
1676
+ // because we internally enable `ssrEmitAssets` within our plugin.
1677
+ // These assets typically wouldn't exist by default, which is why we
1678
+ // assume it's safe to remove them.
1668
1679
let movedAssetPaths : string [ ] = [ ] ;
1680
+ let removedAssetPaths : string [ ] = [ ] ;
1681
+ let copiedAssetPaths : string [ ] = [ ] ;
1669
1682
for ( let ssrAssetPath of ssrAssetPaths ) {
1670
1683
let src = path . join ( serverBuildDirectory , ssrAssetPath ) ;
1671
1684
let dest = path . join ( clientBuildDirectory , ssrAssetPath ) ;
1672
1685
1673
- if ( ! fse . existsSync ( dest ) ) {
1674
- await fse . move ( src , dest ) ;
1675
- movedAssetPaths . push ( dest ) ;
1676
- } else {
1677
- await fse . remove ( src ) ;
1686
+ if ( ! userSsrEmitAssets ) {
1687
+ if ( ! fse . existsSync ( dest ) ) {
1688
+ await fse . move ( src , dest ) ;
1689
+ movedAssetPaths . push ( dest ) ;
1690
+ } else {
1691
+ await fse . remove ( src ) ;
1692
+ removedAssetPaths . push ( dest ) ;
1693
+ }
1694
+ } else if ( ! fse . existsSync ( dest ) ) {
1695
+ await fse . copy ( src , dest ) ;
1696
+ copiedAssetPaths . push ( dest ) ;
1678
1697
}
1679
1698
}
1680
1699
1681
- // We assume CSS assets from the SSR build are unnecessary and remove
1682
- // them for the same reasons as above.
1683
- let ssrCssPaths = Object . values ( ssrViteManifest ) . flatMap (
1684
- ( chunk ) => chunk . css ?? [ ]
1685
- ) ;
1700
+ if ( ! userSsrEmitAssets ) {
1701
+ // We assume CSS assets from the SSR build are unnecessary and
1702
+ // remove them for the same reasons as above.
1703
+ let ssrCssPaths = Object . values ( ssrViteManifest ) . flatMap (
1704
+ ( chunk ) => chunk . css ?? [ ]
1705
+ ) ;
1706
+ await Promise . all (
1707
+ ssrCssPaths . map ( async ( cssPath ) => {
1708
+ let src = path . join ( serverBuildDirectory , cssPath ) ;
1709
+ await fse . remove ( src ) ;
1710
+ removedAssetPaths . push ( src ) ;
1711
+ } )
1712
+ ) ;
1713
+ }
1714
+
1715
+ let cleanedAssetPaths = [ ...removedAssetPaths , ...movedAssetPaths ] ;
1716
+ let handledAssetPaths = [ ...cleanedAssetPaths , ...copiedAssetPaths ] ;
1717
+
1718
+ // Clean empty asset directories
1719
+ let cleanedAssetDirs = new Set ( cleanedAssetPaths . map ( path . dirname ) ) ;
1686
1720
await Promise . all (
1687
- ssrCssPaths . map ( ( cssPath ) =>
1688
- fse . remove ( path . join ( serverBuildDirectory , cssPath ) )
1689
- )
1721
+ Array . from ( cleanedAssetDirs ) . map ( async ( dir ) => {
1722
+ try {
1723
+ const files = await fse . readdir ( dir ) ;
1724
+ if ( files . length === 0 ) {
1725
+ await fse . remove ( dir ) ;
1726
+ }
1727
+ } catch { }
1728
+ } )
1690
1729
) ;
1691
1730
1692
- if ( movedAssetPaths . length ) {
1693
- viteConfig . logger . info (
1694
- [
1695
- "" ,
1696
- `${ colors . green ( "✓" ) } ${ movedAssetPaths . length } asset${
1697
- movedAssetPaths . length > 1 ? "s" : ""
1698
- } moved from React Router server build to client assets.`,
1699
- ...movedAssetPaths . map ( ( movedAssetPath ) =>
1700
- colors . dim ( path . relative ( ctx . rootDirectory , movedAssetPath ) )
1701
- ) ,
1702
- "" ,
1703
- ] . join ( "\n" )
1704
- ) ;
1731
+ // If we handled any assets, add some leading whitespace to
1732
+ // our logs to make them more prominent
1733
+ if ( handledAssetPaths . length ) {
1734
+ viteConfig . logger . info ( "" ) ;
1735
+ }
1736
+
1737
+ function logHandledAssets ( paths : string [ ] , message : string ) {
1738
+ invariant ( viteConfig ) ;
1739
+ if ( paths . length ) {
1740
+ viteConfig . logger . info (
1741
+ [
1742
+ `${ colors . green ( "✓" ) } ${ message } ` ,
1743
+ ...paths . map ( ( assetPath ) =>
1744
+ colors . dim ( path . relative ( ctx . rootDirectory , assetPath ) )
1745
+ ) ,
1746
+ ] . join ( "\n" )
1747
+ ) ;
1748
+ }
1749
+ }
1750
+
1751
+ logHandledAssets (
1752
+ removedAssetPaths ,
1753
+ `${ removedAssetPaths . length } asset${
1754
+ removedAssetPaths . length > 1 ? "s" : ""
1755
+ } cleaned from React Router server build.`
1756
+ ) ;
1757
+
1758
+ logHandledAssets (
1759
+ movedAssetPaths ,
1760
+ `${ movedAssetPaths . length } asset${
1761
+ movedAssetPaths . length > 1 ? "s" : ""
1762
+ } moved from React Router server build to client assets.`
1763
+ ) ;
1764
+
1765
+ logHandledAssets (
1766
+ copiedAssetPaths ,
1767
+ `${ copiedAssetPaths . length } asset${
1768
+ copiedAssetPaths . length > 1 ? "s" : ""
1769
+ } copied from React Router server build to client assets.`
1770
+ ) ;
1771
+
1772
+ // If we handled any assets, add some leading whitespace to our logs
1773
+ // to make them more prominent
1774
+ if ( handledAssetPaths . length ) {
1775
+ viteConfig . logger . info ( "" ) ;
1705
1776
}
1706
1777
1707
1778
// Set an environment variable we can look for in the handler to
0 commit comments