@wooojin/forgen 0.4.8 → 0.4.9

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 (122) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/assets/dev-guide/be/README.md +226 -0
  3. package/assets/dev-guide/be/adapters/build-agents-md.sh +63 -0
  4. package/assets/dev-guide/be/principles/common.md +433 -0
  5. package/assets/dev-guide/be/principles/go.md +469 -0
  6. package/assets/dev-guide/be/principles/node.md +388 -0
  7. package/assets/dev-guide/be/skills/go/be-build/SKILL.md +262 -0
  8. package/assets/dev-guide/be/skills/go/be-perf/SKILL.md +308 -0
  9. package/assets/dev-guide/be/skills/go/be-review/SKILL.md +119 -0
  10. package/assets/dev-guide/be/skills/go/be-security/SKILL.md +362 -0
  11. package/assets/dev-guide/be/skills/node/be-build/SKILL.md +239 -0
  12. package/assets/dev-guide/be/skills/node/be-perf/SKILL.md +272 -0
  13. package/assets/dev-guide/be/skills/node/be-review/SKILL.md +118 -0
  14. package/assets/dev-guide/be/skills/node/be-security/SKILL.md +355 -0
  15. package/assets/dev-guide/be/sources/12factor/INDEX.md +53 -0
  16. package/assets/dev-guide/be/sources/api-design/INDEX.md +56 -0
  17. package/assets/dev-guide/be/sources/ddia/INDEX.md +55 -0
  18. package/assets/dev-guide/be/sources/go-runtime/INDEX.md +62 -0
  19. package/assets/dev-guide/be/sources/node-runtime/INDEX.md +60 -0
  20. package/assets/dev-guide/be/sources/otel/INDEX.md +53 -0
  21. package/assets/dev-guide/be/sources/owasp-api/INDEX.md +52 -0
  22. package/assets/dev-guide/be/sources/postgres/INDEX.md +55 -0
  23. package/assets/dev-guide/be/sources/sre-book/INDEX.md +48 -0
  24. package/assets/dev-guide/fe/README.md +197 -0
  25. package/assets/dev-guide/fe/adapters/build-agents-md.sh +63 -0
  26. package/assets/dev-guide/fe/adapters/refresh.sh +68 -0
  27. package/assets/dev-guide/fe/principles/common.md +160 -0
  28. package/assets/dev-guide/fe/principles/react.md +183 -0
  29. package/assets/dev-guide/fe/principles/vue.md +196 -0
  30. package/assets/dev-guide/fe/skills/react/fe-build/SKILL.md +139 -0
  31. package/assets/dev-guide/fe/skills/react/fe-perf/SKILL.md +179 -0
  32. package/assets/dev-guide/fe/skills/react/fe-review/SKILL.md +141 -0
  33. package/assets/dev-guide/fe/skills/vue/fe-build/SKILL.md +148 -0
  34. package/assets/dev-guide/fe/skills/vue/fe-perf/SKILL.md +163 -0
  35. package/assets/dev-guide/fe/skills/vue/fe-review/SKILL.md +136 -0
  36. package/assets/dev-guide/fe/sources/a11y-dx/INDEX.md +41 -0
  37. package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-memory.md +150 -0
  38. package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-performance.md +99 -0
  39. package/assets/dev-guide/fe/sources/a11y-dx/lighthouse-audits.md +146 -0
  40. package/assets/dev-guide/fe/sources/a11y-dx/react-devtools-profiler.md +128 -0
  41. package/assets/dev-guide/fe/sources/a11y-dx/wcag22-new-criteria.md +174 -0
  42. package/assets/dev-guide/fe/sources/perf/01-core-web-vitals.md +58 -0
  43. package/assets/dev-guide/fe/sources/perf/02-inp.md +83 -0
  44. package/assets/dev-guide/fe/sources/perf/03-lcp-cls.md +130 -0
  45. package/assets/dev-guide/fe/sources/perf/04-speculation-rules.md +148 -0
  46. package/assets/dev-guide/fe/sources/perf/05-view-transitions.md +153 -0
  47. package/assets/dev-guide/fe/sources/perf/06-nextjs-caching.md +188 -0
  48. package/assets/dev-guide/fe/sources/perf/07-server-components.md +181 -0
  49. package/assets/dev-guide/fe/sources/perf/08-ppr.md +133 -0
  50. package/assets/dev-guide/fe/sources/perf/09-nextjs-image.md +200 -0
  51. package/assets/dev-guide/fe/sources/perf/10-optimize-lcp.md +201 -0
  52. package/assets/dev-guide/fe/sources/perf/INDEX.md +88 -0
  53. package/assets/dev-guide/fe/sources/react/INDEX.md +41 -0
  54. package/assets/dev-guide/fe/sources/react/keeping-components-pure.md +135 -0
  55. package/assets/dev-guide/fe/sources/react/no-effect-patterns.md +183 -0
  56. package/assets/dev-guide/fe/sources/react/react-compiler.md +182 -0
  57. package/assets/dev-guide/fe/sources/react/server-components.md +194 -0
  58. package/assets/dev-guide/fe/sources/react/server-functions.md +192 -0
  59. package/assets/dev-guide/fe/sources/react/suspense.md +218 -0
  60. package/assets/dev-guide/fe/sources/react/use-action-state.md +123 -0
  61. package/assets/dev-guide/fe/sources/react/use-form-status.md +158 -0
  62. package/assets/dev-guide/fe/sources/react/use-hook.md +153 -0
  63. package/assets/dev-guide/fe/sources/react/use-optimistic.md +194 -0
  64. package/assets/dev-guide/fe/sources/toss-ff/INDEX.md +58 -0
  65. package/assets/dev-guide/fe/sources/toss-ff/cohesion-code-directory.md +79 -0
  66. package/assets/dev-guide/fe/sources/toss-ff/cohesion-form-fields.md +110 -0
  67. package/assets/dev-guide/fe/sources/toss-ff/cohesion-magic-number.md +47 -0
  68. package/assets/dev-guide/fe/sources/toss-ff/coupling-item-edit-modal.md +124 -0
  69. package/assets/dev-guide/fe/sources/toss-ff/coupling-use-bottom-sheet.md +57 -0
  70. package/assets/dev-guide/fe/sources/toss-ff/coupling-use-page-state.md +71 -0
  71. package/assets/dev-guide/fe/sources/toss-ff/overview-4-principles.md +77 -0
  72. package/assets/dev-guide/fe/sources/toss-ff/predictability-hidden-logic.md +59 -0
  73. package/assets/dev-guide/fe/sources/toss-ff/predictability-http.md +77 -0
  74. package/assets/dev-guide/fe/sources/toss-ff/predictability-use-user.md +110 -0
  75. package/assets/dev-guide/fe/sources/toss-ff/readability-comparison-order.md +52 -0
  76. package/assets/dev-guide/fe/sources/toss-ff/readability-condition-name.md +64 -0
  77. package/assets/dev-guide/fe/sources/toss-ff/readability-login-start-page.md +183 -0
  78. package/assets/dev-guide/fe/sources/toss-ff/readability-magic-number.md +53 -0
  79. package/assets/dev-guide/fe/sources/toss-ff/readability-submit-button.md +73 -0
  80. package/assets/dev-guide/fe/sources/toss-ff/readability-ternary-operator.md +38 -0
  81. package/assets/dev-guide/fe/sources/toss-ff/readability-use-page-state.md +77 -0
  82. package/assets/dev-guide/fe/sources/toss-ff/readability-user-policy.md +98 -0
  83. package/assets/dev-guide/fe/sources/vue/INDEX.md +17 -0
  84. package/assets/dev-guide/fe/sources/vue/composition-api.md +251 -0
  85. package/assets/dev-guide/fe/sources/vue/nuxt-data-fetching.md +232 -0
  86. package/assets/dev-guide/fe/sources/vue/pinia-state-management.md +134 -0
  87. package/assets/dev-guide/fe/sources/vue/reactivity-pitfalls.md +261 -0
  88. package/assets/dev-guide/fe/sources/vue/style-guide-priority-a.md +117 -0
  89. package/assets/dev-guide/fe/sources/vue/style-guide-priority-b.md +231 -0
  90. package/assets/dev-guide/fe/sources/vue/style-guide-priority-c.md +86 -0
  91. package/assets/dev-guide/fe/sources/vue/style-guide-priority-d.md +72 -0
  92. package/dist/cli.js +42 -0
  93. package/dist/core/dashboard-cli.d.ts +12 -0
  94. package/dist/core/dashboard-cli.js +226 -0
  95. package/dist/core/dev-guide-injector.d.ts +26 -0
  96. package/dist/core/dev-guide-injector.js +137 -0
  97. package/dist/core/init.js +53 -0
  98. package/dist/core/lifecycle-classifier.d.ts +23 -0
  99. package/dist/core/lifecycle-classifier.js +104 -0
  100. package/dist/core/observability-backfill.d.ts +31 -0
  101. package/dist/core/observability-backfill.js +178 -0
  102. package/dist/core/observability-store.d.ts +58 -0
  103. package/dist/core/observability-store.js +195 -0
  104. package/dist/core/session-store.js +4 -0
  105. package/dist/core/spawn.d.ts +17 -0
  106. package/dist/core/spawn.js +179 -2
  107. package/dist/core/statusline-cli.js +34 -1
  108. package/dist/engine/compound-extractor.js +39 -0
  109. package/dist/engine/compound-loop.js +6 -0
  110. package/dist/engine/compound-retire.d.ts +20 -0
  111. package/dist/engine/compound-retire.js +85 -0
  112. package/dist/hooks/context-guard.js +25 -1
  113. package/dist/hooks/post-tool-use.js +48 -0
  114. package/dist/hooks/solution-injector.js +93 -0
  115. package/dist/host/install-claude.d.ts +6 -2
  116. package/dist/host/install-claude.js +74 -2
  117. package/dist/host/install-codex.d.ts +4 -0
  118. package/dist/host/install-codex.js +71 -0
  119. package/dist/host/install-orchestrator.js +1 -0
  120. package/package.json +6 -6
  121. package/plugin.json +1 -1
  122. package/scripts/postinstall.js +134 -0
@@ -0,0 +1,182 @@
1
+ ---
2
+ title: React Compiler (자동 메모이제이션)
3
+ source: https://react.dev/learn/react-compiler
4
+ fetched: 2026-05-18
5
+ category: compiler
6
+ react_version: 19
7
+ ---
8
+
9
+ ## 개요
10
+
11
+ React Compiler는 `useMemo`, `useCallback`, `React.memo`를 수동으로 작성할 필요 없이 자동으로 메모이제이션을 처리하는 빌드타임 최적화 도구.
12
+
13
+ **핵심 기능:**
14
+ - 컴포넌트와 계산값 자동 메모이제이션
15
+ - 수동 `useMemo` / `useCallback` 대체
16
+ - 설정 없이 기본적으로 React 앱 최적화
17
+ - React 19 권장, React 17/18도 지원
18
+
19
+ ---
20
+
21
+ ## 설치
22
+
23
+ ```bash
24
+ npm install -D babel-plugin-react-compiler@latest
25
+ # 또는
26
+ yarn add -D babel-plugin-react-compiler@latest
27
+ # 또는
28
+ pnpm install -D babel-plugin-react-compiler@latest
29
+ ```
30
+
31
+ ---
32
+
33
+ ## 빌드 도구별 설정
34
+
35
+ ### Babel
36
+
37
+ ```js
38
+ // babel.config.js
39
+ module.exports = {
40
+ plugins: [
41
+ 'babel-plugin-react-compiler', // 반드시 첫 번째로!
42
+ // ... 다른 플러그인
43
+ ],
44
+ };
45
+ ```
46
+
47
+ > **중요**: React Compiler는 Babel 플러그인 파이프라인에서 **첫 번째**로 실행되어야 함.
48
+
49
+ ### Vite (v6.0.0+)
50
+
51
+ ```bash
52
+ npm install -D @rolldown/plugin-babel
53
+ ```
54
+
55
+ ```js
56
+ // vite.config.js
57
+ import { defineConfig } from 'vite';
58
+ import react, { reactCompilerPreset } from '@vitejs/plugin-react';
59
+ import babel from '@rolldown/plugin-babel';
60
+
61
+ export default defineConfig({
62
+ plugins: [
63
+ react(),
64
+ babel({
65
+ presets: [reactCompilerPreset()],
66
+ }),
67
+ ],
68
+ });
69
+ ```
70
+
71
+ Vite 구버전 (6.0.0 미만):
72
+ ```js
73
+ // vite.config.js
74
+ import { defineConfig } from 'vite';
75
+ import react from '@vitejs/plugin-react';
76
+
77
+ export default defineConfig({
78
+ plugins: [
79
+ react({
80
+ babel: {
81
+ plugins: ['babel-plugin-react-compiler'],
82
+ },
83
+ }),
84
+ ],
85
+ });
86
+ ```
87
+
88
+ ### React Router (Vite)
89
+
90
+ ```bash
91
+ npm install vite-plugin-babel
92
+ ```
93
+
94
+ ```js
95
+ // vite.config.js
96
+ import { defineConfig } from "vite";
97
+ import babel from "vite-plugin-babel";
98
+ import { reactRouter } from "@react-router/dev/vite";
99
+
100
+ const ReactCompilerConfig = { /* ... */ };
101
+
102
+ export default defineConfig({
103
+ plugins: [
104
+ reactRouter(),
105
+ babel({
106
+ filter: /\.[jt]sx?$/,
107
+ babelConfig: {
108
+ presets: ["@babel/preset-typescript"], // TypeScript 사용 시
109
+ plugins: [
110
+ ["babel-plugin-react-compiler", ReactCompilerConfig],
111
+ ],
112
+ },
113
+ }),
114
+ ],
115
+ });
116
+ ```
117
+
118
+ ### Next.js
119
+ [Next.js 공식 문서](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) 참조.
120
+
121
+ ---
122
+
123
+ ## ESLint 플러그인
124
+
125
+ ```bash
126
+ npm install -D eslint-plugin-react-hooks@latest
127
+ ```
128
+
129
+ `recommended-latest` 프리셋에 컴파일러 규칙 포함:
130
+ - Rules of React 위반 식별
131
+ - 최적화 불가 컴포넌트 표시
132
+ - 수정 방법 에러 메시지 제공
133
+
134
+ ---
135
+
136
+ ## 적용 확인
137
+
138
+ ### React DevTools
139
+ 1. React Developer Tools 브라우저 확장 설치
140
+ 2. 개발 모드로 앱 실행
141
+ 3. React DevTools 열기
142
+ 4. 컴포넌트 이름 옆 ✨ 이모지 확인 → "Memo ✨" 뱃지
143
+
144
+ ### 빌드 출력 확인
145
+
146
+ 컴파일된 코드에 자동 메모이제이션 로직 포함:
147
+ ```js
148
+ import { c as _c } from "react/compiler-runtime";
149
+
150
+ export default function MyApp() {
151
+ const $ = _c(1);
152
+ let t0;
153
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
154
+ t0 = <div>Hello World</div>;
155
+ $[0] = t0;
156
+ } else {
157
+ t0 = $[0];
158
+ }
159
+ return t0;
160
+ }
161
+ ```
162
+
163
+ ---
164
+
165
+ ## 특정 컴포넌트 최적화 제외
166
+
167
+ ```js
168
+ function ProblematicComponent() {
169
+ "use no memo"; // 이 컴포넌트만 컴파일러 건너뜀
170
+ // ...
171
+ }
172
+ ```
173
+
174
+ ---
175
+
176
+ ## 요약: 이전 vs 이후
177
+
178
+ | 이전 (수동) | 이후 (컴파일러) |
179
+ |------------|----------------|
180
+ | `const memoVal = useMemo(() => compute(a, b), [a, b])` | 자동 처리 |
181
+ | `const cb = useCallback(() => fn(x), [x])` | 자동 처리 |
182
+ | `export default React.memo(MyComponent)` | 자동 처리 |
@@ -0,0 +1,194 @@
1
+ ---
2
+ title: Server Components
3
+ source: https://react.dev/reference/rsc/server-components
4
+ fetched: 2026-05-18
5
+ category: rsc
6
+ react_version: 19
7
+ ---
8
+
9
+ ## 개요
10
+
11
+ Server Components는 번들링 전, 클라이언트 앱/SSR 서버와 분리된 환경에서 렌더링되는 새로운 React 컴포넌트 유형.
12
+
13
+ **핵심 특징:**
14
+ - 빌드 타임 또는 요청마다 서버에서 렌더링
15
+ - `useState` 등 인터랙티브 API 사용 불가
16
+ - `async/await` 직접 사용 가능
17
+ - 브라우저에 전송되지 않음 (번들에 포함 안 됨)
18
+ - **`"use server"` 디렉티브 없음** — Server Component는 기본값; `"use client"` / `"use server"`만 존재
19
+
20
+ ---
21
+
22
+ ## 사용 사례 1: 서버 없는 빌드타임 렌더링
23
+
24
+ 무거운 라이브러리를 번들에 포함하지 않고 빌드 시 처리:
25
+
26
+ ❌ 기존 방식 (클라이언트 번들에 35.9K + 206K 추가):
27
+ ```js
28
+ import marked from 'marked'; // 35.9K (11.2K gzipped)
29
+ import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)
30
+
31
+ function Page({ page }) {
32
+ const [content, setContent] = useState('');
33
+ useEffect(() => {
34
+ fetch(`/api/content/${page}`).then((data) => {
35
+ setContent(data.content);
36
+ });
37
+ }, [page]);
38
+ return <div>{sanitizeHtml(marked(content))}</div>;
39
+ }
40
+ ```
41
+
42
+ ✅ Server Component (번들 크기 0):
43
+ ```js
44
+ import marked from 'marked'; // 번들에 포함되지 않음
45
+ import sanitizeHtml from 'sanitize-html'; // 번들에 포함되지 않음
46
+
47
+ async function Page({ page }) {
48
+ const content = await file.readFile(`${page}.md`);
49
+ return <div>{sanitizeHtml(marked(content))}</div>;
50
+ }
51
+ ```
52
+
53
+ 클라이언트 출력:
54
+ ```js
55
+ <div><!-- html for markdown --></div>
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 사용 사례 2: 요청마다 서버 데이터 페칭
61
+
62
+ 클라이언트 waterfall 없이 서버에서 직접 DB 쿼리:
63
+
64
+ ❌ 기존 방식 (N+1 waterfall):
65
+ ```js
66
+ function Note({ id }) {
67
+ const [note, setNote] = useState('');
68
+ useEffect(() => {
69
+ fetch(`/api/notes/${id}`).then(data => setNote(data.note));
70
+ }, [id]);
71
+
72
+ return (
73
+ <div>
74
+ <Author id={note.authorId} />
75
+ <p>{note}</p>
76
+ </div>
77
+ );
78
+ }
79
+
80
+ function Author({ id }) {
81
+ const [author, setAuthor] = useState('');
82
+ useEffect(() => {
83
+ fetch(`/api/authors/${id}`).then(data => setAuthor(data.author));
84
+ }, [id]);
85
+ return <span>By: {author.name}</span>;
86
+ }
87
+ ```
88
+
89
+ ✅ Server Component (병렬 DB 쿼리):
90
+ ```js
91
+ import db from './database';
92
+
93
+ async function Note({ id }) {
94
+ const note = await db.notes.get(id);
95
+ return (
96
+ <div>
97
+ <Author id={note.authorId} />
98
+ <p>{note}</p>
99
+ </div>
100
+ );
101
+ }
102
+
103
+ async function Author({ id }) {
104
+ const author = await db.authors.get(id);
105
+ return <span>By: {author.name}</span>;
106
+ }
107
+ ```
108
+
109
+ 클라이언트 출력:
110
+ ```js
111
+ <div>
112
+ <span>By: The React Team</span>
113
+ <p>React 19 is...</p>
114
+ </div>
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 인터랙티비티 추가: Server + Client 조합
120
+
121
+ `"use client"` 디렉티브로 Client Component와 합성:
122
+
123
+ ```js
124
+ // Server Component
125
+ import Expandable from './Expandable';
126
+
127
+ async function Notes() {
128
+ const notes = await db.notes.getAll();
129
+ return (
130
+ <div>
131
+ {notes.map(note => (
132
+ <Expandable key={note.id}>
133
+ <p note={note} />
134
+ </Expandable>
135
+ ))}
136
+ </div>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ```js
142
+ // Client Component
143
+ "use client"
144
+
145
+ export default function Expandable({ children }) {
146
+ const [expanded, setExpanded] = useState(false);
147
+ return (
148
+ <div>
149
+ <button onClick={() => setExpanded(!expanded)}>Toggle</button>
150
+ {expanded && children}
151
+ </div>
152
+ );
153
+ }
154
+ ```
155
+
156
+ ---
157
+
158
+ ## Promise를 서버→클라이언트로 전달
159
+
160
+ ```js
161
+ // Server Component
162
+ import db from './database';
163
+
164
+ async function Page({ id }) {
165
+ const note = await db.notes.get(id); // 서버에서 await
166
+ const commentsPromise = db.comments.get(note.id); // 시작만, 클라이언트에서 await
167
+
168
+ return (
169
+ <div>
170
+ {note}
171
+ <Suspense fallback={<p>Loading Comments...</p>}>
172
+ <Comments commentsPromise={commentsPromise} />
173
+ </Suspense>
174
+ </div>
175
+ );
176
+ }
177
+ ```
178
+
179
+ ```js
180
+ // Client Component
181
+ "use client";
182
+ import { use } from 'react';
183
+
184
+ function Comments({ commentsPromise }) {
185
+ const comments = use(commentsPromise); // 서버에서 시작된 Promise 이어서 처리
186
+ return comments.map(comment => <p>{comment}</p>);
187
+ }
188
+ ```
189
+
190
+ ---
191
+
192
+ ## API 안정성 주의
193
+
194
+ > Server Component 구현을 위한 번들러/프레임워크 API는 semver를 따르지 않으며 React 19.x 마이너 버전 간 breaking change 가능. 특정 React 버전에 pin하거나 Canary 릴리스 사용 권장.
@@ -0,0 +1,192 @@
1
+ ---
2
+ title: Server Functions ('use server' / 'use client')
3
+ source: https://react.dev/reference/rsc/server-functions
4
+ fetched: 2026-05-18
5
+ category: rsc
6
+ react_version: 19
7
+ ---
8
+
9
+ ## 개요
10
+
11
+ Server Functions는 `"use server"` 디렉티브로 정의된 서버에서 실행되는 비동기 함수. Client Component에서 호출 가능.
12
+
13
+ > **Note**: 2024년 9월 이전에는 "Server Actions"라고 불렸음. Server Actions는 action props에 전달되거나 action 내부에서 호출되는 Server Functions이지만, 모든 Server Functions가 Server Actions는 아님.
14
+
15
+ **동작 원리**: 프레임워크가 자동으로 함수 참조를 생성하고, 클라이언트에서 호출 시 서버로 요청을 전송하고 결과를 반환.
16
+
17
+ ---
18
+
19
+ ## 'use server' vs 'use client'
20
+
21
+ | 디렉티브 | 위치 | 의미 |
22
+ |----------|------|------|
23
+ | `"use server"` | 파일 상단 또는 함수 첫 줄 | 이 함수/모듈은 서버에서만 실행 |
24
+ | `"use client"` | 파일 상단 | 이 컴포넌트는 클라이언트에서 실행 |
25
+ | (없음) | — | Server Component (기본값) |
26
+
27
+ ---
28
+
29
+ ## 사용 패턴
30
+
31
+ ### 1. Server Component 내부에서 Server Function 정의
32
+
33
+ ```js
34
+ // Server Component
35
+ import Button from './Button';
36
+
37
+ function EmptyNote() {
38
+ async function createNoteAction() {
39
+ 'use server'; // 함수 레벨 디렉티브
40
+
41
+ await db.notes.create();
42
+ }
43
+
44
+ return <Button onClick={createNoteAction} />;
45
+ }
46
+ ```
47
+
48
+ Client Component에서 참조 확인:
49
+ ```js
50
+ "use client";
51
+
52
+ export default function Button({ onClick }) {
53
+ console.log(onClick);
54
+ // { $$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction' }
55
+ return <button onClick={() => onClick()}>Create Empty Note</button>;
56
+ }
57
+ ```
58
+
59
+ ### 2. 별도 파일에서 Server Functions 내보내기
60
+
61
+ ```js
62
+ // actions.js
63
+ "use server"; // 파일 레벨 디렉티브
64
+
65
+ export async function createNote() {
66
+ await db.notes.create();
67
+ }
68
+ ```
69
+
70
+ ```js
71
+ // Client Component
72
+ "use client";
73
+ import { createNote } from './actions';
74
+
75
+ function EmptyNote() {
76
+ return <button onClick={() => createNote()} />;
77
+ }
78
+ ```
79
+
80
+ ### 3. useTransition과 함께 (Actions)
81
+
82
+ ```js
83
+ // actions.js
84
+ "use server";
85
+
86
+ export async function updateName(name) {
87
+ if (!name) {
88
+ return { error: 'Name is required' };
89
+ }
90
+ await db.users.updateName(name);
91
+ }
92
+ ```
93
+
94
+ ```js
95
+ // Client Component
96
+ "use client";
97
+ import { updateName } from './actions';
98
+ import { useTransition, useState } from 'react';
99
+
100
+ function UpdateName() {
101
+ const [name, setName] = useState('');
102
+ const [error, setError] = useState(null);
103
+ const [isPending, startTransition] = useTransition();
104
+
105
+ const submitAction = async () => {
106
+ startTransition(async () => {
107
+ const { error } = await updateName(name);
108
+ if (error) {
109
+ setError(error);
110
+ } else {
111
+ setName('');
112
+ }
113
+ });
114
+ };
115
+
116
+ return (
117
+ <form action={submitAction}>
118
+ <input type="text" name="name" disabled={isPending} />
119
+ {error && <span>Failed: {error}</span>}
120
+ </form>
121
+ );
122
+ }
123
+ ```
124
+
125
+ ### 4. Form Action으로 직접 사용
126
+
127
+ ```js
128
+ "use client";
129
+ import { updateName } from './actions';
130
+
131
+ function UpdateName() {
132
+ return (
133
+ <form action={updateName}>
134
+ <input type="text" name="name" />
135
+ </form>
136
+ );
137
+ }
138
+ ```
139
+
140
+ > 성공 시 React가 자동으로 폼 리셋.
141
+
142
+ ### 5. useActionState와 조합
143
+
144
+ ```js
145
+ "use client";
146
+ import { updateName } from './actions';
147
+ import { useActionState } from 'react';
148
+
149
+ function UpdateName() {
150
+ const [state, submitAction, isPending] = useActionState(updateName, { error: null });
151
+
152
+ return (
153
+ <form action={submitAction}>
154
+ <input type="text" name="name" disabled={isPending} />
155
+ {state.error && <span>Failed: {state.error}</span>}
156
+ </form>
157
+ );
158
+ }
159
+ ```
160
+
161
+ **이점:**
162
+ - pending state 접근
163
+ - 마지막 반환 응답 접근
164
+ - hydration 전 폼 자동 재실행
165
+ - 점진적 향상 지원
166
+
167
+ ### 6. 점진적 향상 (Progressive Enhancement)
168
+
169
+ ```js
170
+ "use client";
171
+ import { updateName } from './actions';
172
+ import { useActionState } from 'react';
173
+
174
+ function UpdateName() {
175
+ const [, submitAction] = useActionState(updateName, null, `/name/update`);
176
+
177
+ return (
178
+ <form action={submitAction}>
179
+ {/* form fields */}
180
+ </form>
181
+ );
182
+ }
183
+ ```
184
+
185
+ > 세 번째 인자(permalink)를 전달하면 JavaScript 로드 전 폼 제출 시 해당 URL로 리다이렉트.
186
+
187
+ ---
188
+
189
+ ## API 안정성
190
+
191
+ - React 19의 Server Functions 자체: stable
192
+ - 번들러/프레임워크 구현 API: semver 미준수, 마이너 버전 간 breaking change 가능