2
2
// context but want to use Vite's ESM build to avoid deprecation warnings
3
3
import type * as Vite from "vite" ;
4
4
import { type BinaryLike , createHash } from "node:crypto" ;
5
+ import * as fs from "node:fs" ;
5
6
import * as path from "node:path" ;
6
7
import * as url from "node:url" ;
7
8
import * as fse from "fs-extra" ;
@@ -805,6 +806,39 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
805
806
return new Set ( [ ...cssUrlPaths , ...chunkAssetPaths ] ) ;
806
807
} ;
807
808
809
+ let generateSriManifest = async ( ctx : ReactRouterPluginContext ) => {
810
+ let clientBuildDirectory = getClientBuildDirectory ( ctx . reactRouterConfig ) ;
811
+ // walk the client build directory and generate SRI hashes for all .js files
812
+ let entries = fs . readdirSync ( clientBuildDirectory , {
813
+ withFileTypes : true ,
814
+ recursive : true ,
815
+ } ) ;
816
+ let sriManifest : ReactRouterManifest [ "sri" ] = { } ;
817
+ for ( const entry of entries ) {
818
+ if ( entry . isFile ( ) && entry . name . endsWith ( ".js" ) ) {
819
+ let contents ;
820
+ try {
821
+ contents = await fse . readFile (
822
+ path . join ( entry . path , entry . name ) ,
823
+ "utf-8"
824
+ ) ;
825
+ } catch ( e ) {
826
+ logger . error ( `Failed to read file for SRI generation: ${ entry . name } ` ) ;
827
+ throw e ;
828
+ }
829
+ let hash = createHash ( "sha384" )
830
+ . update ( contents )
831
+ . digest ( )
832
+ . toString ( "base64" ) ;
833
+ let filepath = getVite ( ) . normalizePath (
834
+ path . relative ( clientBuildDirectory , path . join ( entry . path , entry . name ) )
835
+ ) ;
836
+ sriManifest [ `${ ctx . publicPath } ${ filepath } ` ] = `sha384-${ hash } ` ;
837
+ }
838
+ }
839
+ return sriManifest ;
840
+ } ;
841
+
808
842
let generateReactRouterManifestsForBuild = async ( {
809
843
routeIds,
810
844
} : {
@@ -942,6 +976,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
942
976
let reactRouterBrowserManifest : ReactRouterManifest = {
943
977
...fingerprintedValues ,
944
978
...nonFingerprintedValues ,
979
+ sri : undefined ,
945
980
} ;
946
981
947
982
// Write the browser manifest to disk as part of the build process
@@ -952,12 +987,18 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
952
987
) } ;`
953
988
) ;
954
989
990
+ let sri : ReactRouterManifest [ "sri" ] = undefined ;
991
+ if ( ctx . reactRouterConfig . future . unstable_subResourceIntegrity ) {
992
+ sri = await generateSriManifest ( ctx ) ;
993
+ }
994
+
955
995
// The server manifest is the same as the browser manifest, except for
956
996
// server bundle builds which only includes routes for the current bundle,
957
997
// otherwise the server and client have the same routes
958
998
let reactRouterServerManifest : ReactRouterManifest = {
959
999
...reactRouterBrowserManifest ,
960
1000
routes : serverRoutes ,
1001
+ sri,
961
1002
} ;
962
1003
963
1004
return {
@@ -1043,6 +1084,8 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
1043
1084
} ;
1044
1085
}
1045
1086
1087
+ let sri : ReactRouterManifest [ "sri" ] = undefined ;
1088
+
1046
1089
let reactRouterManifestForDev = {
1047
1090
version : String ( Math . random ( ) ) ,
1048
1091
url : combineURLs ( ctx . publicPath , virtual . browserManifest . url ) ,
@@ -1056,6 +1099,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
1056
1099
) ,
1057
1100
imports : [ ] ,
1058
1101
} ,
1102
+ sri,
1059
1103
routes,
1060
1104
} ;
1061
1105
0 commit comments