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,14 @@ 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 buildCache = new Map < string , {
22+ documentComponent : any ;
23+ documentCss : string | undefined ;
24+ renderAsync : typeof renderAsync ;
25+ sourceMapToOriginalFile : RawSourceMap ;
26+ } > ( ) ;
27+
1928export const getDocumentComponent = async (
2029 documentPath : string
2130) : Promise <
@@ -30,6 +39,23 @@ export const getDocumentComponent = async (
3039 logger . debug ( `[getDocumentComponent] Starting build for: ${ documentPath } ` ) ;
3140 const startTime = performance . now ( ) ;
3241
42+ // Check cache based on file content hash
43+ try {
44+ const fileContent = await fs . promises . readFile ( documentPath , 'utf-8' ) ;
45+ const hash = crypto . createHash ( 'md5' ) . update ( fileContent ) . digest ( 'hex' ) ;
46+
47+ if ( buildCache . has ( hash ) ) {
48+ logger . debug ( `[getDocumentComponent] Using cached build for ${ documentPath } ` ) ;
49+ const cachedResult = buildCache . get ( hash ) ! ;
50+ const totalTime = performance . now ( ) - startTime ;
51+ logger . debug ( `[getDocumentComponent] Cache hit in ${ totalTime . toFixed ( 2 ) } ms` ) ;
52+ return cachedResult ;
53+ }
54+ } catch ( cacheError ) {
55+ // If cache check fails, continue with normal build
56+ logger . debug ( `[getDocumentComponent] Cache check failed, proceeding with build` ) ;
57+ }
58+
3359 let outputFiles : OutputFile [ ] ;
3460 try {
3561 logger . debug ( 'Starting esbuild' ) ;
@@ -38,7 +64,7 @@ export const getDocumentComponent = async (
3864 entryPoints : [ documentPath ] ,
3965 platform : "node" ,
4066 bundle : true ,
41- minify : true ,
67+ minify : false ,
4268 write : false ,
4369 format : "cjs" ,
4470 jsx : "automatic" ,
@@ -127,12 +153,33 @@ export const getDocumentComponent = async (
127153 const totalTime = performance . now ( ) - startTime ;
128154 logger . debug ( `[getDocumentComponent] Total processing completed in ${ totalTime . toFixed ( 2 ) } ms` ) ;
129155
130- return {
156+ const result = {
131157 documentComponent : executionResult . DocumentComponent ,
132158 documentCss,
133159 renderAsync : executionResult . renderAsync ,
134160 sourceMapToOriginalFile : sourceMapToDocument ,
135161 } ;
162+
163+ // Cache the successful result
164+ try {
165+ const fileContent = await fs . promises . readFile ( documentPath , 'utf-8' ) ;
166+ const hash = crypto . createHash ( 'md5' ) . update ( fileContent ) . digest ( 'hex' ) ;
167+ buildCache . set ( hash , result ) ;
168+
169+ // Limit cache size to prevent memory leaks
170+ if ( buildCache . size > 50 ) {
171+ const firstKey = buildCache . keys ( ) . next ( ) . value ;
172+ if ( firstKey ) {
173+ buildCache . delete ( firstKey ) ;
174+ }
175+ }
176+ logger . debug ( `[getDocumentComponent] Result cached with hash ${ hash } ` ) ;
177+ } catch ( cacheError ) {
178+ // If caching fails, still return the result
179+ logger . debug ( `[getDocumentComponent] Failed to cache result:` , cacheError ) ;
180+ }
181+
182+ return result ;
136183 } catch ( error ) {
137184 logger . error ( '[getDocumentComponent] Processing error:' , error ) ;
138185 return {
0 commit comments