From 1be37868815ddc9b0645547373e2cf45c167a791 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:48:01 +0000 Subject: [PATCH 1/3] Initial plan From 7b2034694ddb6ea7a2b6171f951c989957d9e31c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:52:57 +0000 Subject: [PATCH 2/3] Implement performance optimizations: disable minification, add build caching, increase debounce Co-authored-by: dportillo-ixs <116919472+dportillo-ixs@users.noreply.github.com> --- .../hot-reloading/setup-hot-reloading.ts | 2 +- .../src/utils/get-document-component.tsx | 51 ++++++++++++++++++- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/packages/htmldocs/src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts b/packages/htmldocs/src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts index 586aca5..134b5bd 100644 --- a/packages/htmldocs/src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts +++ b/packages/htmldocs/src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts @@ -49,7 +49,7 @@ export const setupHotreloading = async ( changes = []; - }, 150); + }, 500); const absolutePathToDocumentsDirectory = path.resolve( process.cwd(), diff --git a/packages/htmldocs/src/utils/get-document-component.tsx b/packages/htmldocs/src/utils/get-document-component.tsx index 2ceb2f7..d9d1dd8 100644 --- a/packages/htmldocs/src/utils/get-document-component.tsx +++ b/packages/htmldocs/src/utils/get-document-component.tsx @@ -1,5 +1,6 @@ import * as es from "esbuild"; import fs from "node:fs"; +import crypto from "node:crypto"; import { BuildFailure, type OutputFile } from "esbuild"; import { @@ -16,6 +17,14 @@ import postCssPlugin from "esbuild-style-plugin"; import { RawSourceMap } from "source-map-js"; import logger from "~/lib/logger"; +// Build cache to avoid rebuilding unchanged files +const buildCache = new Map(); + export const getDocumentComponent = async ( documentPath: string ): Promise< @@ -30,6 +39,23 @@ export const getDocumentComponent = async ( logger.debug(`[getDocumentComponent] Starting build for: ${documentPath}`); const startTime = performance.now(); + // Check cache based on file content hash + try { + const fileContent = await fs.promises.readFile(documentPath, 'utf-8'); + const hash = crypto.createHash('md5').update(fileContent).digest('hex'); + + if (buildCache.has(hash)) { + logger.debug(`[getDocumentComponent] Using cached build for ${documentPath}`); + const cachedResult = buildCache.get(hash)!; + const totalTime = performance.now() - startTime; + logger.debug(`[getDocumentComponent] Cache hit in ${totalTime.toFixed(2)}ms`); + return cachedResult; + } + } catch (cacheError) { + // If cache check fails, continue with normal build + logger.debug(`[getDocumentComponent] Cache check failed, proceeding with build`); + } + let outputFiles: OutputFile[]; try { logger.debug('Starting esbuild'); @@ -38,7 +64,7 @@ export const getDocumentComponent = async ( entryPoints: [documentPath], platform: "node", bundle: true, - minify: true, + minify: false, write: false, format: "cjs", jsx: "automatic", @@ -127,12 +153,33 @@ export const getDocumentComponent = async ( const totalTime = performance.now() - startTime; logger.debug(`[getDocumentComponent] Total processing completed in ${totalTime.toFixed(2)}ms`); - return { + const result = { documentComponent: executionResult.DocumentComponent, documentCss, renderAsync: executionResult.renderAsync, sourceMapToOriginalFile: sourceMapToDocument, }; + + // Cache the successful result + try { + const fileContent = await fs.promises.readFile(documentPath, 'utf-8'); + const hash = crypto.createHash('md5').update(fileContent).digest('hex'); + buildCache.set(hash, result); + + // Limit cache size to prevent memory leaks + if (buildCache.size > 50) { + const firstKey = buildCache.keys().next().value; + if (firstKey) { + buildCache.delete(firstKey); + } + } + logger.debug(`[getDocumentComponent] Result cached with hash ${hash}`); + } catch (cacheError) { + // If caching fails, still return the result + logger.debug(`[getDocumentComponent] Failed to cache result:`, cacheError); + } + + return result; } catch (error) { logger.error('[getDocumentComponent] Processing error:', error); return { From 5ad3682a15fc70adc50d2fd88fb0a9bbe226913a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:55:51 +0000 Subject: [PATCH 3/3] Address code review feedback: extract cache size constant, avoid double file read Co-authored-by: dportillo-ixs <116919472+dportillo-ixs@users.noreply.github.com> --- .../src/utils/get-document-component.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/htmldocs/src/utils/get-document-component.tsx b/packages/htmldocs/src/utils/get-document-component.tsx index d9d1dd8..de72a42 100644 --- a/packages/htmldocs/src/utils/get-document-component.tsx +++ b/packages/htmldocs/src/utils/get-document-component.tsx @@ -18,6 +18,7 @@ import { RawSourceMap } from "source-map-js"; import logger from "~/lib/logger"; // Build cache to avoid rebuilding unchanged files +const MAX_CACHE_SIZE = 50; const buildCache = new Map 50) { + if (buildCache.size > MAX_CACHE_SIZE) { const firstKey = buildCache.keys().next().value; if (firstKey) { buildCache.delete(firstKey); } } logger.debug(`[getDocumentComponent] Result cached with hash ${hash}`); - } catch (cacheError) { - // If caching fails, still return the result - logger.debug(`[getDocumentComponent] Failed to cache result:`, cacheError); } return result;