@@ -5,15 +5,16 @@ import { blue, cyan, dim, gray, green, red, yellow } from 'kolorist'
55import PQueue from 'p-queue'
66import fs from 'fs-extra'
77import type { InlineConfig } from 'vite'
8- import { mergeConfig , resolveConfig , build as viteBuild , version as viteVersion } from 'vite'
8+ import { createLogger , mergeConfig , resolveConfig , build as viteBuild , version as viteVersion } from 'vite'
99import type { VitePluginPWAAPI } from 'vite-plugin-pwa'
1010import { JSDOM } from 'jsdom'
1111import type { RouteRecord , ViteReactSSGContext , ViteReactSSGOptions } from '../types'
1212import { serializeState } from '../utils/state'
13- import { buildLog , createRequest , getSize , removeLeadingSlash , resolveAlias , routesToPaths , withTrailingSlash } from './utils'
13+ import { removeLeadingSlash , withTrailingSlash } from '../utils/path'
14+ import { buildLog , createRequest , getSize , resolveAlias , routesToPaths } from './utils'
1415import { getCritters } from './critial'
1516import { render } from './server'
16- import { detectEntry , renderHTML } from './html'
17+ import { SCRIPT_COMMENT_PLACEHOLDER , detectEntry , renderHTML } from './html'
1718import { renderPreloadLinks } from './preload-links'
1819
1920export type SSRManifest = Record < string , string [ ] >
@@ -27,6 +28,8 @@ export interface ManifestItem {
2728
2829export type Manifest = Record < string , ManifestItem >
2930
31+ export type StaticLoaderDataManifest = Record < string , Record < string , unknown > | undefined >
32+
3033export type CreateRootFactory = ( client : boolean , routePath ?: string ) => Promise < ViteReactSSGContext < true > | ViteReactSSGContext < false > >
3134
3235function DefaultIncludedRoutes ( paths : string [ ] , _routes : Readonly < RouteRecord [ ] > ) {
@@ -39,7 +42,8 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
3942 const config = await resolveConfig ( viteConfig , 'build' , mode , mode )
4043 const cwd = process . cwd ( )
4144 const root = config . root || cwd
42- const ssgOut = join ( root , '.vite-react-ssg-temp' , Math . random ( ) . toString ( 36 ) . substring ( 2 , 12 ) )
45+ const hash = Math . random ( ) . toString ( 36 ) . substring ( 2 , 12 )
46+ const ssgOut = join ( root , '.vite-react-ssg-temp' , hash )
4347 const outDir = config . build . outDir || 'dist'
4448 const out = isAbsolute ( outDir ) ? outDir : join ( root , outDir )
4549 const configBase = config . base
@@ -64,6 +68,13 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
6468 if ( fs . existsSync ( ssgOut ) )
6569 await fs . remove ( ssgOut )
6670
71+ const clientLogger = createLogger ( )
72+ const loggerWarn = clientLogger . warn
73+ clientLogger . warn = ( msg : string , options ) => {
74+ if ( msg . includes ( 'vite:resolve' ) && msg . includes ( 'externalized for browser compatibility' ) )
75+ return
76+ loggerWarn ( msg , options )
77+ }
6778 // client
6879 buildLog ( 'Build for client...' )
6980 await viteBuild ( mergeConfig ( viteConfig , {
@@ -82,7 +93,9 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
8293 } ,
8394 } ,
8495 } ,
96+ customLogger : clientLogger ,
8597 mode : config . mode ,
98+ ssr : { noExternal : [ 'vite-react-ssg' ] } ,
8699 } ) )
87100
88101 if ( mock ) {
@@ -114,6 +127,7 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
114127 } ,
115128 } ,
116129 mode : config . mode ,
130+ ssr : { noExternal : [ 'vite-react-ssg' ] } ,
117131 } ) )
118132
119133 const prefix = ( format === 'esm' && process . platform === 'win32' ) ? 'file://' : ''
@@ -153,6 +167,8 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
153167 const queue = new PQueue ( { concurrency } )
154168 const crittersQueue = new PQueue ( { concurrency : 1 } )
155169
170+ const staticLoaderDataManifest : StaticLoaderDataManifest = { }
171+
156172 for ( const path of routesPaths ) {
157173 queue . add ( async ( ) => {
158174 try {
@@ -166,7 +182,8 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
166182 const fetchUrl = `${ withTrailingSlash ( base ) } ${ removeLeadingSlash ( path ) } `
167183 const request = createRequest ( fetchUrl )
168184
169- const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag } = await render ( app ?? [ ...routes ] , request , styleCollector , base )
185+ const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render ( app ?? [ ...routes ] , request , styleCollector , base )
186+ staticLoaderDataManifest [ path ] = routerContext ?. loaderData
170187
171188 await triggerOnSSRAppRendered ?.( path , appHTML , appCtx )
172189
@@ -188,6 +205,7 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
188205
189206 const html = jsdom . serialize ( )
190207 let transformed = ( await onPageRendered ?.( path , html , appCtx ) ) || html
208+ transformed = transformed . replace ( SCRIPT_COMMENT_PLACEHOLDER , `window.__VITE_REACT_SSG_HASH__ = '${ hash } '` )
191209 if ( critters ) {
192210 transformed = ( await crittersQueue . add ( ( ) => critters . process ( transformed ) ) ) !
193211 transformed = transformed . replace ( / < l i n k \s r e l = " s t y l e s h e e t " / g, '<link rel="stylesheet" crossorigin' )
@@ -220,6 +238,13 @@ export async function build(ssgOptions: Partial<ViteReactSSGOptions> = {}, viteC
220238
221239 await queue . start ( ) . onIdle ( )
222240
241+ buildLog ( 'Generating static loader data manifest...' )
242+ const staticLoaderDataManifestString = JSON . stringify ( staticLoaderDataManifest , null , 0 )
243+ await fs . writeFile ( join ( out , `static-loader-data-manifest-${ hash } .json` ) , staticLoaderDataManifestString )
244+ config . logger . info (
245+ `${ dim ( `${ outDir } /` ) } ${ cyan ( `static-loader-data-manifest-${ hash } .json` . padEnd ( 15 , ' ' ) ) } ${ dim ( getSize ( staticLoaderDataManifestString ) ) } ` ,
246+ )
247+
223248 await fs . remove ( join ( root , '.vite-react-ssg-temp' ) )
224249
225250 const pwaPlugin : VitePluginPWAAPI = config . plugins . find ( i => i . name === 'vite-plugin-pwa' ) ?. api
0 commit comments