@simplysm/sd-cli 14.0.11 → 14.0.12
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 +58 -253
- package/dist/angular/client-transform-stylesheet.js +1 -1
- package/dist/angular/client-transform-stylesheet.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts +1 -1
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +60 -34
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/angular/vite-postcss-inline-plugin.d.ts +1 -1
- package/dist/angular/vite-postcss-inline-plugin.js +1 -1
- package/dist/capacitor/capacitor.d.ts +14 -2
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +131 -17
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/build.d.ts +3 -10
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +3 -10
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/check.js +3 -3
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -9
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +3 -9
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/device.d.ts +3 -3
- package/dist/commands/device.js +5 -5
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/publish.d.ts +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +18 -26
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/replace-deps.d.ts +3 -3
- package/dist/commands/replace-deps.d.ts.map +1 -1
- package/dist/commands/replace-deps.js +1 -1
- package/dist/commands/typecheck.d.ts +4 -3
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +5 -11
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/commands/watch.d.ts +9 -9
- package/dist/commands/watch.js +9 -9
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +42 -3
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +3 -1
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.d.ts +7 -7
- package/dist/engines/NgtscEngine.d.ts.map +1 -1
- package/dist/engines/NgtscEngine.js +3 -3
- package/dist/engines/ServerEsbuildEngine.d.ts +7 -7
- package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
- package/dist/engines/ServerEsbuildEngine.js +3 -3
- package/dist/engines/TscEngine.d.ts +7 -7
- package/dist/engines/TscEngine.d.ts.map +1 -1
- package/dist/engines/TscEngine.js +3 -3
- package/dist/engines/ViteEngine.d.ts +1 -1
- package/dist/engines/ViteEngine.d.ts.map +1 -1
- package/dist/engines/ViteEngine.js +7 -12
- package/dist/engines/ViteEngine.js.map +1 -1
- package/dist/engines/index.d.ts +5 -5
- package/dist/engines/index.js +5 -5
- package/dist/engines/types.d.ts +20 -20
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/infra/ResultCollector.d.ts +9 -9
- package/dist/infra/ResultCollector.js +8 -8
- package/dist/infra/SignalHandler.d.ts +7 -7
- package/dist/infra/SignalHandler.js +7 -7
- package/dist/infra/WorkerManager.d.ts +14 -14
- package/dist/infra/WorkerManager.js +14 -14
- package/dist/orchestrators/BuildOrchestrator.d.ts +25 -25
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +29 -29
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts +7 -7
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +34 -34
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/sd-cli-entry.d.ts +2 -2
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +15 -8
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.d.ts +3 -3
- package/dist/sd-cli.js +16 -16
- package/dist/sd-cli.js.map +1 -1
- package/dist/sd-config.types.d.ts +105 -105
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/angular-compiler.js +5 -5
- package/dist/utils/angular-compiler.js.map +1 -1
- package/dist/utils/build-env.d.ts +1 -1
- package/dist/utils/build-env.js +1 -1
- package/dist/utils/concurrency.d.ts +7 -7
- package/dist/utils/concurrency.js +7 -7
- package/dist/utils/copy-public.d.ts +9 -9
- package/dist/utils/copy-public.js +17 -17
- package/dist/utils/copy-public.js.map +1 -1
- package/dist/utils/copy-src.d.ts +9 -9
- package/dist/utils/copy-src.js +11 -11
- package/dist/utils/copy-src.js.map +1 -1
- package/dist/utils/engine-stop.d.ts +8 -9
- package/dist/utils/engine-stop.d.ts.map +1 -1
- package/dist/utils/engine-stop.js +9 -10
- package/dist/utils/engine-stop.js.map +1 -1
- package/dist/utils/esbuild-config.d.ts +23 -23
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/esbuild-config.js +25 -25
- package/dist/utils/esbuild-config.js.map +1 -1
- package/dist/utils/lint-with-program.d.ts +15 -15
- package/dist/utils/lint-with-program.d.ts.map +1 -1
- package/dist/utils/lint-with-program.js +29 -29
- package/dist/utils/lint-with-program.js.map +1 -1
- package/dist/utils/ngtsc-build-core.d.ts +8 -8
- package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
- package/dist/utils/ngtsc-build-core.js +14 -14
- package/dist/utils/ngtsc-build-core.js.map +1 -1
- package/dist/utils/output-path-rewriter.d.ts +14 -14
- package/dist/utils/output-path-rewriter.js +18 -18
- package/dist/utils/output-path-rewriter.js.map +1 -1
- package/dist/utils/output-utils.d.ts +6 -6
- package/dist/utils/output-utils.js +11 -11
- package/dist/utils/output-utils.js.map +1 -1
- package/dist/utils/package-utils.d.ts +21 -21
- package/dist/utils/package-utils.d.ts.map +1 -1
- package/dist/utils/package-utils.js +56 -45
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/replace-deps.d.ts +25 -25
- package/dist/utils/replace-deps.d.ts.map +1 -1
- package/dist/utils/replace-deps.js +84 -65
- package/dist/utils/replace-deps.js.map +1 -1
- package/dist/utils/sd-config.d.ts +3 -3
- package/dist/utils/sd-config.js +3 -3
- package/dist/utils/tsc-build.d.ts +13 -13
- package/dist/utils/tsc-build.d.ts.map +1 -1
- package/dist/utils/tsc-build.js +9 -9
- package/dist/utils/tsc-build.js.map +1 -1
- package/dist/utils/tsconfig.d.ts +11 -9
- package/dist/utils/tsconfig.d.ts.map +1 -1
- package/dist/utils/tsconfig.js +11 -9
- package/dist/utils/tsconfig.js.map +1 -1
- package/dist/utils/typecheck-non-package.d.ts +5 -6
- package/dist/utils/typecheck-non-package.d.ts.map +1 -1
- package/dist/utils/typecheck-non-package.js +7 -8
- package/dist/utils/typecheck-non-package.js.map +1 -1
- package/dist/utils/typecheck-serialization.d.ts +8 -8
- package/dist/utils/typecheck-serialization.d.ts.map +1 -1
- package/dist/utils/typecheck-serialization.js +12 -16
- package/dist/utils/typecheck-serialization.js.map +1 -1
- package/dist/utils/vite-config.d.ts +8 -5
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +36 -29
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.js +1 -1
- package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
- package/dist/utils/worker-events.d.ts +12 -12
- package/dist/utils/worker-events.d.ts.map +1 -1
- package/dist/utils/worker-events.js +10 -10
- package/dist/utils/worker-events.js.map +1 -1
- package/dist/utils/worker-utils.d.ts +12 -13
- package/dist/utils/worker-utils.d.ts.map +1 -1
- package/dist/utils/worker-utils.js +12 -13
- package/dist/utils/worker-utils.js.map +1 -1
- package/dist/vitest-plugin.d.ts.map +1 -1
- package/dist/vitest-plugin.js +5 -7
- package/dist/vitest-plugin.js.map +1 -1
- package/dist/workers/client.worker.d.ts +4 -2
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +209 -1
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/library-build.worker.d.ts +1 -1
- package/dist/workers/library-build.worker.d.ts.map +1 -1
- package/dist/workers/library-build.worker.js +7 -7
- package/dist/workers/library-build.worker.js.map +1 -1
- package/dist/workers/lint.worker.d.ts +2 -2
- package/dist/workers/lint.worker.js +2 -2
- package/dist/workers/ngtsc-build.worker.js +30 -30
- package/dist/workers/ngtsc-build.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts +17 -17
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +46 -46
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-runtime.worker.d.ts +7 -7
- package/dist/workers/server-runtime.worker.d.ts.map +1 -1
- package/dist/workers/server-runtime.worker.js +17 -17
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/docs/config.md +340 -0
- package/docs/publish-configuration-types.md +87 -0
- package/docs/pwa-configuration-types.md +55 -0
- package/docs/vitest-plugin.md +47 -0
- package/package.json +9 -7
- package/src/angular/client-transform-stylesheet.ts +1 -1
- package/src/angular/vite-angular-plugin.ts +70 -37
- package/src/angular/vite-postcss-inline-plugin.ts +1 -1
- package/src/capacitor/capacitor.ts +159 -23
- package/src/commands/build.ts +3 -10
- package/src/commands/check.ts +3 -3
- package/src/commands/dev.ts +3 -9
- package/src/commands/device.ts +5 -5
- package/src/commands/publish.ts +30 -26
- package/src/commands/replace-deps.ts +3 -3
- package/src/commands/typecheck.ts +7 -13
- package/src/commands/watch.ts +9 -9
- package/src/electron/electron.ts +49 -4
- package/src/engines/BaseEngine.ts +4 -1
- package/src/engines/NgtscEngine.ts +7 -7
- package/src/engines/ServerEsbuildEngine.ts +7 -7
- package/src/engines/TscEngine.ts +7 -7
- package/src/engines/ViteEngine.ts +8 -13
- package/src/engines/index.ts +5 -5
- package/src/engines/types.ts +20 -20
- package/src/infra/ResultCollector.ts +9 -9
- package/src/infra/SignalHandler.ts +7 -7
- package/src/infra/WorkerManager.ts +14 -14
- package/src/orchestrators/BuildOrchestrator.ts +37 -37
- package/src/orchestrators/DevWatchOrchestrator.ts +36 -36
- package/src/sd-cli-entry.ts +15 -8
- package/src/sd-cli.ts +16 -16
- package/src/sd-config.types.ts +107 -107
- package/src/utils/angular-compiler.ts +5 -5
- package/src/utils/build-env.ts +1 -1
- package/src/utils/concurrency.ts +7 -7
- package/src/utils/copy-public.ts +17 -17
- package/src/utils/copy-src.ts +11 -11
- package/src/utils/engine-stop.ts +9 -10
- package/src/utils/esbuild-config.ts +29 -29
- package/src/utils/lint-with-program.ts +34 -34
- package/src/utils/ngtsc-build-core.ts +17 -17
- package/src/utils/output-path-rewriter.ts +18 -18
- package/src/utils/output-utils.ts +11 -11
- package/src/utils/package-utils.ts +57 -45
- package/src/utils/replace-deps.ts +92 -67
- package/src/utils/sd-config.ts +3 -3
- package/src/utils/tsc-build.ts +18 -18
- package/src/utils/tsconfig.ts +11 -9
- package/src/utils/typecheck-non-package.ts +7 -8
- package/src/utils/typecheck-serialization.ts +13 -15
- package/src/utils/vite-config.ts +45 -35
- package/src/utils/vite-scope-watch-plugin.ts +6 -1
- package/src/utils/worker-events.ts +16 -16
- package/src/utils/worker-utils.ts +12 -13
- package/src/vitest-plugin.ts +5 -8
- package/src/workers/client.worker.ts +236 -2
- package/src/workers/library-build.worker.ts +8 -8
- package/src/workers/lint.worker.ts +2 -2
- package/src/workers/ngtsc-build.worker.ts +31 -31
- package/src/workers/server-build.worker.ts +60 -60
- package/src/workers/server-runtime.worker.ts +22 -22
- package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +1 -0
- package/tests/angular/vite-angular-plugin-hmr.spec.ts +78 -0
- package/tests/angular/vite-angular-plugin.spec.ts +67 -0
- package/tests/capacitor/capacitor-build.spec.ts +6 -4
- package/tests/capacitor/capacitor-icon.spec.ts +7 -5
- package/tests/capacitor/capacitor-init.spec.ts +120 -10
- package/tests/capacitor/capacitor-run.spec.ts +14 -17
- package/tests/capacitor/capacitor-workspace.spec.ts +5 -3
- package/tests/commands/check.spec.ts +2 -2
- package/tests/commands/publish.spec.ts +2 -2
- package/tests/commands/typecheck.spec.ts +8 -0
- package/tests/electron/electron.spec.ts +12 -10
- package/tests/engines/base-engine.spec.ts +37 -0
- package/tests/engines/vite-engine.spec.ts +115 -3
- package/tests/utils/vite-config.spec.ts +144 -90
- package/tests/workers/client-worker.spec.ts +690 -0
- package/tests/workers/server-build-worker.spec.ts +3 -3
package/src/utils/vite-config.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { InlineConfig, PluginOption } from "vite";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { pathx } from "@simplysm/core-node";
|
|
4
3
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
5
4
|
import browserslistToEsbuild from "browserslist-to-esbuild";
|
|
6
5
|
import { sdAngularPlugin } from "../angular/vite-angular-plugin.js";
|
|
@@ -36,7 +35,7 @@ export interface CreateClientViteConfigOptions {
|
|
|
36
35
|
warnings?: string[];
|
|
37
36
|
lint?: { success: boolean; errorCount: number; warningCount: number; formattedOutput: string };
|
|
38
37
|
}) => void;
|
|
39
|
-
/**
|
|
38
|
+
/** 컴파일의 ts.Program을 사용하여 lint 실행 */
|
|
40
39
|
enableLint?: boolean;
|
|
41
40
|
/** replaceDeps 목록 (dev 모드에서 sdScopeWatchPlugin에 전달) */
|
|
42
41
|
replaceDeps?: ScopeWatchReplaceDep[];
|
|
@@ -48,18 +47,21 @@ export interface CreateClientViteConfigOptions {
|
|
|
48
47
|
postCssPlugins?: unknown[];
|
|
49
48
|
/** polyfills 경로 배열 (transformIndexHtml로 주입) */
|
|
50
49
|
polyfills?: string[];
|
|
51
|
-
/**
|
|
50
|
+
/** 레거시 모듈 지원 (코드 스플리팅 비활성화) */
|
|
52
51
|
legacyModule?: boolean;
|
|
53
52
|
/** PWA 설정. false로 비활성화. 미설정 시 기본값으로 활성화 */
|
|
54
53
|
pwa?: false | SdPwaConfig;
|
|
54
|
+
/** Vite optimizeDeps.exclude에 전달할 패키지 목록 */
|
|
55
|
+
exclude?: string[];
|
|
56
|
+
/** watch 모드 (build.watch 활성화, emptyOutDir: false) */
|
|
57
|
+
watch?: boolean;
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
/**
|
|
58
61
|
* Client Vite 설정을 생성한다. dev/build 모드에서 공용으로 사용한다.
|
|
59
62
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* Feature 1.1: legacyModule (import.meta 치환 + inlineDynamicImports)
|
|
63
|
+
* Angular AOT 플러그인, tsconfigPaths, env define, server/build 기본 설정,
|
|
64
|
+
* browserslist, PostCSS, polyfills, legacyModule (inlineDynamicImports) 등을 통합 구성한다.
|
|
63
65
|
*/
|
|
64
66
|
export async function createClientViteConfig(
|
|
65
67
|
options: CreateClientViteConfigOptions,
|
|
@@ -112,8 +114,12 @@ export async function createClientViteConfig(
|
|
|
112
114
|
);
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
// replaceDeps HMR (dev
|
|
116
|
-
if (
|
|
117
|
+
// replaceDeps HMR (dev 모드 또는 watch 모드)
|
|
118
|
+
if (
|
|
119
|
+
(options.mode === "dev" || options.watch === true) &&
|
|
120
|
+
options.replaceDeps != null &&
|
|
121
|
+
options.replaceDeps.length > 0
|
|
122
|
+
) {
|
|
117
123
|
plugins.push(
|
|
118
124
|
sdScopeWatchPlugin({
|
|
119
125
|
pkgDir: options.pkgDir,
|
|
@@ -127,7 +133,7 @@ export async function createClientViteConfig(
|
|
|
127
133
|
const serverConfig =
|
|
128
134
|
options.mode === "dev"
|
|
129
135
|
? {
|
|
130
|
-
host: options.serverPort === 0 ? "127.0.0.1" :
|
|
136
|
+
host: options.serverPort === 0 ? "127.0.0.1" : "0.0.0.0",
|
|
131
137
|
port: options.serverPort === 0 ? undefined : options.serverPort,
|
|
132
138
|
strictPort: options.serverPort !== 0,
|
|
133
139
|
}
|
|
@@ -139,6 +145,12 @@ export async function createClientViteConfig(
|
|
|
139
145
|
? { postcss: { plugins: options.postCssPlugins as import("postcss").AcceptedPlugin[] } }
|
|
140
146
|
: undefined;
|
|
141
147
|
|
|
148
|
+
// optimizeDeps.exclude (사용자 지정 exclude)
|
|
149
|
+
const optimizeDepsConfig =
|
|
150
|
+
options.exclude != null && options.exclude.length > 0
|
|
151
|
+
? { exclude: options.exclude }
|
|
152
|
+
: undefined;
|
|
153
|
+
|
|
142
154
|
const config: InlineConfig = {
|
|
143
155
|
root: options.pkgDir,
|
|
144
156
|
base: `/${name}/`,
|
|
@@ -149,6 +161,15 @@ export async function createClientViteConfig(
|
|
|
149
161
|
esbuild: {
|
|
150
162
|
target: esbuildTarget,
|
|
151
163
|
},
|
|
164
|
+
build: {
|
|
165
|
+
target: esbuildTarget,
|
|
166
|
+
},
|
|
167
|
+
optimizeDeps: {
|
|
168
|
+
...optimizeDepsConfig,
|
|
169
|
+
esbuildOptions: {
|
|
170
|
+
target: esbuildTarget as string[],
|
|
171
|
+
},
|
|
172
|
+
},
|
|
152
173
|
};
|
|
153
174
|
|
|
154
175
|
// PWA (build 모드 + pwa !== false)
|
|
@@ -207,8 +228,15 @@ export async function createClientViteConfig(
|
|
|
207
228
|
});
|
|
208
229
|
}
|
|
209
230
|
|
|
210
|
-
// legacyModule: true →
|
|
231
|
+
// legacyModule: true → 코드 스플리팅 비활성화 + esbuild import.meta/import() 변환 활성화
|
|
211
232
|
if (options.legacyModule === true) {
|
|
233
|
+
config.esbuild = {
|
|
234
|
+
...config.esbuild,
|
|
235
|
+
supported: {
|
|
236
|
+
"import-meta": false,
|
|
237
|
+
"dynamic-import": false,
|
|
238
|
+
},
|
|
239
|
+
};
|
|
212
240
|
config.build = {
|
|
213
241
|
...config.build,
|
|
214
242
|
rollupOptions: {
|
|
@@ -217,39 +245,21 @@ export async function createClientViteConfig(
|
|
|
217
245
|
},
|
|
218
246
|
},
|
|
219
247
|
};
|
|
220
|
-
|
|
221
|
-
const pkgDir = options.pkgDir;
|
|
222
|
-
const base = `/${name}/`;
|
|
223
|
-
|
|
224
|
-
(config.plugins as PluginOption[]).push({
|
|
225
|
-
name: "sd-legacy-import-meta",
|
|
226
|
-
enforce: "post",
|
|
227
|
-
transform(code: string, id: string) {
|
|
228
|
-
if (!code.includes("import.meta")) return;
|
|
229
|
-
|
|
230
|
-
// id(파일 경로)를 Vite 서빙 URL로 변환
|
|
231
|
-
const relative = pathx.posix(path.relative(pkgDir, id));
|
|
232
|
-
const moduleUrl = id.startsWith("/") || id.startsWith("\0")
|
|
233
|
-
? id // 가상 모듈(/@vite/client 등)은 그대로 사용
|
|
234
|
-
: base + relative;
|
|
235
|
-
|
|
236
|
-
const varName = "__sd_import_meta__";
|
|
237
|
-
const injected = `const ${varName} = { url: new URL(${JSON.stringify(moduleUrl)}, document.baseURI).href };\n`;
|
|
238
|
-
const replaced = code.replaceAll("import.meta", varName);
|
|
239
|
-
|
|
240
|
-
return { code: injected + replaced, map: null };
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
248
|
}
|
|
244
249
|
|
|
245
250
|
// build 모드 설정
|
|
246
251
|
if (options.mode === "build") {
|
|
247
|
-
config.logLevel = "silent";
|
|
248
252
|
config.build = {
|
|
249
253
|
...config.build,
|
|
250
254
|
outDir: path.join(options.pkgDir, "dist"),
|
|
251
|
-
emptyOutDir: true,
|
|
252
255
|
};
|
|
256
|
+
if (options.watch === true) {
|
|
257
|
+
config.build.watch = {};
|
|
258
|
+
config.build.emptyOutDir = false;
|
|
259
|
+
} else {
|
|
260
|
+
config.logLevel = "silent";
|
|
261
|
+
config.build.emptyOutDir = true;
|
|
262
|
+
}
|
|
253
263
|
}
|
|
254
264
|
|
|
255
265
|
return config;
|
|
@@ -44,7 +44,12 @@ export function sdScopeWatchPlugin(options: SdScopeWatchPluginOptions): Plugin {
|
|
|
44
44
|
|
|
45
45
|
const watchPaths: string[] = [];
|
|
46
46
|
for (const dep of options.replaceDeps) {
|
|
47
|
-
const distDir = path.join(
|
|
47
|
+
const distDir = path.join(
|
|
48
|
+
options.pkgDir,
|
|
49
|
+
"node_modules",
|
|
50
|
+
...dep.packageName.split("/"),
|
|
51
|
+
"dist",
|
|
52
|
+
);
|
|
48
53
|
if (fs.existsSync(distDir)) {
|
|
49
54
|
watchPaths.push(distDir);
|
|
50
55
|
}
|
|
@@ -6,24 +6,24 @@ import { formatBuildMessages } from "./output-utils";
|
|
|
6
6
|
|
|
7
7
|
const workerEventsLogger = consola.withTag("sd:cli:worker-events");
|
|
8
8
|
|
|
9
|
-
/**
|
|
9
|
+
/** 워커 빌드 완료 이벤트 데이터 */
|
|
10
10
|
export interface BuildEventData {
|
|
11
11
|
success: boolean;
|
|
12
12
|
errors?: string[];
|
|
13
13
|
warnings?: string[];
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
/**
|
|
16
|
+
/** 워커 에러 이벤트 데이터 */
|
|
17
17
|
export interface ErrorEventData {
|
|
18
18
|
message: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
/**
|
|
21
|
+
/** 워커 서버 준비 완료 이벤트 데이터 */
|
|
22
22
|
export interface ServerReadyEventData {
|
|
23
23
|
port: number;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/** Server
|
|
26
|
+
/** Server 빌드 완료 이벤트 데이터 */
|
|
27
27
|
export interface ServerBuildEventData {
|
|
28
28
|
success: boolean;
|
|
29
29
|
mainJsPath: string;
|
|
@@ -32,7 +32,7 @@ export interface ServerBuildEventData {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* 기본 Worker 정보 타입
|
|
36
36
|
*/
|
|
37
37
|
export interface BaseWorkerInfo<TEvents extends Record<string, unknown> = Record<string, unknown>> {
|
|
38
38
|
name: string;
|
|
@@ -46,7 +46,7 @@ export interface BaseWorkerInfo<TEvents extends Record<string, unknown> = Record
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* 워커 이벤트 핸들러 옵션
|
|
50
50
|
*/
|
|
51
51
|
export interface WorkerEventHandlerOptions {
|
|
52
52
|
resultKey: string;
|
|
@@ -55,13 +55,13 @@ export interface WorkerEventHandlerOptions {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
58
|
+
* 공통 Worker 이벤트 핸들러를 등록한다 (buildStart, build, error만 — serverReady 미포함)
|
|
59
59
|
*
|
|
60
|
-
* @param workerInfo
|
|
61
|
-
* @param opts
|
|
62
|
-
* @param results
|
|
63
|
-
* @param rebuildManager
|
|
64
|
-
* @returns completeTask
|
|
60
|
+
* @param workerInfo 워커 정보
|
|
61
|
+
* @param opts 핸들러 옵션
|
|
62
|
+
* @param results 결과 맵
|
|
63
|
+
* @param rebuildManager 재빌드 매니저
|
|
64
|
+
* @returns completeTask 함수 (결과 저장 및 빌드 완료 신호)
|
|
65
65
|
*/
|
|
66
66
|
export function registerWorkerEventHandlers(
|
|
67
67
|
workerInfo: {
|
|
@@ -85,18 +85,18 @@ export function registerWorkerEventHandlers(
|
|
|
85
85
|
workerInfo.isInitialBuild = false;
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
//
|
|
88
|
+
// 빌드 시작 (재빌드 시)
|
|
89
89
|
workerInfo.worker.on("buildStart", () => {
|
|
90
90
|
if (!workerInfo.isInitialBuild) {
|
|
91
91
|
workerInfo.buildResolver = rebuildManager.registerBuild(opts.resultKey, opts.listrTitle);
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
//
|
|
95
|
+
// 빌드 완료
|
|
96
96
|
workerInfo.worker.on("build", (data) => {
|
|
97
97
|
workerEventsLogger.debug(`[${workerInfo.name}] build: success=${String(data.success)}`);
|
|
98
98
|
|
|
99
|
-
//
|
|
99
|
+
// 경고 출력
|
|
100
100
|
if (data.warnings != null && data.warnings.length > 0) {
|
|
101
101
|
workerEventsLogger.warn(
|
|
102
102
|
formatBuildMessages(workerInfo.name, workerInfo.config.target, data.warnings),
|
|
@@ -112,7 +112,7 @@ export function registerWorkerEventHandlers(
|
|
|
112
112
|
});
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
//
|
|
115
|
+
// 에러
|
|
116
116
|
workerInfo.worker.on("error", (data) => {
|
|
117
117
|
workerEventsLogger.debug(`[${workerInfo.name}] error: ${data.message}`);
|
|
118
118
|
completeTask({
|
|
@@ -2,11 +2,11 @@ import consola, { type ConsolaInstance, LogLevels } from "consola";
|
|
|
2
2
|
import { SdCliReporter } from "./SdCliReporter";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* 워커 스레드에서 sd-cli 리포터와 디버그 로그 레벨을 적용한다.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* SD_DEBUG 환경변수(메인 프로세스의 --debug 플래그로 설정)를 확인하고
|
|
8
|
+
* 현재 워커 스레드의 consola에 디버그 로그 레벨을 적용한다.
|
|
9
|
+
* 워커 모듈 최상위에서 호출해야 한다.
|
|
10
10
|
*/
|
|
11
11
|
export function applyDebugLevel(): void {
|
|
12
12
|
consola.options.reporters = [new SdCliReporter()];
|
|
@@ -16,14 +16,13 @@ export function applyDebugLevel(): void {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* 워커 프로세스 종료 시그널에 대한 정리 핸들러를 등록한다.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* exit with code 0.
|
|
21
|
+
* 프로세스 종료 전 리소스를 정상적으로 정리하기 위해 SIGINT와 SIGTERM 핸들러를 등록한다.
|
|
22
|
+
* 두 핸들러 모두 정리 함수를 실행하고 코드 0으로 종료한다.
|
|
24
23
|
*
|
|
25
|
-
* @param cleanup -
|
|
26
|
-
* @param logger -
|
|
24
|
+
* @param cleanup - 종료 시 실행할 정리 함수 (동기 또는 비동기)
|
|
25
|
+
* @param logger - 에러 로깅용 consola 로거 인스턴스
|
|
27
26
|
*/
|
|
28
27
|
export function registerCleanupHandlers(
|
|
29
28
|
cleanup: () => void | Promise<void>,
|
|
@@ -45,10 +44,10 @@ export function registerCleanupHandlers(
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
/**
|
|
48
|
-
*
|
|
47
|
+
* Worker 함수의 중복 호출을 방지하는 가드를 생성한다.
|
|
49
48
|
*
|
|
50
|
-
* @param label -
|
|
51
|
-
* @returns
|
|
49
|
+
* @param label - 에러 메시지에 사용할 함수명
|
|
50
|
+
* @returns 두 번 호출되면 에러를 던지는 가드 함수
|
|
52
51
|
*/
|
|
53
52
|
export function createOnceGuard(label: string): () => void {
|
|
54
53
|
let called = false;
|
package/src/vitest-plugin.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import ts from "typescript";
|
|
4
|
+
import { pathx } from "@simplysm/core-node";
|
|
4
5
|
import { NgtscProgram, type AngularLibraryHostExtensions } from "./utils/angular-build";
|
|
5
6
|
import { compileScssString, compileScssFile } from "./utils/scss-compiler";
|
|
6
7
|
|
|
@@ -48,7 +49,7 @@ export function angularVitestPlugin(options: AngularVitestPluginOptions): Plugin
|
|
|
48
49
|
|
|
49
50
|
const host = ts.createCompilerHost(compilerOptions);
|
|
50
51
|
|
|
51
|
-
// AngularLibraryHostExtensions
|
|
52
|
+
// AngularLibraryHostExtensions 덕 타이핑
|
|
52
53
|
const hostExt = host as ts.CompilerHost & AngularLibraryHostExtensions;
|
|
53
54
|
hostExt.readResource = (fileName: string) => ts.sys.readFile(fileName) ?? "";
|
|
54
55
|
|
|
@@ -95,12 +96,12 @@ export function angularVitestPlugin(options: AngularVitestPluginOptions): Plugin
|
|
|
95
96
|
const { transformers } = program.compiler.prepareEmit();
|
|
96
97
|
const tsProgram = program.getTsProgram();
|
|
97
98
|
|
|
98
|
-
//
|
|
99
|
+
// 파일별 emit
|
|
99
100
|
for (const filePath of sourceFiles) {
|
|
100
101
|
const sf = tsProgram.getSourceFile(filePath);
|
|
101
102
|
if (sf == null) continue;
|
|
102
103
|
|
|
103
|
-
currentSourcePath =
|
|
104
|
+
currentSourcePath = pathx.posix(filePath);
|
|
104
105
|
tsProgram.emit(sf, host.writeFile, undefined, false, transformers);
|
|
105
106
|
}
|
|
106
107
|
},
|
|
@@ -110,7 +111,7 @@ export function angularVitestPlugin(options: AngularVitestPluginOptions): Plugin
|
|
|
110
111
|
return undefined;
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
const compiled = compiledFiles.get(
|
|
114
|
+
const compiled = compiledFiles.get(pathx.posix(id));
|
|
114
115
|
if (compiled == null) {
|
|
115
116
|
return undefined;
|
|
116
117
|
}
|
|
@@ -119,7 +120,3 @@ export function angularVitestPlugin(options: AngularVitestPluginOptions): Plugin
|
|
|
119
120
|
},
|
|
120
121
|
};
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
-
function normalizePath(p: string): string {
|
|
124
|
-
return p.replace(/\\/g, "/");
|
|
125
|
-
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createServer, build as viteBuild, type ViteDevServer } from "vite";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import http from "node:http";
|
|
5
|
+
import mime from "mime";
|
|
4
6
|
import { createWorker } from "@simplysm/core-node";
|
|
5
7
|
import { err as errNs } from "@simplysm/core-common";
|
|
6
8
|
import { consola } from "consola";
|
|
@@ -31,8 +33,10 @@ export interface ClientBuildInfo {
|
|
|
31
33
|
browserSupport?: SdBrowserSupportConfig;
|
|
32
34
|
/** PWA 설정. false로 비활성화. 미설정 시 기본값으로 활성화 */
|
|
33
35
|
pwa?: false | SdPwaConfig;
|
|
34
|
-
/**
|
|
36
|
+
/** 컴파일의 ts.Program을 사용하여 lint 실행 */
|
|
35
37
|
enableLint?: boolean;
|
|
38
|
+
/** Vite optimizeDeps.exclude에 전달할 패키지 목록 */
|
|
39
|
+
exclude?: string[];
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
/** Client 빌드 결과 */
|
|
@@ -58,7 +62,113 @@ export interface ClientWorkerEvents extends Record<string, unknown> {
|
|
|
58
62
|
|
|
59
63
|
const logger = consola.withTag("sd:cli:client:worker");
|
|
60
64
|
|
|
65
|
+
/** viteBuild({ build: { watch: {} } }) 반환 타입의 최소 인터페이스 */
|
|
66
|
+
interface WatcherHandle {
|
|
67
|
+
on(event: string, handler: (event: { code: string; error?: { message: string } }) => void): void;
|
|
68
|
+
close(): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
|
|
61
71
|
let viteServer: ViteDevServer | undefined;
|
|
72
|
+
let rollupWatcher: WatcherHandle | undefined;
|
|
73
|
+
let legacyHttpServer: http.Server | undefined;
|
|
74
|
+
|
|
75
|
+
/** SSE 연결된 클라이언트 목록 (live reload용) */
|
|
76
|
+
const sseClients = new Set<http.ServerResponse>();
|
|
77
|
+
|
|
78
|
+
/** SSE 연결된 모든 클라이언트에 reload 신호를 전송한다 */
|
|
79
|
+
function notifyLiveReload(): void {
|
|
80
|
+
for (const client of sseClients) {
|
|
81
|
+
client.write("data: reload\n\n");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
/** live reload 클라이언트 스크립트 (HTML에 주입) */
|
|
87
|
+
const LIVE_RELOAD_SCRIPT = `<script>(function(){var s=new EventSource("__live-reload");s.onmessage=function(){location.reload();};})()</script>`;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* HTML 응답 시 live reload 스크립트를 </body> 직전에 주입한다.
|
|
91
|
+
*/
|
|
92
|
+
function injectLiveReloadScript(html: string): string {
|
|
93
|
+
const idx = html.lastIndexOf("</body>");
|
|
94
|
+
if (idx !== -1) {
|
|
95
|
+
return html.slice(0, idx) + LIVE_RELOAD_SCRIPT + html.slice(idx);
|
|
96
|
+
}
|
|
97
|
+
return html + LIVE_RELOAD_SCRIPT;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* legacy dev 모드용 HTTP 정적 파일 서버를 생성한다.
|
|
102
|
+
* dist/ 디렉토리의 파일을 서빙하고, SPA fallback + SSE live reload를 지원한다.
|
|
103
|
+
*/
|
|
104
|
+
function createLegacyHttpServer(distDir: string, basePath: string): http.Server {
|
|
105
|
+
return http.createServer((req, res) => {
|
|
106
|
+
const url = (req.url ?? "/").split("?")[0];
|
|
107
|
+
|
|
108
|
+
// basePath prefix 제거
|
|
109
|
+
let relativePath: string;
|
|
110
|
+
if (url.startsWith(basePath)) {
|
|
111
|
+
relativePath = url.slice(basePath.length);
|
|
112
|
+
} else {
|
|
113
|
+
res.writeHead(404);
|
|
114
|
+
res.end("Not Found");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// SSE live reload 엔드포인트
|
|
119
|
+
if (relativePath === "__live-reload" || relativePath === "/__live-reload") {
|
|
120
|
+
res.writeHead(200, {
|
|
121
|
+
"Content-Type": "text/event-stream",
|
|
122
|
+
"Cache-Control": "no-cache",
|
|
123
|
+
"Connection": "keep-alive",
|
|
124
|
+
});
|
|
125
|
+
sseClients.add(res);
|
|
126
|
+
req.on("close", () => {
|
|
127
|
+
sseClients.delete(res);
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 빈 경로 또는 / → index.html
|
|
133
|
+
if (relativePath === "" || relativePath === "/") {
|
|
134
|
+
relativePath = "index.html";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 선행 슬래시 제거
|
|
138
|
+
if (relativePath.startsWith("/")) {
|
|
139
|
+
relativePath = relativePath.slice(1);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const filePath = path.join(distDir, relativePath);
|
|
143
|
+
const ext = path.extname(filePath);
|
|
144
|
+
|
|
145
|
+
// 파일 존재 확인
|
|
146
|
+
if (fs.existsSync(filePath) && !fs.statSync(filePath).isDirectory()) {
|
|
147
|
+
const contentType = mime.getType(ext) ?? "application/octet-stream";
|
|
148
|
+
if (ext === ".html") {
|
|
149
|
+
// HTML: live reload 스크립트 주입
|
|
150
|
+
const content = injectLiveReloadScript(fs.readFileSync(filePath, "utf-8"));
|
|
151
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
152
|
+
res.end(content);
|
|
153
|
+
} else {
|
|
154
|
+
const content = fs.readFileSync(filePath);
|
|
155
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
156
|
+
res.end(content);
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
// SPA fallback: index.html 반환 (live reload 스크립트 주입)
|
|
160
|
+
const indexPath = path.join(distDir, "index.html");
|
|
161
|
+
if (fs.existsSync(indexPath)) {
|
|
162
|
+
const content = injectLiveReloadScript(fs.readFileSync(indexPath, "utf-8"));
|
|
163
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
164
|
+
res.end(content);
|
|
165
|
+
} else {
|
|
166
|
+
res.writeHead(404);
|
|
167
|
+
res.end("Not Found");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
62
172
|
|
|
63
173
|
function resolvePackageInfo(info: ClientBuildInfo): {
|
|
64
174
|
tsconfigPath: string;
|
|
@@ -77,6 +187,9 @@ function resolvePackageInfo(info: ClientBuildInfo): {
|
|
|
77
187
|
* 서버가 준비되면 serverReady 이벤트로 포트를 알린다.
|
|
78
188
|
*/
|
|
79
189
|
async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
190
|
+
if (info.browserSupport?.legacyModule === true) {
|
|
191
|
+
return startLegacyWatch(info);
|
|
192
|
+
}
|
|
80
193
|
logger.debug(`[${info.name}] client worker startWatch 시작 (port: ${info.port ?? "auto"})`);
|
|
81
194
|
try {
|
|
82
195
|
const { tsconfigPath, pkgName } = resolvePackageInfo(info);
|
|
@@ -102,6 +215,7 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
|
102
215
|
legacyModule: info.browserSupport?.legacyModule,
|
|
103
216
|
polyfills,
|
|
104
217
|
pwa: info.pwa,
|
|
218
|
+
exclude: info.exclude,
|
|
105
219
|
});
|
|
106
220
|
|
|
107
221
|
logger.debug(`[${info.name}] Vite server 생성 시작`);
|
|
@@ -138,15 +252,134 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
|
138
252
|
}
|
|
139
253
|
|
|
140
254
|
/**
|
|
141
|
-
*
|
|
255
|
+
* legacy watch 시작. Vite build --watch로 파일 변경을 감시한다.
|
|
256
|
+
* legacyModule: true일 때 createServer 대신 사용한다.
|
|
257
|
+
*/
|
|
258
|
+
async function startLegacyWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
259
|
+
logger.debug(`[${info.name}] client worker startLegacyWatch 시작`);
|
|
260
|
+
try {
|
|
261
|
+
const { tsconfigPath, pkgName } = resolvePackageInfo(info);
|
|
262
|
+
|
|
263
|
+
// dist 초기화 (첫 빌드만 비움)
|
|
264
|
+
const distDir = path.join(info.pkgDir, "dist");
|
|
265
|
+
fs.rmSync(distDir, { recursive: true, force: true });
|
|
266
|
+
|
|
267
|
+
// polyfills.ts 자동 감지
|
|
268
|
+
const polyfillsPath = path.join(info.pkgDir, "src", "polyfills.ts");
|
|
269
|
+
const polyfills = fs.existsSync(polyfillsPath) ? ["./src/polyfills.ts"] : undefined;
|
|
270
|
+
|
|
271
|
+
const viteConfig = await createClientViteConfig({
|
|
272
|
+
pkgDir: info.pkgDir,
|
|
273
|
+
pkgName,
|
|
274
|
+
mode: "build",
|
|
275
|
+
tsconfigPath,
|
|
276
|
+
serverPort: 0,
|
|
277
|
+
env: info.env,
|
|
278
|
+
watch: true,
|
|
279
|
+
onBuildStart: () => sender.send("buildStart", {}),
|
|
280
|
+
onBuild: (result) => sender.send("build", result),
|
|
281
|
+
enableLint: info.enableLint,
|
|
282
|
+
replaceDeps: info.replaceDeps,
|
|
283
|
+
onScopeRebuild: () => sender.send("scopeRebuild", {}),
|
|
284
|
+
browserslist: info.browserSupport?.browserslist,
|
|
285
|
+
postCssPlugins: info.browserSupport?.postCss?.plugins,
|
|
286
|
+
legacyModule: info.browserSupport?.legacyModule,
|
|
287
|
+
polyfills,
|
|
288
|
+
pwa: false,
|
|
289
|
+
exclude: info.exclude,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const watcher = (await viteBuild(viteConfig)) as WatcherHandle;
|
|
293
|
+
rollupWatcher = watcher;
|
|
294
|
+
|
|
295
|
+
// .config.json 생성
|
|
296
|
+
writeConfigJson(info.pkgDir, info.configs);
|
|
297
|
+
|
|
298
|
+
// HTTP 정적 파일 서버 시작
|
|
299
|
+
const name = pkgName.replace(/^@[^/]+\//, "");
|
|
300
|
+
const basePath = `/${name}/`;
|
|
301
|
+
const httpServer = createLegacyHttpServer(distDir, basePath);
|
|
302
|
+
legacyHttpServer = httpServer;
|
|
303
|
+
|
|
304
|
+
const serverPort = await new Promise<number>((resolve, reject) => {
|
|
305
|
+
httpServer.listen(info.port ?? 0, "0.0.0.0", () => {
|
|
306
|
+
const addr = httpServer.address();
|
|
307
|
+
if (typeof addr === "object" && addr != null) {
|
|
308
|
+
resolve(addr.port);
|
|
309
|
+
} else {
|
|
310
|
+
reject(new Error("HTTP 서버 포트를 감지할 수 없습니다."));
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
httpServer.on("error", reject);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
sender.send("serverReady", { port: serverPort });
|
|
317
|
+
|
|
318
|
+
// 첫 빌드 완료 대기
|
|
319
|
+
return await new Promise<ClientBuildResult>((resolve) => {
|
|
320
|
+
let firstBuildResolved = false;
|
|
321
|
+
|
|
322
|
+
watcher.on("event", (event: { code: string; error?: { message: string } }) => {
|
|
323
|
+
if (event.code === "END") {
|
|
324
|
+
if (!firstBuildResolved) {
|
|
325
|
+
firstBuildResolved = true;
|
|
326
|
+
resolve({ success: true });
|
|
327
|
+
} else {
|
|
328
|
+
// 재빌드 완료 → 브라우저 live reload
|
|
329
|
+
notifyLiveReload();
|
|
330
|
+
}
|
|
331
|
+
} else if (event.code === "ERROR") {
|
|
332
|
+
const message = event.error?.message ?? "Unknown build error";
|
|
333
|
+
sender.send("error", { message });
|
|
334
|
+
if (!firstBuildResolved) {
|
|
335
|
+
firstBuildResolved = true;
|
|
336
|
+
resolve({ success: false, errors: [message] });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
} catch (err) {
|
|
342
|
+
const message = errNs.message(err);
|
|
343
|
+
sender.send("error", { message });
|
|
344
|
+
return { success: false, errors: [message] };
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* dev server 중지. Vite server 또는 RollupWatcher를 정리한다.
|
|
142
350
|
*/
|
|
143
351
|
async function stopWatch(): Promise<void> {
|
|
144
352
|
logger.debug("Vite server 정리 시작");
|
|
353
|
+
|
|
354
|
+
const watcherToClose = rollupWatcher;
|
|
355
|
+
rollupWatcher = undefined;
|
|
356
|
+
if (watcherToClose != null) {
|
|
357
|
+
await watcherToClose.close();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// SSE 클라이언트 정리
|
|
361
|
+
for (const client of sseClients) {
|
|
362
|
+
client.end();
|
|
363
|
+
}
|
|
364
|
+
sseClients.clear();
|
|
365
|
+
|
|
366
|
+
const httpServerToClose = legacyHttpServer;
|
|
367
|
+
legacyHttpServer = undefined;
|
|
368
|
+
if (httpServerToClose != null) {
|
|
369
|
+
await new Promise<void>((resolve, reject) => {
|
|
370
|
+
httpServerToClose.close((err) => {
|
|
371
|
+
if (err != null) reject(err);
|
|
372
|
+
else resolve();
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
145
377
|
const serverToClose = viteServer;
|
|
146
378
|
viteServer = undefined;
|
|
147
379
|
if (serverToClose != null) {
|
|
148
380
|
await serverToClose.close();
|
|
149
381
|
}
|
|
382
|
+
|
|
150
383
|
logger.debug("Vite server 정리 완료");
|
|
151
384
|
}
|
|
152
385
|
|
|
@@ -182,6 +415,7 @@ async function build(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
|
182
415
|
legacyModule: info.browserSupport?.legacyModule,
|
|
183
416
|
polyfills,
|
|
184
417
|
pwa: info.pwa,
|
|
418
|
+
exclude: info.exclude,
|
|
185
419
|
});
|
|
186
420
|
|
|
187
421
|
await viteBuild(viteConfig);
|