diff --git a/.jules/bolt.md b/.jules/bolt.md index 284d180..3f11c24 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -19,3 +19,6 @@ ## 2026-07-13 - 단일 패스 문자열 치환 최적화 (O(N) 단일 스캔 및 지연 할당) **Learning:** `String.replace()`를 여러 번 체이닝하여 호출하면, 문자열 치환이 발생하지 않는 경우에도 내부적으로 불필요한 스캔이 중복 발생하고, 치환 시마다 새로운 문자열 객체와 char 배열이 할당되어 메모리 낭비와 성능 저하(GC 압박)가 발생한다. **Action:** 여러 문자를 한 번에 치환해야 하는 경우, O(N) 단일 스캔을 통해 `charAt()`으로 문자를 확인하고, 치환이 실제로 필요한 경우에만 `StringBuilder`를 지연 할당(Lazy allocation)하여 성능을 최적화하고 불필요한 메모리 할당을 방지한다. +## 2026-07-14 - 뷰어 쉘 HTML 렌더링 성능 최적화 +**Learning:** 크기가 큰 텍스트 블록에 대해 여러 번의 `.replace()` 메서드 체이닝을 사용할 경우, 호출할 때마다 새로운 문자열 객체가 생성되어 불필요한 메모리 할당이 발생합니다. +**Action:** 긴 문자열 템플릿에 동적 변수를 삽입해야 할 때는 정적인 템플릿 상수(static final)들로 분리한 뒤 문자열 연결(concatenation)을 사용하면, 컴파일 시 `StringConcatFactory`를 통해 최적화되어 요청당 객체 할당량을 크게 줄일 수 있습니다. diff --git a/src/main/java/com/clearfolio/viewer/controller/ViewerUiController.java b/src/main/java/com/clearfolio/viewer/controller/ViewerUiController.java index 5e7de3c..f00d00a 100644 --- a/src/main/java/com/clearfolio/viewer/controller/ViewerUiController.java +++ b/src/main/java/com/clearfolio/viewer/controller/ViewerUiController.java @@ -59,81 +59,95 @@ private static String escapeHtmlAttribute(String value) { return HtmlUtils.htmlEscape(value); } - private static String viewerShellHtml(String docId, String initialState) { + // ⚡ Bolt: Use static template parts to avoid chained replace() + // allocations on every request. + + /** Part 1 of the viewer shell template. */ + private static final String VIEWER_SHELL_PART_1 = """ + + + + + + + + + + Clearfolio Viewer + + + + + + + +
+

Document preview

+

Preparing preview shell...

+ +
+

Preview status

+ +
Loading...
+ + + +
+ + +
+
+ +
+

Preview

+ +
+ +

When ready, the converted artifact will appear here.

+
+
+
+ + + + + + + """; + + private static String viewerShellHtml(final String docId, final String initialState) { String docIdString = escapeHtmlAttribute(docId); - String template = """ - - - - - - - - - - Clearfolio Viewer - - - - - - - -
-

Document preview

-

Preparing preview shell...

- -
-

Preview status

- -
Loading...
- - - -
- - -
-
- -
-

Preview

- -
- -

When ready, the converted artifact will appear here.

-
-
-
- - - - - - - """; - - return template - .replace("{{DOC_ID}}", docIdString) - .replace("{{INITIAL_STATE}}", initialState) - .replace("{{PDFJS_VIEWER_PATH}}", PDF_JS_VIEWER_PATH); + return VIEWER_SHELL_PART_1 + docIdString + VIEWER_SHELL_PART_2 + initialState + + VIEWER_SHELL_PART_3 + PDF_JS_VIEWER_PATH + VIEWER_SHELL_PART_4; } private static String demoShellHtml() {