@simplysm/sd-cli 14.0.16 → 14.0.18

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 (202) hide show
  1. package/README.md +2 -1
  2. package/dist/angular/client-transform-stylesheet.d.ts +2 -0
  3. package/dist/angular/client-transform-stylesheet.d.ts.map +1 -1
  4. package/dist/angular/client-transform-stylesheet.js +88 -2
  5. package/dist/angular/client-transform-stylesheet.js.map +1 -1
  6. package/dist/angular/vite-angular-plugin.d.ts +7 -0
  7. package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
  8. package/dist/angular/vite-angular-plugin.js +78 -16
  9. package/dist/angular/vite-angular-plugin.js.map +1 -1
  10. package/dist/capacitor/capacitor.d.ts.map +1 -1
  11. package/dist/capacitor/capacitor.js +9 -13
  12. package/dist/capacitor/capacitor.js.map +1 -1
  13. package/dist/commands/check.d.ts.map +1 -1
  14. package/dist/commands/check.js +8 -9
  15. package/dist/commands/check.js.map +1 -1
  16. package/dist/commands/device.d.ts.map +1 -1
  17. package/dist/commands/device.js +33 -1
  18. package/dist/commands/device.js.map +1 -1
  19. package/dist/commands/lint.d.ts +0 -1
  20. package/dist/commands/lint.d.ts.map +1 -1
  21. package/dist/commands/lint.js +2 -3
  22. package/dist/commands/lint.js.map +1 -1
  23. package/dist/commands/publish.js +2 -2
  24. package/dist/commands/publish.js.map +1 -1
  25. package/dist/commands/typecheck.d.ts.map +1 -1
  26. package/dist/commands/typecheck.js +0 -1
  27. package/dist/commands/typecheck.js.map +1 -1
  28. package/dist/electron/electron.d.ts +3 -2
  29. package/dist/electron/electron.d.ts.map +1 -1
  30. package/dist/electron/electron.js +54 -31
  31. package/dist/electron/electron.js.map +1 -1
  32. package/dist/engines/BaseEngine.js +1 -1
  33. package/dist/engines/BaseEngine.js.map +1 -1
  34. package/dist/engines/NgtscEngine.d.ts.map +1 -1
  35. package/dist/engines/NgtscEngine.js +0 -1
  36. package/dist/engines/NgtscEngine.js.map +1 -1
  37. package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
  38. package/dist/engines/ServerEsbuildEngine.js +0 -1
  39. package/dist/engines/ServerEsbuildEngine.js.map +1 -1
  40. package/dist/engines/TscEngine.d.ts.map +1 -1
  41. package/dist/engines/TscEngine.js +0 -1
  42. package/dist/engines/TscEngine.js.map +1 -1
  43. package/dist/engines/ViteEngine.d.ts.map +1 -1
  44. package/dist/engines/ViteEngine.js +8 -1
  45. package/dist/engines/ViteEngine.js.map +1 -1
  46. package/dist/engines/index.d.ts +0 -10
  47. package/dist/engines/index.d.ts.map +1 -1
  48. package/dist/engines/index.js +0 -5
  49. package/dist/engines/index.js.map +1 -1
  50. package/dist/engines/types.d.ts +0 -1
  51. package/dist/engines/types.d.ts.map +1 -1
  52. package/dist/infra/SignalHandler.d.ts +1 -6
  53. package/dist/infra/SignalHandler.d.ts.map +1 -1
  54. package/dist/infra/SignalHandler.js +4 -13
  55. package/dist/infra/SignalHandler.js.map +1 -1
  56. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  57. package/dist/orchestrators/BuildOrchestrator.js +7 -12
  58. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  59. package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
  60. package/dist/orchestrators/DevWatchOrchestrator.js +17 -10
  61. package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
  62. package/dist/sd-cli-entry.d.ts +0 -1
  63. package/dist/sd-cli-entry.d.ts.map +1 -1
  64. package/dist/sd-cli-entry.js +7 -8
  65. package/dist/sd-cli-entry.js.map +1 -1
  66. package/dist/sd-config.types.d.ts +11 -1
  67. package/dist/sd-config.types.d.ts.map +1 -1
  68. package/dist/utils/angular-compiler.d.ts.map +1 -1
  69. package/dist/utils/angular-compiler.js +20 -13
  70. package/dist/utils/angular-compiler.js.map +1 -1
  71. package/dist/utils/esbuild-config.d.ts +1 -1
  72. package/dist/utils/esbuild-config.d.ts.map +1 -1
  73. package/dist/utils/esbuild-config.js +1 -4
  74. package/dist/utils/esbuild-config.js.map +1 -1
  75. package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
  76. package/dist/utils/ngtsc-build-core.js +3 -0
  77. package/dist/utils/ngtsc-build-core.js.map +1 -1
  78. package/dist/utils/tsc-build.d.ts +5 -0
  79. package/dist/utils/tsc-build.d.ts.map +1 -1
  80. package/dist/utils/tsc-build.js +2 -1
  81. package/dist/utils/tsc-build.js.map +1 -1
  82. package/dist/utils/vite-config.d.ts +1 -1
  83. package/dist/utils/vite-config.d.ts.map +1 -1
  84. package/dist/utils/vite-config.js +22 -53
  85. package/dist/utils/vite-config.js.map +1 -1
  86. package/dist/utils/vite-pwa-plugin.d.ts +9 -0
  87. package/dist/utils/vite-pwa-plugin.d.ts.map +1 -0
  88. package/dist/utils/vite-pwa-plugin.js +139 -0
  89. package/dist/utils/vite-pwa-plugin.js.map +1 -0
  90. package/dist/utils/worker-utils.d.ts +2 -5
  91. package/dist/utils/worker-utils.d.ts.map +1 -1
  92. package/dist/utils/worker-utils.js +5 -11
  93. package/dist/utils/worker-utils.js.map +1 -1
  94. package/dist/workers/client.worker.d.ts.map +1 -1
  95. package/dist/workers/client.worker.js +9 -3
  96. package/dist/workers/client.worker.js.map +1 -1
  97. package/dist/workers/library-build.worker.d.ts.map +1 -1
  98. package/dist/workers/library-build.worker.js +6 -2
  99. package/dist/workers/library-build.worker.js.map +1 -1
  100. package/dist/workers/ngtsc-build.worker.js +2 -2
  101. package/dist/workers/ngtsc-build.worker.js.map +1 -1
  102. package/dist/workers/server-build.worker.d.ts.map +1 -1
  103. package/dist/workers/server-build.worker.js +6 -2
  104. package/dist/workers/server-build.worker.js.map +1 -1
  105. package/dist/workers/server-runtime.worker.js +4 -4
  106. package/dist/workers/server-runtime.worker.js.map +1 -1
  107. package/docs/config.md +26 -0
  108. package/docs/pwa-configuration-types.md +1 -1
  109. package/package.json +8 -10
  110. package/src/angular/client-transform-stylesheet.ts +104 -2
  111. package/src/angular/vite-angular-plugin.ts +92 -31
  112. package/src/capacitor/capacitor.ts +10 -26
  113. package/src/commands/check.ts +8 -11
  114. package/src/commands/device.ts +38 -3
  115. package/src/commands/lint.ts +2 -3
  116. package/src/commands/publish.ts +2 -2
  117. package/src/commands/typecheck.ts +0 -1
  118. package/src/electron/electron.ts +62 -43
  119. package/src/engines/BaseEngine.ts +1 -1
  120. package/src/engines/NgtscEngine.ts +0 -1
  121. package/src/engines/ServerEsbuildEngine.ts +0 -1
  122. package/src/engines/TscEngine.ts +0 -1
  123. package/src/engines/ViteEngine.ts +7 -1
  124. package/src/engines/index.ts +0 -10
  125. package/src/engines/types.ts +0 -1
  126. package/src/infra/SignalHandler.ts +4 -14
  127. package/src/orchestrators/BuildOrchestrator.ts +7 -9
  128. package/src/orchestrators/DevWatchOrchestrator.ts +21 -9
  129. package/src/sd-cli-entry.ts +11 -16
  130. package/src/sd-config.types.ts +12 -1
  131. package/src/utils/angular-compiler.ts +21 -21
  132. package/src/utils/esbuild-config.ts +2 -5
  133. package/src/utils/ngtsc-build-core.ts +7 -0
  134. package/src/utils/tsc-build.ts +7 -0
  135. package/src/utils/vite-config.ts +23 -55
  136. package/src/utils/vite-pwa-plugin.ts +168 -0
  137. package/src/utils/worker-utils.ts +5 -11
  138. package/src/workers/client.worker.ts +11 -3
  139. package/src/workers/library-build.worker.ts +6 -2
  140. package/src/workers/ngtsc-build.worker.ts +2 -2
  141. package/src/workers/server-build.worker.ts +7 -2
  142. package/src/workers/server-runtime.worker.ts +4 -4
  143. package/tests/angular/client-transform-stylesheet.spec.ts +43 -0
  144. package/tests/angular/find-affected-by-scss.spec.ts +37 -0
  145. package/tests/angular/fixtures/basic-app/scss/_colors.scss +1 -0
  146. package/tests/angular/fixtures/basic-app/scss/_variables.scss +3 -0
  147. package/tests/angular/fixtures/basic-app/src/styled.component.ts +14 -0
  148. package/tests/angular/linker-disk-cache.spec.ts +158 -0
  149. package/tests/angular/scss-disk-cache.spec.ts +162 -0
  150. package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +15 -15
  151. package/tests/angular/vite-angular-plugin-hmr.spec.ts +9 -9
  152. package/tests/angular/vite-angular-plugin-lint.spec.ts +4 -4
  153. package/tests/angular/vite-angular-plugin-scss-hmr.spec.ts +87 -0
  154. package/tests/angular/vite-angular-plugin.spec.ts +15 -15
  155. package/tests/capacitor/capacitor-icon.spec.ts +2 -4
  156. package/tests/capacitor/capacitor-init.spec.ts +2 -4
  157. package/tests/capacitor/capacitor-workspace.spec.ts +2 -4
  158. package/tests/commands/device.spec.ts +100 -0
  159. package/tests/electron/electron.spec.ts +24 -17
  160. package/tests/engines/ngtsc-engine.spec.ts +0 -3
  161. package/tests/engines/server-esbuild-engine.spec.ts +0 -3
  162. package/tests/engines/tsc-engine.spec.ts +1 -2
  163. package/tests/engines/vite-engine.spec.ts +0 -2
  164. package/tests/infra/signal-handler.spec.ts +1 -12
  165. package/tests/orchestrators/build-orchestrator.spec.ts +0 -6
  166. package/tests/orchestrators/dev-watch-orchestrator.spec.ts +24 -66
  167. package/tests/utils/angular-compiler.spec.ts +1396 -32
  168. package/tests/utils/esbuild-config.spec.ts +4 -7
  169. package/tests/utils/{ngtsc-build-core-angular-compiler.spec.ts → ngtsc-build-core.spec.ts} +142 -11
  170. package/tests/utils/tsc-build.spec.ts +4 -1
  171. package/tests/utils/vite-config.spec.ts +130 -261
  172. package/tests/utils/vite-pwa-plugin.acc.spec.ts +143 -0
  173. package/tests/utils/vite-pwa-plugin.spec.ts +350 -0
  174. package/tests/utils/worker-utils.spec.ts +8 -7
  175. package/tests/workers/client-worker.spec.ts +50 -1
  176. package/tests/workers/dev-port-file.verify.md +6 -0
  177. package/tests/workers/library-build-lint.spec.ts +1 -1
  178. package/tests/workers/library-build-worker.spec.ts +1 -1
  179. package/tests/workers/ngtsc-build-lint.spec.ts +1 -1
  180. package/tests/workers/server-build-lint.spec.ts +1 -1
  181. package/tests/workers/server-build-worker.spec.ts +1 -1
  182. package/tests/workers/server-runtime-worker.spec.ts +8 -1
  183. package/dist/infra/WorkerManager.d.ts +0 -40
  184. package/dist/infra/WorkerManager.d.ts.map +0 -1
  185. package/dist/infra/WorkerManager.js +0 -59
  186. package/dist/infra/WorkerManager.js.map +0 -1
  187. package/dist/utils/SdCliReporter.d.ts +0 -18
  188. package/dist/utils/SdCliReporter.d.ts.map +0 -1
  189. package/dist/utils/SdCliReporter.js +0 -144
  190. package/dist/utils/SdCliReporter.js.map +0 -1
  191. package/src/infra/WorkerManager.ts +0 -65
  192. package/src/utils/SdCliReporter.ts +0 -177
  193. package/tests/angular/scss-compiler-async.spec.ts +0 -54
  194. package/tests/commands/dev.spec.ts +0 -53
  195. package/tests/commands/watch.spec.ts +0 -53
  196. package/tests/infra/worker-manager.spec.ts +0 -63
  197. package/tests/utils/angular-compiler-emit.spec.ts +0 -570
  198. package/tests/utils/angular-compiler-init.spec.ts +0 -705
  199. package/tests/utils/angular-compiler-update.spec.ts +0 -293
  200. package/tests/utils/build-env.spec.ts +0 -33
  201. package/tests/utils/ngtsc-build-core-transform-stylesheet.spec.ts +0 -124
  202. package/tests/utils/ngtsc-scss-refactor.spec.ts +0 -47
@@ -2,10 +2,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
2
 
3
3
  // --- Mock factories ---
4
4
 
5
- vi.mock("vite-tsconfig-paths", () => ({
6
- default: vi.fn(() => ({ name: "vite-tsconfig-paths" })),
7
- }));
8
-
9
5
  const mockSdAngularPlugin = vi.fn(() => ({ name: "sd-angular-plugin" }));
10
6
  vi.mock("../../src/angular/vite-angular-plugin.js", () => ({
11
7
  sdAngularPlugin: mockSdAngularPlugin,
@@ -35,14 +31,9 @@ vi.mock("browserslist-to-esbuild", () => ({
35
31
  }),
36
32
  }));
37
33
 
38
- const mockVitePWA = vi.fn(() => ({ name: "vite-plugin-pwa" }));
39
- vi.mock("vite-plugin-pwa", () => ({
40
- VitePWA: mockVitePWA,
41
- }));
42
-
43
- const mockGeneratePwaIcons = vi.fn().mockResolvedValue([]);
44
- vi.mock("../../src/utils/generate-pwa-icons.js", () => ({
45
- generatePwaIcons: mockGeneratePwaIcons,
34
+ const mockSdPwaPlugin = vi.fn(() => ({ name: "sd-pwa" }));
35
+ vi.mock("../../src/utils/vite-pwa-plugin.js", () => ({
36
+ sdPwaPlugin: mockSdPwaPlugin,
46
37
  }));
47
38
 
48
39
  // --- Dynamic import ---
@@ -73,8 +64,8 @@ afterEach(() => {
73
64
 
74
65
  describe("createClientViteConfig", () => {
75
66
  // Acceptance: Scenario "define['process.env'] 제거"
76
- it("does not include process.env in define, only import.meta.env keys", async () => {
77
- const config = await createClientViteConfig({
67
+ it("does not include process.env in define, only import.meta.env keys", () => {
68
+ const config = createClientViteConfig({
78
69
  ...createDefaultOptions(),
79
70
  env: { DEV: "true", VER: "1.0.0" },
80
71
  });
@@ -85,71 +76,64 @@ describe("createClientViteConfig", () => {
85
76
  expect(define["import.meta.env.VER"]).toBe('"1.0.0"');
86
77
  });
87
78
 
88
- // Acceptance: Scenario "browserslist 미설정 시 최신 브라우저 유지"
89
- it("uses es2022 esbuild target when no browserslist is provided", async () => {
90
- const config = await createClientViteConfig(createDefaultOptions());
79
+ // Acceptance: Scenario "기본 target 설정"
80
+ it("uses es2022 build target when no browserslist is provided", () => {
81
+ const config = createClientViteConfig(createDefaultOptions());
91
82
 
92
- expect(config.esbuild).toEqual({ target: "es2022" });
83
+ expect(config.build?.target).toBe("es2022");
84
+ expect(config.esbuild).toBeUndefined();
93
85
  });
94
86
 
95
87
  // Acceptance: Scenario "postCss 미설정 시 처리 없음"
96
- it("does not set css.postcss when no postCssPlugins are provided", async () => {
97
- const config = await createClientViteConfig(createDefaultOptions());
88
+ it("does not set css.postcss when no postCssPlugins are provided", () => {
89
+ const config = createClientViteConfig(createDefaultOptions());
98
90
 
99
91
  expect(config.css).toBeUndefined();
100
92
  });
101
93
 
102
- // Acceptance: Scenario "legacyModule 미설정 시 기본 코드 분할"
103
- it("does not set inlineDynamicImports when legacyModule is not specified", async () => {
104
- const config = await createClientViteConfig(createDefaultOptions());
105
-
106
- // build mode has build config, but no rollupOptions.output.inlineDynamicImports
107
- expect(config.build?.rollupOptions).toBeUndefined();
108
- });
109
-
110
94
  // Acceptance: Scenario "polyfills.ts 파일 미존재 시 주입 없음"
111
- it("does not add polyfills plugin when no polyfills are provided", async () => {
112
- const config = await createClientViteConfig(createDefaultOptions());
95
+ it("does not add polyfills plugin when no polyfills are provided", () => {
96
+ const config = createClientViteConfig(createDefaultOptions());
113
97
 
114
98
  const plugins = config.plugins as Array<{ name: string }>;
115
99
  const polyfillPlugin = plugins.find((p) => p.name === "sd-polyfills");
116
100
  expect(polyfillPlugin).toBeUndefined();
117
101
  });
118
102
 
119
- // Acceptance: Scenario "browserslist 문자열 설정 시 해당 타겟으로 변환"
120
- it("converts browserslist string to esbuild target", async () => {
121
- const config = await createClientViteConfig({
103
+ // Acceptance: Scenario "browserslist target 설정"
104
+ it("converts browserslist string to build target", () => {
105
+ const config = createClientViteConfig({
122
106
  ...createDefaultOptions(),
123
107
  browserslist: "last 2 Chrome versions",
124
108
  });
125
109
 
126
- expect((config.esbuild as { target: string | string[] }).target).toEqual(["chrome120", "chrome119"]);
110
+ expect(config.build?.target).toEqual(["chrome120", "chrome119"]);
127
111
  });
128
112
 
129
113
  // Acceptance: Scenario "browserslist 배열 설정"
130
- it("converts browserslist array to esbuild target", async () => {
131
- const config = await createClientViteConfig({
114
+ it("converts browserslist array to build target", () => {
115
+ const config = createClientViteConfig({
132
116
  ...createDefaultOptions(),
133
117
  browserslist: ["ie 11", "last 2 versions"],
134
118
  });
135
119
 
136
- expect((config.esbuild as { target: string | string[] }).target).toEqual(["es2015"]);
120
+ expect(config.build?.target).toEqual(["es2015"]);
137
121
  });
138
122
 
139
- // Acceptance: Scenario "dev server에서도 browserslist 적용"
140
- it("applies browserslist in dev mode too", async () => {
141
- const config = await createClientViteConfig({
123
+ // Acceptance: Scenario "dev 모드에서도 target 적용"
124
+ it("applies browserslist build target in dev mode too", () => {
125
+ const config = createClientViteConfig({
142
126
  ...createDefaultOptions(),
143
127
  mode: "dev",
144
128
  browserslist: "last 2 Chrome versions",
145
129
  });
146
130
 
147
- expect((config.esbuild as { target: string | string[] }).target).toEqual(["chrome120", "chrome119"]);
131
+ expect(config.build?.target).toEqual(["chrome120", "chrome119"]);
148
132
  });
149
133
 
150
134
  // Unit: browserslist is passed to sdAngularPlugin
151
- it("passes browserslist to sdAngularPlugin as normalized array", async () => {
152
- await createClientViteConfig({
135
+ it("passes browserslist to sdAngularPlugin as normalized array", () => {
136
+ createClientViteConfig({
153
137
  ...createDefaultOptions(),
154
138
  browserslist: "last 2 Chrome versions",
155
139
  });
@@ -162,9 +146,9 @@ describe("createClientViteConfig", () => {
162
146
  });
163
147
 
164
148
  // Acceptance: Scenario ".scss 파일에 PostCSS 적용"
165
- it("sets css.postcss when postCssPlugins are provided", async () => {
149
+ it("sets css.postcss when postCssPlugins are provided", () => {
166
150
  const fakePlugin = { postcssPlugin: "autoprefixer" };
167
- const config = await createClientViteConfig({
151
+ const config = createClientViteConfig({
168
152
  ...createDefaultOptions(),
169
153
  postCssPlugins: [fakePlugin],
170
154
  });
@@ -173,9 +157,9 @@ describe("createClientViteConfig", () => {
173
157
  });
174
158
 
175
159
  // Unit: postCssPlugins is passed to sdAngularPlugin
176
- it("passes postCssPlugins to sdAngularPlugin", async () => {
160
+ it("passes postCssPlugins to sdAngularPlugin", () => {
177
161
  const fakePlugin = { postcssPlugin: "autoprefixer" };
178
- await createClientViteConfig({
162
+ createClientViteConfig({
179
163
  ...createDefaultOptions(),
180
164
  postCssPlugins: [fakePlugin],
181
165
  });
@@ -188,9 +172,9 @@ describe("createClientViteConfig", () => {
188
172
  });
189
173
 
190
174
  // Acceptance: Scenario "Angular 라이브러리 번들 JS 내 인라인 CSS에 PostCSS 적용"
191
- it("adds sdPostCssInlinePlugin when postCssPlugins are provided", async () => {
175
+ it("adds sdPostCssInlinePlugin when postCssPlugins are provided", () => {
192
176
  const fakePlugin = { postcssPlugin: "autoprefixer" };
193
- const config = await createClientViteConfig({
177
+ const config = createClientViteConfig({
194
178
  ...createDefaultOptions(),
195
179
  postCssPlugins: [fakePlugin],
196
180
  });
@@ -201,8 +185,8 @@ describe("createClientViteConfig", () => {
201
185
  });
202
186
 
203
187
  // Unit: no sdPostCssInlinePlugin when empty postCssPlugins
204
- it("does not add sdPostCssInlinePlugin when postCssPlugins is empty", async () => {
205
- const config = await createClientViteConfig({
188
+ it("does not add sdPostCssInlinePlugin when postCssPlugins is empty", () => {
189
+ const config = createClientViteConfig({
206
190
  ...createDefaultOptions(),
207
191
  postCssPlugins: [],
208
192
  });
@@ -213,8 +197,8 @@ describe("createClientViteConfig", () => {
213
197
  });
214
198
 
215
199
  // Acceptance: Scenario "polyfills.ts 파일 존재 시 자동 주입"
216
- it("adds sd-polyfills plugin when polyfills are provided", async () => {
217
- const config = await createClientViteConfig({
200
+ it("adds sd-polyfills plugin when polyfills are provided", () => {
201
+ const config = createClientViteConfig({
218
202
  ...createDefaultOptions(),
219
203
  polyfills: ["./src/polyfills.ts"],
220
204
  });
@@ -226,227 +210,131 @@ describe("createClientViteConfig", () => {
226
210
 
227
211
  // --- legacyModule (Feature 1.1) ---
228
212
 
229
- // Acceptance: Scenario "legacyModule 활성화 시 inlineDynamicImports만 설정한다"
230
- it("enables inlineDynamicImports without import.meta plugin when legacyModule is true", async () => {
231
- const config = await createClientViteConfig({
213
+ // Acceptance: Scenario "legacyModule에서 inlineDynamicImports"
214
+ it("enables inlineDynamicImports and import.meta strip plugin when legacyModule is true", () => {
215
+ const config = createClientViteConfig({
232
216
  ...createDefaultOptions(),
233
217
  legacyModule: true,
234
218
  });
235
219
 
236
- // inlineDynamicImports가 활성화된다
237
- expect((config.build as any)?.rollupOptions?.output?.inlineDynamicImports).toBe(true);
238
- // import.meta 치환 플러그인이 없다 (esbuild target이 자동 치환)
220
+ // inlineDynamicImports가 활성화된다 (rolldownOptions)
221
+ expect((config.build as any)?.rolldownOptions?.output?.inlineDynamicImports).toBe(true);
222
+ // import.meta 치환 플러그인이 존재한다
239
223
  const plugins = config.plugins as Array<{ name: string }>;
240
- const legacyPlugin = plugins.find((p) => p.name === "sd-legacy-import-meta");
241
- expect(legacyPlugin).toBeUndefined();
224
+ const legacyPlugin = plugins.find((p) => p.name === "sd-legacy-strip-import-meta");
225
+ expect(legacyPlugin).toBeDefined();
242
226
  });
243
227
 
244
- // Acceptance: Scenario "legacyModule 미설정코드 분할이 기본 동작한다"
245
- it("does not set inlineDynamicImports when legacyModule is not set", async () => {
246
- const config = await createClientViteConfig(createDefaultOptions());
228
+ // Acceptance: Scenario "legacyModule 미사용rolldownOptions 없음"
229
+ it("does not set inlineDynamicImports when legacyModule is not set", () => {
230
+ const config = createClientViteConfig(createDefaultOptions());
247
231
 
248
232
  // 코드 분할이 기본 동작한다
249
- expect(config.build?.rollupOptions).toBeUndefined();
233
+ expect(config.build?.rolldownOptions).toBeUndefined();
250
234
  });
251
235
 
252
- // Acceptance: Scenario "legacyModule: true는 inlineDynamicImports를 활성화한다"
253
- it("legacyModule: true provides inlineDynamicImports (splitting replacement)", async () => {
254
- const config = await createClientViteConfig({
255
- ...createDefaultOptions(),
256
- legacyModule: true,
257
- });
258
-
259
- // 기존 splitting: false와 동일한 inlineDynamicImports 동작
260
- expect((config.build as any)?.rollupOptions?.output?.inlineDynamicImports).toBe(true);
261
- });
262
-
263
- // --- legacyModule esbuild.supported override (Feature 1.4) ---
236
+ // --- legacyModule import.meta strip (Vite 8 migration) ---
264
237
 
265
- // Acceptance: Scenario "legacyModule: true일 때 esbuild.supported에 import-meta false 설정"
266
- it("sets esbuild.supported to disable import-meta when legacyModule is true", async () => {
267
- const config = await createClientViteConfig({
238
+ // Acceptance: Scenario "legacyModule import.meta 치환 플러그인 존재"
239
+ it("adds sd-legacy-strip-import-meta plugin when legacyModule is true", () => {
240
+ const config = createClientViteConfig({
268
241
  ...createDefaultOptions(),
269
242
  legacyModule: true,
270
243
  });
271
244
 
272
- const esbuildOpts = config.esbuild as Record<string, unknown> | undefined;
273
- expect(esbuildOpts?.["supported"]).toEqual(
274
- expect.objectContaining({
275
- "import-meta": false,
276
- }),
277
- );
245
+ const plugins = config.plugins as Array<{ name: string }>;
246
+ expect(plugins.find((p) => p.name === "sd-legacy-strip-import-meta")).toBeDefined();
278
247
  });
279
248
 
280
- // Acceptance: Scenario "legacyModule 미설정esbuild.supported 변경 없음"
281
- it("does not set esbuild.supported when legacyModule is not specified", async () => {
282
- const config = await createClientViteConfig(createDefaultOptions());
249
+ // Acceptance: Scenario "legacyModule 미사용치환 플러그인 없음"
250
+ it("does not add sd-legacy-strip-import-meta plugin when legacyModule is not specified", () => {
251
+ const config = createClientViteConfig(createDefaultOptions());
283
252
 
284
- const esbuildOpts = config.esbuild as Record<string, unknown> | undefined;
285
- expect(esbuildOpts?.["supported"]).toBeUndefined();
253
+ const plugins = config.plugins as Array<{ name: string }>;
254
+ expect(plugins.find((p) => p.name === "sd-legacy-strip-import-meta")).toBeUndefined();
286
255
  });
287
256
 
288
257
  // --- PWA (Feature 5.2) ---
289
258
 
290
- // Acceptance: Scenario "기본 PWA 활성화"
291
- it("adds VitePWA plugin in build mode when pwa is not specified (default enabled)", async () => {
292
- const config = await createClientViteConfig(createDefaultOptions());
259
+ // Acceptance: Scenario "build 모드에서 기본 활성화"
260
+ it("adds sdPwaPlugin in build mode when pwa is not specified", () => {
261
+ const config = createClientViteConfig(createDefaultOptions());
293
262
 
294
263
  const plugins = config.plugins as Array<{ name: string }>;
295
- const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
264
+ const pwaPlugin = plugins.find((p) => p.name === "sd-pwa");
296
265
  expect(pwaPlugin).toBeDefined();
297
266
  });
298
267
 
299
- // Acceptance: Scenario "PWA 명시적 비활성화"
300
- it("does not add VitePWA plugin when pwa is false", async () => {
301
- const config = await createClientViteConfig({
268
+ // Acceptance: Scenario "pwa false로 비활성화"
269
+ it("does not add sdPwaPlugin when pwa is false", () => {
270
+ const config = createClientViteConfig({
302
271
  ...createDefaultOptions(),
303
272
  pwa: false,
304
273
  });
305
274
 
306
275
  const plugins = config.plugins as Array<{ name: string }>;
307
- const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
276
+ const pwaPlugin = plugins.find((p) => p.name === "sd-pwa");
308
277
  expect(pwaPlugin).toBeUndefined();
309
278
  });
310
279
 
311
- // Acceptance: Scenario "dev 모드에서 service worker 미등록"
312
- it("does not add VitePWA plugin in dev mode", async () => {
313
- const config = await createClientViteConfig({
280
+ // Acceptance: Scenario "dev 모드에서 비활성화"
281
+ it("does not add sdPwaPlugin in dev mode", () => {
282
+ const config = createClientViteConfig({
314
283
  ...createDefaultOptions(),
315
284
  mode: "dev",
316
285
  });
317
286
 
318
287
  const plugins = config.plugins as Array<{ name: string }>;
319
- const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
288
+ const pwaPlugin = plugins.find((p) => p.name === "sd-pwa");
320
289
  expect(pwaPlugin).toBeUndefined();
321
290
  });
322
291
 
323
- // Acceptance: Scenario "manifest 필드 커스텀"
324
- it("passes custom manifest fields to VitePWA plugin", async () => {
325
- await createClientViteConfig({
292
+ // Acceptance: Scenario "pwa 객체 전달"
293
+ it("passes pwa config object to sdPwaPlugin", () => {
294
+ createClientViteConfig({
326
295
  ...createDefaultOptions(),
327
296
  pwa: {
328
297
  manifest: { name: "My App", theme_color: "#000000" },
329
298
  },
330
299
  });
331
300
 
332
- expect(mockVitePWA).toHaveBeenCalledWith(
333
- expect.objectContaining({
334
- manifest: expect.objectContaining({
335
- name: "My App",
336
- theme_color: "#000000",
337
- // defaults for unspecified fields
338
- short_name: "my-client",
339
- display: "standalone",
340
- background_color: "#ffffff",
341
- }),
342
- }),
343
- );
301
+ expect(mockSdPwaPlugin).toHaveBeenCalledWith({
302
+ pkgDir: "/packages/my-client",
303
+ pkgName: "my-client",
304
+ pwa: { manifest: { name: "My App", theme_color: "#000000" } },
305
+ });
344
306
  });
345
307
 
346
- // Acceptance: Scenario "기본 Workbox 캐싱"
347
- it("uses default workbox globPatterns when pwa.workbox is not specified", async () => {
348
- await createClientViteConfig(createDefaultOptions());
349
-
350
- expect(mockVitePWA).toHaveBeenCalledWith(
351
- expect.objectContaining({
352
- workbox: {
353
- globPatterns: ["**/*.{js,css,html,ico,png,svg,woff2}"],
354
- },
355
- }),
356
- );
357
- });
308
+ // Unit: pwa undefined passes undefined to sdPwaPlugin
309
+ it("passes undefined pwa to sdPwaPlugin when pwa is not specified", () => {
310
+ createClientViteConfig(createDefaultOptions());
358
311
 
359
- // Acceptance: Scenario "Workbox globPatterns 커스텀"
360
- it("uses custom workbox globPatterns when specified", async () => {
361
- await createClientViteConfig({
362
- ...createDefaultOptions(),
363
- pwa: {
364
- workbox: { globPatterns: ["**/*.{js,css,html,json}"] },
365
- },
312
+ expect(mockSdPwaPlugin).toHaveBeenCalledWith({
313
+ pkgDir: "/packages/my-client",
314
+ pkgName: "my-client",
315
+ pwa: undefined,
366
316
  });
367
-
368
- expect(mockVitePWA).toHaveBeenCalledWith(
369
- expect.objectContaining({
370
- workbox: {
371
- globPatterns: ["**/*.{js,css,html,json}"],
372
- },
373
- }),
374
- );
375
317
  });
376
318
 
377
- // Unit: pwa empty object uses all defaults
378
- it("uses all defaults when pwa is empty object", async () => {
379
- await createClientViteConfig({
319
+ // Unit: pwa empty object passes empty object to sdPwaPlugin
320
+ it("passes empty pwa object to sdPwaPlugin when pwa is empty", () => {
321
+ createClientViteConfig({
380
322
  ...createDefaultOptions(),
381
323
  pwa: {},
382
324
  });
383
325
 
384
- expect(mockVitePWA).toHaveBeenCalledWith(
385
- expect.objectContaining({
386
- manifest: expect.objectContaining({
387
- name: "my-client",
388
- display: "standalone",
389
- }),
390
- }),
391
- );
392
- });
393
-
394
- // Unit: pwa manifest custom icons overrides default
395
- it("includes custom icons in manifest and skips auto-generation", async () => {
396
- const icons = [{ src: "/icon-192.png", sizes: "192x192", type: "image/png" }];
397
- await createClientViteConfig({
398
- ...createDefaultOptions(),
399
- pwa: { manifest: { icons } },
326
+ expect(mockSdPwaPlugin).toHaveBeenCalledWith({
327
+ pkgDir: "/packages/my-client",
328
+ pkgName: "my-client",
329
+ pwa: {},
400
330
  });
401
-
402
- expect(mockVitePWA).toHaveBeenCalledWith(
403
- expect.objectContaining({
404
- manifest: expect.objectContaining({ icons }),
405
- }),
406
- );
407
- expect(mockGeneratePwaIcons).not.toHaveBeenCalled();
408
- });
409
-
410
- // Acceptance: Scenario "기본 아이콘 자동 생성"
411
- it("calls generatePwaIcons and includes result in manifest", async () => {
412
- mockGeneratePwaIcons.mockResolvedValue([
413
- { src: "icons/icon-192x192.png", sizes: "192x192", type: "image/png" },
414
- { src: "icons/icon-512x512.png", sizes: "512x512", type: "image/png" },
415
- ]);
416
-
417
- await createClientViteConfig(createDefaultOptions());
418
-
419
- expect(mockGeneratePwaIcons).toHaveBeenCalledWith("/packages/my-client");
420
- expect(mockVitePWA).toHaveBeenCalledWith(
421
- expect.objectContaining({
422
- manifest: expect.objectContaining({
423
- icons: [
424
- { src: "icons/icon-192x192.png", sizes: "192x192", type: "image/png" },
425
- { src: "icons/icon-512x512.png", sizes: "512x512", type: "image/png" },
426
- ],
427
- }),
428
- }),
429
- );
430
- });
431
-
432
- // Acceptance: Scenario "원본 아이콘 파일이 없을 때"
433
- it("does not include icons in manifest when no source icon exists", async () => {
434
- mockGeneratePwaIcons.mockResolvedValue([]);
435
-
436
- await createClientViteConfig(createDefaultOptions());
437
-
438
- expect(mockVitePWA).toHaveBeenCalledWith(
439
- expect.objectContaining({
440
- manifest: expect.not.objectContaining({ icons: expect.anything() }),
441
- }),
442
- );
443
331
  });
444
332
 
445
333
  // --- watch option (Feature 1.2: legacy dev mode) ---
446
334
 
447
335
  // Acceptance: Scenario "watch: true 시 build.watch 설정 및 emptyOutDir: false"
448
- it("sets build.watch and emptyOutDir: false when watch is true in build mode", async () => {
449
- const config = await createClientViteConfig({
336
+ it("sets build.watch and emptyOutDir: false when watch is true in build mode", () => {
337
+ const config = createClientViteConfig({
450
338
  ...createDefaultOptions(),
451
339
  mode: "build",
452
340
  watch: true,
@@ -461,7 +349,7 @@ describe("createClientViteConfig", () => {
461
349
  it("includes sdScopeWatchPlugin when watch is true with replaceDeps in build mode", async () => {
462
350
  const { sdScopeWatchPlugin } = await import("../../src/utils/vite-scope-watch-plugin");
463
351
 
464
- const config = await createClientViteConfig({
352
+ const config = createClientViteConfig({
465
353
  ...createDefaultOptions(),
466
354
  mode: "build",
467
355
  watch: true,
@@ -475,8 +363,8 @@ describe("createClientViteConfig", () => {
475
363
  });
476
364
 
477
365
  // Acceptance: Scenario "watch 미설정 시 기존 build 동작 유지"
478
- it("sets emptyOutDir: true and logLevel: silent when watch is not set in build mode", async () => {
479
- const config = await createClientViteConfig(createDefaultOptions());
366
+ it("sets emptyOutDir: true and logLevel: silent when watch is not set in build mode", () => {
367
+ const config = createClientViteConfig(createDefaultOptions());
480
368
 
481
369
  expect(config.build?.emptyOutDir).toBe(true);
482
370
  expect(config.logLevel).toBe("silent");
@@ -484,8 +372,8 @@ describe("createClientViteConfig", () => {
484
372
  });
485
373
 
486
374
  // Unit: watch: true without replaceDeps does not add sdScopeWatchPlugin
487
- it("does not add sdScopeWatchPlugin in watch mode without replaceDeps", async () => {
488
- const config = await createClientViteConfig({
375
+ it("does not add sdScopeWatchPlugin in watch mode without replaceDeps", () => {
376
+ const config = createClientViteConfig({
489
377
  ...createDefaultOptions(),
490
378
  mode: "build",
491
379
  watch: true,
@@ -497,8 +385,8 @@ describe("createClientViteConfig", () => {
497
385
  });
498
386
 
499
387
  // Unit: watch: true still sets outDir
500
- it("sets outDir in watch mode", async () => {
501
- const config = await createClientViteConfig({
388
+ it("sets outDir in watch mode", () => {
389
+ const config = createClientViteConfig({
502
390
  ...createDefaultOptions(),
503
391
  mode: "build",
504
392
  watch: true,
@@ -511,8 +399,8 @@ describe("createClientViteConfig", () => {
511
399
  // --- outDir override ---
512
400
 
513
401
  // Acceptance: Scenario "outDir 설정 시 해당 경로로 빌드 출력"
514
- it("uses custom outDir when provided", async () => {
515
- const config = await createClientViteConfig({
402
+ it("uses custom outDir when provided", () => {
403
+ const config = createClientViteConfig({
516
404
  ...createDefaultOptions(),
517
405
  outDir: "/packages/my-client/.capacitor/www",
518
406
  });
@@ -521,8 +409,8 @@ describe("createClientViteConfig", () => {
521
409
  });
522
410
 
523
411
  // Acceptance: Scenario "outDir 미설정 시 pkgDir/dist 사용"
524
- it("defaults outDir to pkgDir/dist when not provided", async () => {
525
- const config = await createClientViteConfig(createDefaultOptions());
412
+ it("defaults outDir to pkgDir/dist when not provided", () => {
413
+ const config = createClientViteConfig(createDefaultOptions());
526
414
 
527
415
  expect(config.build?.outDir).toMatch(/my-client[\\/]dist$/);
528
416
  });
@@ -530,8 +418,8 @@ describe("createClientViteConfig", () => {
530
418
  // --- exclude (Feature 1.1: vite-exclude-passthrough) ---
531
419
 
532
420
  // Acceptance: Scenario "exclude에 패키지를 지정하면 pre-bundling에서 제외된다"
533
- it("sets optimizeDeps.exclude when exclude is provided", async () => {
534
- const config = await createClientViteConfig({
421
+ it("sets optimizeDeps.exclude when exclude is provided", () => {
422
+ const config = createClientViteConfig({
535
423
  ...createDefaultOptions(),
536
424
  mode: "dev",
537
425
  exclude: ["jeep-sqlite"],
@@ -541,8 +429,8 @@ describe("createClientViteConfig", () => {
541
429
  });
542
430
 
543
431
  // Acceptance: Scenario "exclude 미설정 시 기존 동작과 동일하다"
544
- it("does not set optimizeDeps.exclude when exclude is not provided", async () => {
545
- const config = await createClientViteConfig({
432
+ it("does not set optimizeDeps.exclude when exclude is not provided", () => {
433
+ const config = createClientViteConfig({
546
434
  ...createDefaultOptions(),
547
435
  mode: "dev",
548
436
  });
@@ -554,7 +442,7 @@ describe("createClientViteConfig", () => {
554
442
  it("sets optimizeDeps.exclude from exclude while sdScopeWatchPlugin handles replaceDeps", async () => {
555
443
  const { sdScopeWatchPlugin } = await import("../../src/utils/vite-scope-watch-plugin");
556
444
 
557
- const config = await createClientViteConfig({
445
+ const config = createClientViteConfig({
558
446
  ...createDefaultOptions(),
559
447
  mode: "dev",
560
448
  exclude: ["jeep-sqlite"],
@@ -568,8 +456,8 @@ describe("createClientViteConfig", () => {
568
456
  });
569
457
 
570
458
  // Acceptance: Scenario "exclude만 있고 replaceDeps가 없으면 exclude만 제외된다"
571
- it("sets optimizeDeps.exclude from exclude when no replaceDeps", async () => {
572
- const config = await createClientViteConfig({
459
+ it("sets optimizeDeps.exclude from exclude when no replaceDeps", () => {
460
+ const config = createClientViteConfig({
573
461
  ...createDefaultOptions(),
574
462
  mode: "dev",
575
463
  exclude: ["jeep-sqlite"],
@@ -585,8 +473,8 @@ describe("createClientViteConfig", () => {
585
473
  // --- framework selection (Feature 1.1: client-framework-selection) ---
586
474
 
587
475
  // Acceptance: Scenario "Solid 프레임워크 선택"
588
- it("uses solidPlugin when framework is 'solid'", async () => {
589
- const config = await createClientViteConfig({
476
+ it("uses solidPlugin when framework is 'solid'", () => {
477
+ const config = createClientViteConfig({
590
478
  ...createDefaultOptions(),
591
479
  framework: "solid",
592
480
  });
@@ -598,16 +486,16 @@ describe("createClientViteConfig", () => {
598
486
  });
599
487
 
600
488
  // Acceptance: Scenario "framework 미지정 시 기본값"
601
- it("uses sdAngularPlugin when framework is not specified", async () => {
602
- await createClientViteConfig(createDefaultOptions());
489
+ it("uses sdAngularPlugin when framework is not specified", () => {
490
+ createClientViteConfig(createDefaultOptions());
603
491
 
604
492
  expect(mockSdAngularPlugin).toHaveBeenCalled();
605
493
  expect(mockSolidPlugin).not.toHaveBeenCalled();
606
494
  });
607
495
 
608
496
  // Acceptance: Scenario "Angular 프레임워크 명시 선택"
609
- it("uses sdAngularPlugin when framework is 'angular'", async () => {
610
- await createClientViteConfig({
497
+ it("uses sdAngularPlugin when framework is 'angular'", () => {
498
+ createClientViteConfig({
611
499
  ...createDefaultOptions(),
612
500
  framework: "angular",
613
501
  });
@@ -617,9 +505,9 @@ describe("createClientViteConfig", () => {
617
505
  });
618
506
 
619
507
  // Acceptance: Scenario "Solid 빌드에서 PostCSS inline 플러그인 미적용"
620
- it("does not add sdPostCssInlinePlugin when framework is 'solid' even with postCssPlugins", async () => {
508
+ it("does not add sdPostCssInlinePlugin when framework is 'solid' even with postCssPlugins", () => {
621
509
  const fakePlugin = { postcssPlugin: "autoprefixer" };
622
- const config = await createClientViteConfig({
510
+ const config = createClientViteConfig({
623
511
  ...createDefaultOptions(),
624
512
  framework: "solid",
625
513
  postCssPlugins: [fakePlugin],
@@ -631,30 +519,11 @@ describe("createClientViteConfig", () => {
631
519
  expect(config.css?.postcss).toEqual({ plugins: [fakePlugin] });
632
520
  });
633
521
 
634
- // Acceptance: Scenario "pwa 필드 미설정 시 기본값"
635
- it("uses default manifest values from pkgName when pwa is undefined", async () => {
636
- await createClientViteConfig(createDefaultOptions());
637
-
638
- expect(mockVitePWA).toHaveBeenCalledWith(
639
- expect.objectContaining({
640
- registerType: "prompt",
641
- injectRegister: "script",
642
- manifest: expect.objectContaining({
643
- name: "my-client",
644
- short_name: "my-client",
645
- display: "standalone",
646
- theme_color: "#ffffff",
647
- background_color: "#ffffff",
648
- }),
649
- }),
650
- );
651
- });
652
-
653
522
  // --- legacyModule dev mode (Feature: fix-legacy-ngdevmode) ---
654
523
 
655
524
  // Acceptance: Scenario "legacyModule: true + dev 명령 실행 시 sdAngularPlugin에 dev: true 전달"
656
- it("passes dev: true to sdAngularPlugin when mode is dev with legacyModule", async () => {
657
- await createClientViteConfig({
525
+ it("passes dev: true to sdAngularPlugin when mode is dev with legacyModule", () => {
526
+ createClientViteConfig({
658
527
  ...createDefaultOptions(),
659
528
  mode: "dev",
660
529
  legacyModule: true,
@@ -667,8 +536,8 @@ describe("createClientViteConfig", () => {
667
536
  });
668
537
 
669
538
  // Acceptance: Scenario "legacyModule dev에서 build output 설정이 적용된다"
670
- it("applies build output settings when mode is dev with legacyModule", async () => {
671
- const config = await createClientViteConfig({
539
+ it("applies build output settings when mode is dev with legacyModule", () => {
540
+ const config = createClientViteConfig({
672
541
  ...createDefaultOptions(),
673
542
  mode: "dev",
674
543
  legacyModule: true,
@@ -681,9 +550,9 @@ describe("createClientViteConfig", () => {
681
550
  expect(config.build?.minify).toBe(false);
682
551
  });
683
552
 
684
- // Unit: legacyModule dev에서 PWA가 추가되지 않는다
685
- it("does not add VitePWA plugin when mode is dev with legacyModule", async () => {
686
- const config = await createClientViteConfig({
553
+ // Acceptance: Scenario "dev + legacyModule에서 비활성화"
554
+ it("does not add sdPwaPlugin when mode is dev with legacyModule", () => {
555
+ const config = createClientViteConfig({
687
556
  ...createDefaultOptions(),
688
557
  mode: "dev",
689
558
  legacyModule: true,
@@ -691,7 +560,7 @@ describe("createClientViteConfig", () => {
691
560
  });
692
561
 
693
562
  const plugins = config.plugins as Array<{ name: string }>;
694
- const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
563
+ const pwaPlugin = plugins.find((p) => p.name === "sd-pwa");
695
564
  expect(pwaPlugin).toBeUndefined();
696
565
  });
697
566
  });