perf(core): JSON 서빙 네트워크 오버헤드 최적화
실측(g7.dev) 결과 줄바꿈 제거·gzip 은 이미 적용된 상태였고, 남은 실질 개선 3종을 구현: - 모든 API 응답에 JSON_UNESCAPED_UNICODE 적용 — 한글이 \uXXXX(6B)로 팽창하던 것을 raw UTF-8(3B)로 직렬화 (lang pack gzip -9.1%) - 공개 레이아웃 서빙에서 개발자용 comment/_comment 재귀 제거, 편집 모드(with_source_meta)는 보존 (layout gzip -34.9%) - 번들 JS/CSS(BinaryFileResponse) gzip 압축 사각지대 해소 — 기존 미들웨어가 getContent==false 로 압축을 건너뛰던 문제 (-73~77%)
This commit is contained in:
1 parent
a958443d69
commit
c819820573
11 files changed
+638
-145
No files matched your search
@@ -587,6 +587,27 @@ class PublicLayoutController extends PublicBaseController
|
||||
|
||||
---
|
||||
|
||||
## JSON 인코딩 옵션 (JSON_UNESCAPED_UNICODE)
|
||||
|
||||
모든 `response()->json()` 호출은 `ResponseHelper::JSON_ENCODE_OPTIONS`(= `JSON_UNESCAPED_UNICODE`)를 인코딩 옵션으로 전달한다. 한글 등 멀티바이트 문자를 `\uXXXX`(6바이트)로 이스케이프하지 않고 raw UTF-8(한글 3바이트)로 직렬화하여 응답 전송 크기를 줄인다. 다국어 팩(lang) 응답처럼 한글 비중이 큰 페이로드에서 절감 효과가 크다.
|
||||
|
||||
```php
|
||||
// ✅ 올바른 사용 — 네 번째 인자로 옵션 전달
|
||||
return response()->json($payload, $status, [], ResponseHelper::JSON_ENCODE_OPTIONS);
|
||||
|
||||
// 헤더 배열이 필요한 경우 (세 번째 인자)
|
||||
return response()->json($payload, $status, ['Cache-Control' => '...'], ResponseHelper::JSON_ENCODE_OPTIONS);
|
||||
|
||||
// ❌ 옵션 누락 — 한글이 \uXXXX 로 팽창
|
||||
return response()->json($payload, $status);
|
||||
```
|
||||
|
||||
`ResponseHelper` 의 모든 메서드(`success`/`error`/`validationError`/… )와 `BaseApiController::successWithCache`/`cachedJsonResponse` 는 이미 이 옵션을 적용한다. 컨트롤러/서비스는 `ResponseHelper` 를 사용하면 자동으로 적용되므로 별도 조치가 불필요하다. `response()->json()` 을 직접 호출하는 신규 코드에서만 옵션 전달을 잊지 않는다.
|
||||
|
||||
> 슬래시 언이스케이프(`JSON_UNESCAPED_SLASHES`)는 적용하지 않는다 — endpoint 경로의 `\/` 는 크기 영향이 미미하고, 기존 응답 본문 정확 매칭 테스트의 안전성을 우선한다.
|
||||
|
||||
---
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [index.md](index.md) - 백엔드 가이드 인덱스
|
||||
|
||||
@@ -435,6 +435,16 @@ php artisan template:cache-clear # 전체 번들 파일 정리 포함
|
||||
|
||||
> 개별 에셋 서빙 라우트(`/api/{type}/assets/...`, `*.map` 포함)는 소스맵·static 참조를 위해 존치한다.
|
||||
|
||||
### 전송 압축 (gzip)
|
||||
|
||||
번들 JS/CSS 는 `fileResponse()`(= `response()->file()` → `BinaryFileResponse`)로 서빙되며, `GzipEncodeResponse` 미들웨어가 gzip 압축을 적용한다. `BinaryFileResponse` 는 `getContent()` 가 `false` 를 반환하므로, 미들웨어는 파일 경로(`getFile()->getPathname()`)에서 본문을 읽어 압축한 뒤 헤더(Content-Type/ETag/Cache-Control)를 승계한 일반 `Response` 로 치환한다.
|
||||
|
||||
- 1KB 미만 번들(예: 빈 CSS)은 `MIN_COMPRESS_SIZE` 가드로 압축 생략.
|
||||
- `Accept-Encoding: gzip` 미포함 요청, 이미 `Content-Encoding` 이 있는 응답, 304 응답은 압축 대상에서 제외.
|
||||
- 회귀 테스트: `tests/Feature/Middleware/GzipEncodeResponseTest.php` (BinaryFileResponse 압축/헤더 승계/소용량 skip).
|
||||
|
||||
> `BinaryFileResponse` 를 압축 대상에 포함하지 않으면 번들이 비압축 전송되는 사각지대가 생긴다(모듈/플러그인 번들은 크기가 커 압축 이득이 특히 크다).
|
||||
|
||||
---
|
||||
|
||||
## 에셋 로딩 전략
|
||||
|
||||
@@ -554,7 +554,7 @@ Laravel의 `FormRequest::validated()` 메서드는 `rules()`에 정의된 필드
|
||||
| `id` | string | ✅ | 컴포넌트 고유 ID |
|
||||
| `type` | string | ✅ | 컴포넌트 타입 (basic/composite/layout) |
|
||||
| `name` | string | ✅ | 컴포넌트 이름 (components.json에 등록된 이름) |
|
||||
| `comment` | string | ✅ | 시안 추적 코드 및 역할 설명 (예: "F-002: 상품명 검색 필드") |
|
||||
| `comment` | string | ✅ | 시안 추적 코드 및 역할 설명 (예: "F-002: 상품명 검색 필드"). 공개 서빙 응답에서는 제거됨 (아래 참조) |
|
||||
| `props` | object | ❌ | 컴포넌트에 전달할 props |
|
||||
| `text` | string | ❌ | 텍스트 콘텐츠 (최우선 렌더링) |
|
||||
| `children` | array | ❌ | 자식 컴포넌트 배열 (레이아웃/집합 컴포넌트에서 사용) |
|
||||
@@ -575,6 +575,13 @@ Laravel의 `FormRequest::validated()` 메서드는 `rules()`에 정의된 필드
|
||||
> - `actions`: [layout-json-features.md](layout-json-features.md#액션-시스템-actions)
|
||||
> - `isolatedState`: [아래 섹션](#격리된-상태-isolatedstate)
|
||||
|
||||
### `comment` / `_comment` — 공개 서빙 응답에서 제거
|
||||
|
||||
`comment` / `_comment` 는 편집기·개발자용 설명 주석이며 런타임 렌더러는 참조하지 않는다. 공개 레이아웃 서빙(`GET /api/layouts/{template}/{layout}.json`) 응답에서는 전송 크기 절감을 위해 이 두 키가 노드 트리 전체에서 재귀적으로 제거된다(`LayoutService::stripDeveloperComments`).
|
||||
|
||||
- 편집 모드 서빙(`?with_source_meta=1`, 편집 권한 필요)에서는 편집기가 `comment` 를 편집 가능한 속성으로 노출하므로 **보존**된다. 공개/편집 응답은 별도 캐시 키로 분리되어 있어 조건부 제거가 안전하다.
|
||||
- 따라서 `comment` 는 편집기·저장본에서는 유지되고, 일반 사용자에게 서빙되는 응답에서만 사라진다. 레이아웃 로직이 `comment` 값에 의존해서는 안 된다.
|
||||
|
||||
---
|
||||
|
||||
## 격리된 상태 (isolatedState)
|
||||
|
||||
Reference in new issue
Block a user