@mandujs/mcp 0.38.12 → 0.39.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +3 -3
  2. package/package.json +3 -5
  3. package/src/activity-adapter.ts +23 -23
  4. package/src/activity-monitor.ts +39 -10
  5. package/src/adapters/index.ts +20 -20
  6. package/src/adapters/monitor-adapter.ts +100 -100
  7. package/src/adapters/tool-adapter.ts +90 -90
  8. package/src/executor/index.ts +22 -22
  9. package/src/executor/tool-executor.ts +148 -148
  10. package/src/hooks/config-watcher.ts +173 -173
  11. package/src/hooks/index.ts +23 -23
  12. package/src/hooks/mcp-hooks.ts +227 -227
  13. package/src/index.ts +5 -5
  14. package/src/logging/index.ts +15 -15
  15. package/src/logging/mcp-transport.ts +134 -134
  16. package/src/new-resources.ts +2 -2
  17. package/src/profiles.ts +25 -54
  18. package/src/prompts.ts +4 -4
  19. package/src/registry/index.ts +13 -13
  20. package/src/registry/mcp-tool-registry.ts +298 -298
  21. package/src/resources/generated-skills/catalog.ts +36 -0
  22. package/src/resources/generated-skills/mandu-agent-workflow/SKILL.md +48 -0
  23. package/src/resources/generated-skills/mandu-contract/SKILL.md +20 -0
  24. package/src/resources/generated-skills/mandu-fs-routes/SKILL.md +19 -0
  25. package/src/resources/generated-skills/mandu-guard/SKILL.md +20 -0
  26. package/src/resources/generated-skills/mandu-hydration/SKILL.md +19 -0
  27. package/src/resources/generated-skills/mandu-testing/SKILL.md +20 -0
  28. package/src/resources/handlers.ts +3 -3
  29. package/src/resources/skills/guides.ts +49 -49
  30. package/src/resources/skills/index.ts +12 -12
  31. package/src/resources/skills/loader.ts +8 -35
  32. package/src/resources/skills/recipes.ts +28 -28
  33. package/src/server.ts +1 -1
  34. package/src/tools/agent.ts +479 -409
  35. package/src/tools/ate-exemplar.ts +92 -92
  36. package/src/tools/ate-flakes.ts +90 -90
  37. package/src/tools/ate-mutate.ts +103 -103
  38. package/src/tools/ate-mutation-report.ts +64 -64
  39. package/src/tools/ate-oracle-pending.ts +49 -49
  40. package/src/tools/ate-oracle-replay.ts +44 -44
  41. package/src/tools/ate-oracle-verdict.ts +70 -70
  42. package/src/tools/ate-prompt.ts +146 -146
  43. package/src/tools/ate-run.ts +1 -1
  44. package/src/tools/ate.ts +38 -38
  45. package/src/tools/brain.ts +6 -6
  46. package/src/tools/composite.ts +19 -61
  47. package/src/tools/contract.ts +11 -9
  48. package/src/tools/deploy-plan.ts +2 -2
  49. package/src/tools/deploy-preview.ts +316 -316
  50. package/src/tools/design.ts +825 -825
  51. package/src/tools/docs.ts +350 -350
  52. package/src/tools/generate.ts +4 -3
  53. package/src/tools/guard.ts +1 -1
  54. package/src/tools/history.ts +1 -1
  55. package/src/tools/hydration.ts +64 -64
  56. package/src/tools/index.ts +0 -118
  57. package/src/tools/kitchen.ts +72 -72
  58. package/src/tools/lint.ts +226 -226
  59. package/src/tools/loop-close.ts +175 -175
  60. package/src/tools/negotiate.ts +263 -263
  61. package/src/tools/resource.ts +1 -1
  62. package/src/tools/run-tests.ts +424 -424
  63. package/src/tools/runtime.ts +1 -1
  64. package/src/tools/seo.ts +1 -1
  65. package/src/tools/slot-validation.ts +19 -19
  66. package/src/tools/spec.ts +201 -201
  67. package/src/tools/transaction.ts +1 -1
  68. package/src/tx-lock.ts +73 -73
  69. package/src/utils/runtime-control.ts +52 -52
  70. package/src/utils/withWarnings.ts +1 -1
  71. package/src/resources/skills/mandu-agent-workflow/SKILL.md +0 -124
  72. package/src/resources/skills/mandu-agent-workflow/metadata.json +0 -7
  73. package/src/resources/skills/mandu-composition/SKILL.md +0 -131
  74. package/src/resources/skills/mandu-composition/metadata.json +0 -13
  75. package/src/resources/skills/mandu-composition/rules/_sections.md +0 -26
  76. package/src/resources/skills/mandu-composition/rules/_template.md +0 -77
  77. package/src/resources/skills/mandu-composition/rules/comp-arch-avoid-boolean-props.md +0 -146
  78. package/src/resources/skills/mandu-composition/rules/comp-arch-compound-components.md +0 -164
  79. package/src/resources/skills/mandu-composition/rules/comp-island-event.md +0 -161
  80. package/src/resources/skills/mandu-composition/rules/comp-island-slot-split.md +0 -167
  81. package/src/resources/skills/mandu-composition/rules/comp-pattern-children.md +0 -149
  82. package/src/resources/skills/mandu-composition/rules/comp-state-context-interface.md +0 -148
  83. package/src/resources/skills/mandu-composition/rules/comp-state-lift-state.md +0 -150
  84. package/src/resources/skills/mandu-deployment/SKILL.md +0 -135
  85. package/src/resources/skills/mandu-deployment/_sections.md +0 -41
  86. package/src/resources/skills/mandu-deployment/_template.md +0 -38
  87. package/src/resources/skills/mandu-deployment/metadata.json +0 -13
  88. package/src/resources/skills/mandu-deployment/rules/db-provider-supabase.md +0 -300
  89. package/src/resources/skills/mandu-deployment/rules/deploy-build-bun.md +0 -109
  90. package/src/resources/skills/mandu-deployment/rules/deploy-build-output.md +0 -115
  91. package/src/resources/skills/mandu-deployment/rules/deploy-cicd-github.md +0 -219
  92. package/src/resources/skills/mandu-deployment/rules/deploy-docker-bun.md +0 -150
  93. package/src/resources/skills/mandu-deployment/rules/deploy-docker-compose.md +0 -223
  94. package/src/resources/skills/mandu-deployment/rules/deploy-platform-fly.md +0 -152
  95. package/src/resources/skills/mandu-deployment/rules/deploy-platform-render.md +0 -179
  96. package/src/resources/skills/mandu-deployment/rules/deploy-platform-vercel.md +0 -140
  97. package/src/resources/skills/mandu-fs-routes/SKILL.md +0 -122
  98. package/src/resources/skills/mandu-fs-routes/metadata.json +0 -12
  99. package/src/resources/skills/mandu-fs-routes/rules/_sections.md +0 -36
  100. package/src/resources/skills/mandu-fs-routes/rules/_template.md +0 -69
  101. package/src/resources/skills/mandu-fs-routes/rules/routes-api-methods.md +0 -65
  102. package/src/resources/skills/mandu-fs-routes/rules/routes-dynamic-param.md +0 -93
  103. package/src/resources/skills/mandu-fs-routes/rules/routes-naming-page.md +0 -55
  104. package/src/resources/skills/mandu-guard/SKILL.md +0 -162
  105. package/src/resources/skills/mandu-guard/metadata.json +0 -12
  106. package/src/resources/skills/mandu-guard/rules/_sections.md +0 -36
  107. package/src/resources/skills/mandu-guard/rules/_template.md +0 -82
  108. package/src/resources/skills/mandu-guard/rules/guard-config-rules.md +0 -100
  109. package/src/resources/skills/mandu-guard/rules/guard-layer-direction.md +0 -76
  110. package/src/resources/skills/mandu-guard/rules/guard-preset-mandu.md +0 -81
  111. package/src/resources/skills/mandu-guard/rules/guard-validate-import.md +0 -80
  112. package/src/resources/skills/mandu-hydration/SKILL.md +0 -139
  113. package/src/resources/skills/mandu-hydration/metadata.json +0 -12
  114. package/src/resources/skills/mandu-hydration/rules/_sections.md +0 -31
  115. package/src/resources/skills/mandu-hydration/rules/_template.md +0 -72
  116. package/src/resources/skills/mandu-hydration/rules/hydration-data-event.md +0 -109
  117. package/src/resources/skills/mandu-hydration/rules/hydration-directive-use-client.md +0 -55
  118. package/src/resources/skills/mandu-hydration/rules/hydration-island-setup.md +0 -160
  119. package/src/resources/skills/mandu-hydration/rules/hydration-priority-visible.md +0 -91
  120. package/src/resources/skills/mandu-performance/SKILL.md +0 -125
  121. package/src/resources/skills/mandu-performance/metadata.json +0 -14
  122. package/src/resources/skills/mandu-performance/rules/_sections.md +0 -31
  123. package/src/resources/skills/mandu-performance/rules/_template.md +0 -64
  124. package/src/resources/skills/mandu-performance/rules/perf-async-defer-await.md +0 -103
  125. package/src/resources/skills/mandu-performance/rules/perf-async-parallel.md +0 -95
  126. package/src/resources/skills/mandu-performance/rules/perf-bun-file.md +0 -124
  127. package/src/resources/skills/mandu-performance/rules/perf-bun-serve.md +0 -125
  128. package/src/resources/skills/mandu-performance/rules/perf-bundle-imports.md +0 -80
  129. package/src/resources/skills/mandu-performance/rules/perf-bundle-island-lazy.md +0 -145
  130. package/src/resources/skills/mandu-performance/rules/perf-cache-react.md +0 -98
  131. package/src/resources/skills/mandu-performance/rules/perf-render-transitions.md +0 -154
  132. package/src/resources/skills/mandu-security/SKILL.md +0 -127
  133. package/src/resources/skills/mandu-security/metadata.json +0 -13
  134. package/src/resources/skills/mandu-security/rules/_sections.md +0 -31
  135. package/src/resources/skills/mandu-security/rules/_template.md +0 -74
  136. package/src/resources/skills/mandu-security/rules/sec-auth-guard.md +0 -127
  137. package/src/resources/skills/mandu-security/rules/sec-env-management.md +0 -133
  138. package/src/resources/skills/mandu-security/rules/sec-input-validate.md +0 -148
  139. package/src/resources/skills/mandu-security/rules/sec-protect-csrf.md +0 -146
  140. package/src/resources/skills/mandu-security/rules/sec-protect-headers.md +0 -138
  141. package/src/resources/skills/mandu-slot/SKILL.md +0 -125
  142. package/src/resources/skills/mandu-slot/metadata.json +0 -12
  143. package/src/resources/skills/mandu-slot/rules/_sections.md +0 -36
  144. package/src/resources/skills/mandu-slot/rules/_template.md +0 -63
  145. package/src/resources/skills/mandu-slot/rules/slot-basic-structure.md +0 -38
  146. package/src/resources/skills/mandu-slot/rules/slot-ctx-response.md +0 -56
  147. package/src/resources/skills/mandu-slot/rules/slot-guard-auth.md +0 -59
  148. package/src/resources/skills/mandu-slot/rules/slot-http-methods.md +0 -64
  149. package/src/resources/skills/mandu-styling/SKILL.md +0 -196
  150. package/src/resources/skills/mandu-styling/_sections.md +0 -43
  151. package/src/resources/skills/mandu-styling/_template.md +0 -32
  152. package/src/resources/skills/mandu-styling/metadata.json +0 -15
  153. package/src/resources/skills/mandu-styling/rules/style-component-compound.md +0 -235
  154. package/src/resources/skills/mandu-styling/rules/style-component-slots.md +0 -255
  155. package/src/resources/skills/mandu-styling/rules/style-component-tokens.md +0 -205
  156. package/src/resources/skills/mandu-styling/rules/style-island-animations.md +0 -272
  157. package/src/resources/skills/mandu-styling/rules/style-island-scoping.md +0 -167
  158. package/src/resources/skills/mandu-styling/rules/style-island-variants.md +0 -221
  159. package/src/resources/skills/mandu-styling/rules/style-perf-critical.md +0 -209
  160. package/src/resources/skills/mandu-styling/rules/style-perf-purge.md +0 -192
  161. package/src/resources/skills/mandu-styling/rules/style-setup-modules.md +0 -162
  162. package/src/resources/skills/mandu-styling/rules/style-setup-panda.md +0 -164
  163. package/src/resources/skills/mandu-styling/rules/style-setup-tailwind.md +0 -170
  164. package/src/resources/skills/mandu-styling/rules/style-tailwind-v4-gotchas.md +0 -179
  165. package/src/resources/skills/mandu-styling/rules/style-theme-darkmode.md +0 -229
  166. package/src/resources/skills/mandu-testing/SKILL.md +0 -132
  167. package/src/resources/skills/mandu-testing/metadata.json +0 -13
  168. package/src/resources/skills/mandu-testing/rules/_sections.md +0 -26
  169. package/src/resources/skills/mandu-testing/rules/_template.md +0 -65
  170. package/src/resources/skills/mandu-testing/rules/test-component-island.md +0 -195
  171. package/src/resources/skills/mandu-testing/rules/test-e2e-playwright.md +0 -196
  172. package/src/resources/skills/mandu-testing/rules/test-mock-fetch.md +0 -219
  173. package/src/resources/skills/mandu-testing/rules/test-slot-unit.md +0 -192
  174. package/src/resources/skills/mandu-ui/SKILL.md +0 -159
  175. package/src/resources/skills/mandu-ui/_sections.md +0 -23
  176. package/src/resources/skills/mandu-ui/_template.md +0 -32
  177. package/src/resources/skills/mandu-ui/metadata.json +0 -13
  178. package/src/resources/skills/mandu-ui/rules/ui-accessibility-aria.md +0 -232
  179. package/src/resources/skills/mandu-ui/rules/ui-accessibility-focus.md +0 -238
  180. package/src/resources/skills/mandu-ui/rules/ui-composition-patterns.md +0 -259
  181. package/src/resources/skills/mandu-ui/rules/ui-island-integration.md +0 -258
  182. package/src/resources/skills/mandu-ui/rules/ui-radix-patterns.md +0 -213
  183. package/src/resources/skills/mandu-ui/rules/ui-shadcn-setup.md +0 -209
@@ -1,124 +0,0 @@
1
- ---
2
- title: Use Bun.file() for Efficient File Operations
3
- impact: HIGH
4
- impactDescription: 10× faster than Node.js fs
5
- tags: performance, bun, file, io
6
- ---
7
-
8
- ## Use Bun.file() for Efficient File Operations
9
-
10
- **Impact: HIGH (10× faster than Node.js fs)**
11
-
12
- Bun.file()은 lazy 로딩과 스트리밍을 지원하여 Node.js fs보다 훨씬 빠릅니다.
13
-
14
- **Incorrect (Node.js 방식):**
15
-
16
- ```typescript
17
- import { readFile, writeFile } from "fs/promises";
18
-
19
- // ❌ 전체 파일을 메모리에 로드
20
- const content = await readFile("./data.json", "utf-8");
21
- const data = JSON.parse(content);
22
- ```
23
-
24
- **Correct (Bun.file 방식):**
25
-
26
- ```typescript
27
- // ✅ Lazy 로딩, 필요할 때만 읽음
28
- const file = Bun.file("./data.json");
29
-
30
- // 메타데이터만 읽기 (파일 내용 로드 안 함)
31
- console.log(file.size); // 빠름
32
- console.log(file.type); // "application/json"
33
-
34
- // 필요할 때 내용 읽기
35
- const data = await file.json(); // JSON 파싱 내장
36
- ```
37
-
38
- ## Mandu Slot에서의 활용
39
-
40
- ```typescript
41
- // spec/slots/files.slot.ts
42
- import { Mandu } from "@mandujs/core";
43
-
44
- export default Mandu.filling()
45
- .get(async (ctx) => {
46
- const filename = ctx.params.filename;
47
- const file = Bun.file(`./uploads/${filename}`);
48
-
49
- // ✅ 파일 존재 확인
50
- if (!(await file.exists())) {
51
- return ctx.notFound("File not found");
52
- }
53
-
54
- // ✅ 스트리밍 응답
55
- return new Response(file, {
56
- headers: {
57
- "Content-Type": file.type,
58
- "Content-Length": String(file.size),
59
- },
60
- });
61
- })
62
-
63
- .post(async (ctx) => {
64
- const body = await ctx.body<{ content: string }>();
65
-
66
- // ✅ 효율적인 파일 쓰기
67
- await Bun.write("./uploads/new-file.txt", body.content);
68
-
69
- return ctx.created({ message: "File saved" });
70
- });
71
- ```
72
-
73
- ## 대용량 파일 스트리밍
74
-
75
- ```typescript
76
- export default Mandu.filling()
77
- .get(async (ctx) => {
78
- const file = Bun.file("./large-video.mp4");
79
-
80
- // ✅ Range 요청 지원 (비디오 스트리밍)
81
- const range = ctx.headers.get("range");
82
-
83
- if (range) {
84
- const [start, end] = parseRange(range, file.size);
85
- const chunk = file.slice(start, end + 1);
86
-
87
- return new Response(chunk, {
88
- status: 206,
89
- headers: {
90
- "Content-Range": `bytes ${start}-${end}/${file.size}`,
91
- "Content-Length": String(end - start + 1),
92
- "Content-Type": file.type,
93
- },
94
- });
95
- }
96
-
97
- return new Response(file);
98
- });
99
- ```
100
-
101
- ## 파일 타입별 메서드
102
-
103
- ```typescript
104
- const file = Bun.file("./data.json");
105
-
106
- // 타입별 파싱 메서드
107
- await file.text(); // string
108
- await file.json(); // object
109
- await file.arrayBuffer(); // ArrayBuffer
110
- await file.stream(); // ReadableStream
111
- ```
112
-
113
- ## 여러 파일 동시 읽기
114
-
115
- ```typescript
116
- // ✅ 병렬로 여러 파일 읽기
117
- const [config, data, schema] = await Promise.all([
118
- Bun.file("./config.json").json(),
119
- Bun.file("./data.json").json(),
120
- Bun.file("./schema.json").json(),
121
- ]);
122
- ```
123
-
124
- Reference: [Bun.file() documentation](https://bun.sh/docs/api/file-io)
@@ -1,125 +0,0 @@
1
- ---
2
- title: Optimize Bun.serve() Configuration
3
- impact: HIGH
4
- impactDescription: 2-5× faster than Node.js http
5
- tags: performance, bun, serve, runtime
6
- ---
7
-
8
- ## Optimize Bun.serve() Configuration
9
-
10
- **Impact: HIGH (2-5× faster than Node.js http)**
11
-
12
- Mandu는 Bun.serve()를 기반으로 합니다. 적절한 설정으로 최대 성능을 끌어내세요.
13
-
14
- **기본 최적화 설정:**
15
-
16
- ```typescript
17
- // server.ts
18
- Bun.serve({
19
- port: 3000,
20
-
21
- // ✅ 개발 환경에서만 에러 스택 노출
22
- development: process.env.NODE_ENV !== "production",
23
-
24
- // ✅ 정적 파일 직접 서빙 (미들웨어 우회)
25
- static: {
26
- "/public/*": "./public/",
27
- },
28
-
29
- fetch(req) {
30
- // Mandu 라우터 처리
31
- return handleRequest(req);
32
- },
33
-
34
- // ✅ 에러 핸들링
35
- error(error) {
36
- return new Response(`Error: ${error.message}`, { status: 500 });
37
- },
38
- });
39
- ```
40
-
41
- ## 정적 파일 최적화
42
-
43
- ```typescript
44
- Bun.serve({
45
- fetch(req) {
46
- const url = new URL(req.url);
47
-
48
- // ✅ 정적 파일은 Bun.file()로 직접 서빙
49
- if (url.pathname.startsWith("/assets/")) {
50
- const filePath = `./public${url.pathname}`;
51
- const file = Bun.file(filePath);
52
-
53
- return new Response(file, {
54
- headers: {
55
- // 캐시 헤더 설정
56
- "Cache-Control": "public, max-age=31536000, immutable",
57
- },
58
- });
59
- }
60
-
61
- return handleRequest(req);
62
- },
63
- });
64
- ```
65
-
66
- ## 스트리밍 응답
67
-
68
- 대용량 데이터는 스트리밍으로 메모리 효율 향상:
69
-
70
- ```typescript
71
- export default Mandu.filling()
72
- .get(async (ctx) => {
73
- // ✅ 스트리밍 응답
74
- const stream = new ReadableStream({
75
- async start(controller) {
76
- const cursor = db.query("SELECT * FROM large_table");
77
-
78
- for await (const row of cursor) {
79
- controller.enqueue(JSON.stringify(row) + "\n");
80
- }
81
-
82
- controller.close();
83
- },
84
- });
85
-
86
- return new Response(stream, {
87
- headers: { "Content-Type": "application/x-ndjson" },
88
- });
89
- });
90
- ```
91
-
92
- ## TLS 설정 (HTTPS)
93
-
94
- ```typescript
95
- Bun.serve({
96
- port: 443,
97
-
98
- // ✅ TLS 인증서 설정
99
- tls: {
100
- cert: Bun.file("./cert.pem"),
101
- key: Bun.file("./key.pem"),
102
- },
103
-
104
- fetch(req) {
105
- return handleRequest(req);
106
- },
107
- });
108
- ```
109
-
110
- ## 동시 연결 처리
111
-
112
- Bun은 기본적으로 높은 동시성을 지원하지만, 리소스 제한이 있는 환경에서는:
113
-
114
- ```typescript
115
- Bun.serve({
116
- // ✅ 최대 동시 연결 제한 (메모리 보호)
117
- maxRequestBodySize: 1024 * 1024 * 10, // 10MB
118
-
119
- fetch(req) {
120
- return handleRequest(req);
121
- },
122
- });
123
- ```
124
-
125
- Reference: [Bun.serve() documentation](https://bun.sh/docs/api/http)
@@ -1,80 +0,0 @@
1
- ---
2
- title: Import Directly, Avoid Barrel Files
3
- impact: CRITICAL
4
- impactDescription: 15-70% faster dev boot, 40% faster cold starts
5
- tags: performance, bundle, imports, tree-shaking
6
- ---
7
-
8
- ## Import Directly, Avoid Barrel Files
9
-
10
- **Impact: CRITICAL (15-70% faster dev boot, 40% faster cold starts)**
11
-
12
- 배럴 파일(index.ts에서 re-export)을 통하지 않고 소스 파일에서 직접 import하세요. 대형 라이브러리의 배럴 파일은 수천 개의 모듈을 로드합니다.
13
-
14
- **Incorrect (전체 라이브러리 로드):**
15
-
16
- ```typescript
17
- // app/page.tsx
18
- import { Check, X, Menu } from "lucide-react";
19
- // ❌ 1,583개 모듈 로드, 개발 시 ~2.8초 추가
20
- // 런타임 비용: 콜드 스타트마다 200-800ms
21
-
22
- import { Button, TextField } from "@mui/material";
23
- // ❌ 2,225개 모듈 로드, 개발 시 ~4.2초 추가
24
- ```
25
-
26
- **Correct (필요한 것만 로드):**
27
-
28
- ```typescript
29
- // app/page.tsx
30
- import Check from "lucide-react/dist/esm/icons/check";
31
- import X from "lucide-react/dist/esm/icons/x";
32
- import Menu from "lucide-react/dist/esm/icons/menu";
33
- // ✅ 3개 모듈만 로드 (~2KB vs ~1MB)
34
-
35
- import Button from "@mui/material/Button";
36
- import TextField from "@mui/material/TextField";
37
- // ✅ 필요한 것만 로드
38
- ```
39
-
40
- ## Mandu 프로젝트에서의 적용
41
-
42
- ```typescript
43
- // ❌ 잘못된 방식
44
- import { useAuth, useUser, usePermissions } from "@/features/auth";
45
-
46
- // ✅ 올바른 방식
47
- import { useAuth } from "@/features/auth/hooks/useAuth";
48
- import { useUser } from "@/features/auth/hooks/useUser";
49
- ```
50
-
51
- ## 자체 배럴 파일 피하기
52
-
53
- ```typescript
54
- // ❌ features/auth/index.ts (배럴 파일)
55
- export * from "./hooks/useAuth";
56
- export * from "./hooks/useUser";
57
- export * from "./components/LoginForm";
58
- export * from "./utils/validators";
59
- // 모든 것을 로드하게 만듦
60
-
61
- // ✅ 직접 import
62
- import { useAuth } from "@/features/auth/hooks/useAuth";
63
- ```
64
-
65
- ## 영향받는 일반적인 라이브러리
66
-
67
- - `lucide-react`, `react-icons`
68
- - `@mui/material`, `@mui/icons-material`
69
- - `@radix-ui/react-*`
70
- - `lodash`, `date-fns`
71
- - `@headlessui/react`
72
-
73
- ## 번들 분석
74
-
75
- ```bash
76
- # 번들 크기 분석
77
- bunx vite-bundle-visualizer
78
- ```
79
-
80
- Reference: [How we optimized package imports in Next.js](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)
@@ -1,145 +0,0 @@
1
- ---
2
- title: Lazy Load Islands with Dynamic Import
3
- impact: CRITICAL
4
- impactDescription: 40-60% smaller initial bundle
5
- tags: performance, bundle, island, lazy, dynamic-import
6
- ---
7
-
8
- ## Lazy Load Islands with Dynamic Import
9
-
10
- **Impact: CRITICAL (40-60% smaller initial bundle)**
11
-
12
- 무거운 Island 컴포넌트는 동적 import로 lazy loading하세요. 초기 번들에서 제외되어 페이지 로드가 빨라집니다.
13
-
14
- **Incorrect (즉시 로드):**
15
-
16
- ```tsx
17
- // app/dashboard/page.tsx
18
- import HeavyChart from "./client"; // ❌ 200KB 차트 라이브러리 즉시 로드
19
- import DataTable from "./table.client"; // ❌ 150KB 테이블 라이브러리 즉시 로드
20
-
21
- export default function DashboardPage() {
22
- return (
23
- <div>
24
- <h1>Dashboard</h1>
25
- <HeavyChart data={chartData} />
26
- <DataTable rows={tableData} />
27
- </div>
28
- );
29
- }
30
- ```
31
-
32
- **Correct (lazy loading):**
33
-
34
- ```tsx
35
- // app/dashboard/page.tsx
36
- import { lazy, Suspense } from "react";
37
-
38
- // ✅ 동적 import로 코드 스플리팅
39
- const HeavyChart = lazy(() => import("./client"));
40
- const DataTable = lazy(() => import("./table.client"));
41
-
42
- export default function DashboardPage() {
43
- return (
44
- <div>
45
- <h1>Dashboard</h1>
46
-
47
- <Suspense fallback={<ChartSkeleton />}>
48
- <HeavyChart data={chartData} />
49
- </Suspense>
50
-
51
- <Suspense fallback={<TableSkeleton />}>
52
- <DataTable rows={tableData} />
53
- </Suspense>
54
- </div>
55
- );
56
- }
57
- ```
58
-
59
- ## 조건부 로딩
60
-
61
- 사용자 액션 시에만 로드:
62
-
63
- ```tsx
64
- "use client";
65
-
66
- import { lazy, Suspense, useState } from "react";
67
-
68
- const HeavyEditor = lazy(() => import("./editor.client"));
69
-
70
- export default function EditorToggle() {
71
- const [showEditor, setShowEditor] = useState(false);
72
-
73
- return (
74
- <div>
75
- <button onClick={() => setShowEditor(true)}>
76
- Edit
77
- </button>
78
-
79
- {showEditor && (
80
- <Suspense fallback={<p>Loading editor...</p>}>
81
- <HeavyEditor />
82
- </Suspense>
83
- )}
84
- </div>
85
- );
86
- }
87
- ```
88
-
89
- ## Preload on Hover
90
-
91
- 호버 시 미리 로드하여 체감 속도 향상:
92
-
93
- ```tsx
94
- "use client";
95
-
96
- import { lazy, Suspense, useState } from "react";
97
-
98
- // 프리로드 함수 분리
99
- const editorImport = () => import("./editor.client");
100
- const HeavyEditor = lazy(editorImport);
101
-
102
- export default function EditorToggle() {
103
- const [showEditor, setShowEditor] = useState(false);
104
-
105
- const handleMouseEnter = () => {
106
- // ✅ 호버 시 프리로드 시작
107
- editorImport();
108
- };
109
-
110
- return (
111
- <div>
112
- <button
113
- onMouseEnter={handleMouseEnter}
114
- onClick={() => setShowEditor(true)}
115
- >
116
- Edit
117
- </button>
118
-
119
- {showEditor && (
120
- <Suspense fallback={<p>Loading...</p>}>
121
- <HeavyEditor />
122
- </Suspense>
123
- )}
124
- </div>
125
- );
126
- }
127
- ```
128
-
129
- ## Island Priority와 함께 사용
130
-
131
- ```tsx
132
- // 뷰포트 진입 시 로드 (기본값)
133
- <Island priority="visible">
134
- <Suspense fallback={<Skeleton />}>
135
- <LazyComponent />
136
- </Suspense>
137
- </Island>
138
-
139
- // 브라우저 유휴 시 로드
140
- <Island priority="idle">
141
- <Suspense fallback={<Skeleton />}>
142
- <LazyAnalytics />
143
- </Suspense>
144
- </Island>
145
- ```
@@ -1,98 +0,0 @@
1
- ---
2
- title: Use React.cache() for Request Deduplication
3
- impact: HIGH
4
- impactDescription: Eliminates duplicate queries within request
5
- tags: performance, cache, react-cache, deduplication, slot
6
- ---
7
-
8
- ## Use React.cache() for Request Deduplication
9
-
10
- **Impact: HIGH (Eliminates duplicate queries within request)**
11
-
12
- `React.cache()`를 사용하여 단일 요청 내에서 중복 쿼리를 제거하세요. 인증 확인과 데이터베이스 쿼리에 특히 효과적입니다.
13
-
14
- **사용법:**
15
-
16
- ```typescript
17
- // lib/auth.ts
18
- import { cache } from "react";
19
-
20
- export const getCurrentUser = cache(async () => {
21
- const session = await auth();
22
- if (!session?.user?.id) return null;
23
-
24
- return await db.user.findUnique({
25
- where: { id: session.user.id },
26
- });
27
- });
28
- ```
29
-
30
- 단일 요청 내에서 `getCurrentUser()`를 여러 번 호출해도 쿼리는 한 번만 실행됩니다.
31
-
32
- **Incorrect (항상 캐시 미스):**
33
-
34
- ```typescript
35
- // ❌ 인라인 객체는 매번 새 참조 생성
36
- const getUser = cache(async (params: { uid: number }) => {
37
- return await db.user.findUnique({ where: { id: params.uid } });
38
- });
39
-
40
- // 각 호출이 새 객체, 캐시 미스
41
- getUser({ uid: 1 });
42
- getUser({ uid: 1 }); // 캐시 미스, 쿼리 다시 실행
43
- ```
44
-
45
- **Correct (캐시 히트):**
46
-
47
- ```typescript
48
- // ✅ 프리미티브 인자는 값 동등성 사용
49
- const getUser = cache(async (uid: number) => {
50
- return await db.user.findUnique({ where: { id: uid } });
51
- });
52
-
53
- getUser(1);
54
- getUser(1); // ✅ 캐시 히트, 캐시된 결과 반환
55
- ```
56
-
57
- ## Mandu Slot에서의 활용
58
-
59
- ```typescript
60
- // lib/data.ts
61
- import { cache } from "react";
62
-
63
- export const getProductWithCategory = cache(async (productId: string) => {
64
- const product = await db.product.findUnique({
65
- where: { id: productId },
66
- include: { category: true },
67
- });
68
- return product;
69
- });
70
-
71
- // spec/slots/product.slot.ts
72
- import { Mandu } from "@mandujs/core";
73
- import { getProductWithCategory } from "@/lib/data";
74
-
75
- export default Mandu.filling()
76
- .get(async (ctx) => {
77
- const productId = ctx.params.id;
78
-
79
- // 여러 컴포넌트에서 호출해도 한 번만 실행
80
- const product = await getProductWithCategory(productId);
81
-
82
- return ctx.ok({ product });
83
- });
84
- ```
85
-
86
- ## React.cache() 적합한 사용 사례
87
-
88
- - 데이터베이스 쿼리 (Prisma, Drizzle 등)
89
- - 무거운 계산
90
- - 인증 확인
91
- - 파일 시스템 작업
92
- - fetch가 아닌 모든 비동기 작업
93
-
94
- ## 주의사항
95
-
96
- `React.cache()`는 요청 단위로 캐시됩니다. 요청 간 캐싱이 필요하면 LRU 캐시를 사용하세요.
97
-
98
- Reference: [React.cache documentation](https://react.dev/reference/react/cache)