@mandujs/mcp 0.12.2 → 0.13.0
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.
- package/README.md +367 -367
- package/package.json +2 -2
- package/src/activity-monitor.ts +847 -847
- package/src/adapters/index.ts +20 -20
- package/src/adapters/monitor-adapter.ts +100 -100
- package/src/adapters/tool-adapter.ts +88 -88
- package/src/executor/error-handler.ts +250 -250
- package/src/executor/index.ts +22 -22
- package/src/executor/tool-executor.ts +148 -148
- package/src/hooks/config-watcher.ts +174 -174
- package/src/hooks/index.ts +23 -23
- package/src/hooks/mcp-hooks.ts +227 -227
- package/src/index.ts +106 -106
- package/src/logging/index.ts +15 -15
- package/src/logging/mcp-transport.ts +134 -134
- package/src/registry/index.ts +13 -13
- package/src/registry/mcp-tool-registry.ts +298 -298
- package/src/resources/skills/guides.ts +1136 -1136
- package/src/resources/skills/index.ts +12 -12
- package/src/resources/skills/loader.ts +218 -218
- package/src/resources/skills/mandu-composition/SKILL.md +91 -91
- package/src/resources/skills/mandu-composition/metadata.json +13 -13
- package/src/resources/skills/mandu-composition/rules/_sections.md +26 -26
- package/src/resources/skills/mandu-composition/rules/_template.md +77 -77
- package/src/resources/skills/mandu-composition/rules/comp-arch-avoid-boolean-props.md +146 -146
- package/src/resources/skills/mandu-composition/rules/comp-arch-compound-components.md +164 -164
- package/src/resources/skills/mandu-composition/rules/comp-island-event.md +161 -161
- package/src/resources/skills/mandu-composition/rules/comp-island-slot-split.md +167 -167
- package/src/resources/skills/mandu-composition/rules/comp-pattern-children.md +149 -149
- package/src/resources/skills/mandu-composition/rules/comp-state-context-interface.md +148 -148
- package/src/resources/skills/mandu-composition/rules/comp-state-lift-state.md +150 -150
- package/src/resources/skills/mandu-deployment/SKILL.md +92 -92
- package/src/resources/skills/mandu-deployment/_sections.md +41 -41
- package/src/resources/skills/mandu-deployment/_template.md +38 -38
- package/src/resources/skills/mandu-deployment/metadata.json +13 -13
- package/src/resources/skills/mandu-deployment/rules/deploy-build-bun.md +109 -109
- package/src/resources/skills/mandu-deployment/rules/deploy-build-output.md +115 -115
- package/src/resources/skills/mandu-deployment/rules/deploy-cicd-github.md +219 -219
- package/src/resources/skills/mandu-deployment/rules/deploy-docker-bun.md +150 -150
- package/src/resources/skills/mandu-deployment/rules/deploy-docker-compose.md +223 -223
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-fly.md +152 -152
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-render.md +179 -179
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-supabase.md +323 -323
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-vercel.md +140 -140
- package/src/resources/skills/mandu-fs-routes/SKILL.md +82 -82
- package/src/resources/skills/mandu-fs-routes/metadata.json +12 -12
- package/src/resources/skills/mandu-fs-routes/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-fs-routes/rules/_template.md +69 -69
- package/src/resources/skills/mandu-fs-routes/rules/routes-api-methods.md +65 -65
- package/src/resources/skills/mandu-fs-routes/rules/routes-dynamic-param.md +93 -93
- package/src/resources/skills/mandu-fs-routes/rules/routes-naming-page.md +55 -55
- package/src/resources/skills/mandu-guard/SKILL.md +129 -129
- package/src/resources/skills/mandu-guard/metadata.json +12 -12
- package/src/resources/skills/mandu-guard/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-guard/rules/_template.md +82 -82
- package/src/resources/skills/mandu-guard/rules/guard-config-rules.md +100 -100
- package/src/resources/skills/mandu-guard/rules/guard-layer-direction.md +76 -76
- package/src/resources/skills/mandu-guard/rules/guard-preset-mandu.md +81 -81
- package/src/resources/skills/mandu-guard/rules/guard-validate-import.md +80 -80
- package/src/resources/skills/mandu-hydration/SKILL.md +91 -91
- package/src/resources/skills/mandu-hydration/metadata.json +12 -12
- package/src/resources/skills/mandu-hydration/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-hydration/rules/_template.md +72 -72
- package/src/resources/skills/mandu-hydration/rules/hydration-data-event.md +109 -109
- package/src/resources/skills/mandu-hydration/rules/hydration-directive-use-client.md +55 -55
- package/src/resources/skills/mandu-hydration/rules/hydration-island-setup.md +113 -113
- package/src/resources/skills/mandu-hydration/rules/hydration-priority-visible.md +68 -68
- package/src/resources/skills/mandu-performance/SKILL.md +85 -85
- package/src/resources/skills/mandu-performance/metadata.json +14 -14
- package/src/resources/skills/mandu-performance/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-performance/rules/_template.md +64 -64
- package/src/resources/skills/mandu-performance/rules/perf-async-defer-await.md +103 -103
- package/src/resources/skills/mandu-performance/rules/perf-async-parallel.md +95 -95
- package/src/resources/skills/mandu-performance/rules/perf-bun-file.md +124 -124
- package/src/resources/skills/mandu-performance/rules/perf-bun-serve.md +125 -125
- package/src/resources/skills/mandu-performance/rules/perf-bundle-imports.md +80 -80
- package/src/resources/skills/mandu-performance/rules/perf-bundle-island-lazy.md +145 -145
- package/src/resources/skills/mandu-performance/rules/perf-cache-react.md +98 -98
- package/src/resources/skills/mandu-performance/rules/perf-render-transitions.md +154 -154
- package/src/resources/skills/mandu-security/SKILL.md +87 -87
- package/src/resources/skills/mandu-security/metadata.json +13 -13
- package/src/resources/skills/mandu-security/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-security/rules/_template.md +74 -74
- package/src/resources/skills/mandu-security/rules/sec-auth-guard.md +127 -127
- package/src/resources/skills/mandu-security/rules/sec-env-management.md +133 -133
- package/src/resources/skills/mandu-security/rules/sec-input-validate.md +148 -148
- package/src/resources/skills/mandu-security/rules/sec-protect-csrf.md +146 -146
- package/src/resources/skills/mandu-security/rules/sec-protect-headers.md +138 -138
- package/src/resources/skills/mandu-slot/SKILL.md +85 -85
- package/src/resources/skills/mandu-slot/metadata.json +12 -12
- package/src/resources/skills/mandu-slot/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-slot/rules/_template.md +63 -63
- package/src/resources/skills/mandu-slot/rules/slot-basic-structure.md +38 -38
- package/src/resources/skills/mandu-slot/rules/slot-ctx-response.md +56 -56
- package/src/resources/skills/mandu-slot/rules/slot-guard-auth.md +59 -59
- package/src/resources/skills/mandu-slot/rules/slot-http-methods.md +64 -64
- package/src/resources/skills/mandu-styling/SKILL.md +154 -154
- package/src/resources/skills/mandu-styling/_sections.md +43 -43
- package/src/resources/skills/mandu-styling/_template.md +32 -32
- package/src/resources/skills/mandu-styling/metadata.json +15 -15
- package/src/resources/skills/mandu-styling/rules/style-component-compound.md +235 -235
- package/src/resources/skills/mandu-styling/rules/style-component-slots.md +255 -255
- package/src/resources/skills/mandu-styling/rules/style-component-tokens.md +205 -205
- package/src/resources/skills/mandu-styling/rules/style-island-animations.md +272 -272
- package/src/resources/skills/mandu-styling/rules/style-island-scoping.md +167 -167
- package/src/resources/skills/mandu-styling/rules/style-island-variants.md +221 -221
- package/src/resources/skills/mandu-styling/rules/style-perf-critical.md +209 -209
- package/src/resources/skills/mandu-styling/rules/style-perf-purge.md +192 -192
- package/src/resources/skills/mandu-styling/rules/style-setup-modules.md +162 -162
- package/src/resources/skills/mandu-styling/rules/style-setup-panda.md +164 -164
- package/src/resources/skills/mandu-styling/rules/style-setup-tailwind.md +170 -170
- package/src/resources/skills/mandu-styling/rules/style-tailwind-v4-gotchas.md +179 -179
- package/src/resources/skills/mandu-styling/rules/style-theme-darkmode.md +229 -229
- package/src/resources/skills/mandu-testing/SKILL.md +99 -99
- package/src/resources/skills/mandu-testing/metadata.json +13 -13
- package/src/resources/skills/mandu-testing/rules/_sections.md +26 -26
- package/src/resources/skills/mandu-testing/rules/_template.md +65 -65
- package/src/resources/skills/mandu-testing/rules/test-component-island.md +195 -195
- package/src/resources/skills/mandu-testing/rules/test-e2e-playwright.md +196 -196
- package/src/resources/skills/mandu-testing/rules/test-mock-fetch.md +219 -219
- package/src/resources/skills/mandu-testing/rules/test-slot-unit.md +192 -192
- package/src/resources/skills/mandu-ui/SKILL.md +117 -117
- package/src/resources/skills/mandu-ui/_sections.md +23 -23
- package/src/resources/skills/mandu-ui/_template.md +32 -32
- package/src/resources/skills/mandu-ui/metadata.json +13 -13
- package/src/resources/skills/mandu-ui/rules/ui-accessibility-aria.md +232 -232
- package/src/resources/skills/mandu-ui/rules/ui-accessibility-focus.md +238 -238
- package/src/resources/skills/mandu-ui/rules/ui-composition-patterns.md +259 -259
- package/src/resources/skills/mandu-ui/rules/ui-island-integration.md +258 -258
- package/src/resources/skills/mandu-ui/rules/ui-radix-patterns.md +213 -213
- package/src/resources/skills/mandu-ui/rules/ui-shadcn-setup.md +209 -209
- package/src/resources/skills/recipes.ts +932 -932
- package/src/tools/generate.ts +7 -4
- package/src/tools/guard.ts +17 -4
- package/src/tools/hydration.ts +10 -10
- package/src/tools/project.ts +334 -334
- package/src/tools/runtime.ts +497 -497
- package/src/tools/seo.ts +417 -417
- package/src/tools/spec.ts +80 -159
- package/src/utils/project.ts +22 -12
- package/src/utils/withWarnings.ts +83 -83
|
@@ -1,124 +1,124 @@
|
|
|
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
|
+
---
|
|
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 +1,125 @@
|
|
|
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
|
+
---
|
|
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 +1,80 @@
|
|
|
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
|
+
---
|
|
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)
|