11import * as es from "esbuild" ;
22import fs from "node:fs" ;
3+ import crypto from "node:crypto" ;
34import { BuildFailure , type OutputFile } from "esbuild" ;
45
56import {
@@ -16,6 +17,15 @@ import postCssPlugin from "esbuild-style-plugin";
1617import { RawSourceMap } from "source-map-js" ;
1718import logger from "~/lib/logger" ;
1819
20+ // Build cache to avoid rebuilding unchanged files
21+ const MAX_CACHE_SIZE = 50 ;
22+ const buildCache = new Map < string , {
23+ documentComponent : any ;
24+ documentCss : string | undefined ;
25+ renderAsync : typeof renderAsync ;
26+ sourceMapToOriginalFile : RawSourceMap ;
27+ } > ( ) ;
28+
1929export const getDocumentComponent = async (
2030 documentPath : string
2131) : Promise <
@@ -30,6 +40,25 @@ export const getDocumentComponent = async (
3040 logger . debug ( `[getDocumentComponent] Starting build for: ${ documentPath } ` ) ;
3141 const startTime = performance . now ( ) ;
3242
43+ // Check cache based on file content hash
44+ let fileContent : string | undefined ;
45+ let hash : string | undefined ;
46+ try {
47+ fileContent = await fs . promises . readFile ( documentPath , 'utf-8' ) ;
48+ hash = crypto . createHash ( 'md5' ) . update ( fileContent ) . digest ( 'hex' ) ;
49+
50+ if ( buildCache . has ( hash ) ) {
51+ logger . debug ( `[getDocumentComponent] Using cached build for ${ documentPath } ` ) ;
52+ const cachedResult = buildCache . get ( hash ) ! ;
53+ const totalTime = performance . now ( ) - startTime ;
54+ logger . debug ( `[getDocumentComponent] Cache hit in ${ totalTime . toFixed ( 2 ) } ms` ) ;
55+ return cachedResult ;
56+ }
57+ } catch ( cacheError ) {
58+ // If cache check fails, continue with normal build
59+ logger . debug ( `[getDocumentComponent] Cache check failed, proceeding with build` ) ;
60+ }
61+
3362 let outputFiles : OutputFile [ ] ;
3463 try {
3564 logger . debug ( 'Starting esbuild' ) ;
@@ -38,7 +67,7 @@ export const getDocumentComponent = async (
3867 entryPoints : [ documentPath ] ,
3968 platform : "node" ,
4069 bundle : true ,
41- minify : true ,
70+ minify : false ,
4271 write : false ,
4372 format : "cjs" ,
4473 jsx : "automatic" ,
@@ -127,12 +156,28 @@ export const getDocumentComponent = async (
127156 const totalTime = performance . now ( ) - startTime ;
128157 logger . debug ( `[getDocumentComponent] Total processing completed in ${ totalTime . toFixed ( 2 ) } ms` ) ;
129158
130- return {
159+ const result = {
131160 documentComponent : executionResult . DocumentComponent ,
132161 documentCss,
133162 renderAsync : executionResult . renderAsync ,
134163 sourceMapToOriginalFile : sourceMapToDocument ,
135164 } ;
165+
166+ // Cache the successful result using the hash computed earlier
167+ if ( hash ) {
168+ buildCache . set ( hash , result ) ;
169+
170+ // Limit cache size to prevent memory leaks
171+ if ( buildCache . size > MAX_CACHE_SIZE ) {
172+ const firstKey = buildCache . keys ( ) . next ( ) . value ;
173+ if ( firstKey ) {
174+ buildCache . delete ( firstKey ) ;
175+ }
176+ }
177+ logger . debug ( `[getDocumentComponent] Result cached with hash ${ hash } ` ) ;
178+ }
179+
180+ return result ;
136181 } catch ( error ) {
137182 logger . error ( '[getDocumentComponent] Processing error:' , error ) ;
138183 return {
0 commit comments