@simplysm/sd-cli 14.0.15 → 14.0.17
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 +4 -3
- package/dist/angular/client-transform-stylesheet.d.ts +2 -0
- package/dist/angular/client-transform-stylesheet.d.ts.map +1 -1
- package/dist/angular/client-transform-stylesheet.js +88 -2
- package/dist/angular/client-transform-stylesheet.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts +7 -0
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +78 -16
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +24 -13
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +8 -9
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/device.d.ts +1 -1
- package/dist/commands/device.d.ts.map +1 -1
- package/dist/commands/device.js +61 -12
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/lint.d.ts +0 -1
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +2 -3
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/publish.js +3 -3
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/replace-deps.js +1 -1
- package/dist/commands/replace-deps.js.map +1 -1
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +1 -2
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/electron/electron.d.ts +3 -2
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +54 -31
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.js +1 -1
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.d.ts.map +1 -1
- package/dist/engines/NgtscEngine.js +0 -1
- package/dist/engines/NgtscEngine.js.map +1 -1
- package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
- package/dist/engines/ServerEsbuildEngine.js +0 -1
- package/dist/engines/ServerEsbuildEngine.js.map +1 -1
- package/dist/engines/TscEngine.d.ts.map +1 -1
- package/dist/engines/TscEngine.js +0 -1
- package/dist/engines/TscEngine.js.map +1 -1
- package/dist/engines/ViteEngine.d.ts.map +1 -1
- package/dist/engines/ViteEngine.js +10 -1
- package/dist/engines/ViteEngine.js.map +1 -1
- package/dist/engines/index.d.ts +0 -10
- package/dist/engines/index.d.ts.map +1 -1
- package/dist/engines/index.js +0 -5
- package/dist/engines/index.js.map +1 -1
- package/dist/engines/types.d.ts +0 -1
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/infra/SignalHandler.d.ts +1 -6
- package/dist/infra/SignalHandler.d.ts.map +1 -1
- package/dist/infra/SignalHandler.js +4 -13
- package/dist/infra/SignalHandler.js.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +7 -12
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +18 -11
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/sd-cli-entry.d.ts +0 -1
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +13 -16
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.js +1 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/sd-config.types.d.ts +12 -2
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/angular-compiler.d.ts.map +1 -1
- package/dist/utils/angular-compiler.js +20 -13
- package/dist/utils/angular-compiler.js.map +1 -1
- package/dist/utils/esbuild-config.d.ts +1 -1
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/esbuild-config.js +1 -4
- package/dist/utils/esbuild-config.js.map +1 -1
- package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
- package/dist/utils/ngtsc-build-core.js +3 -0
- package/dist/utils/ngtsc-build-core.js.map +1 -1
- package/dist/utils/orchestrator-utils.js +1 -1
- package/dist/utils/orchestrator-utils.js.map +1 -1
- package/dist/utils/tsc-build.d.ts +5 -0
- package/dist/utils/tsc-build.d.ts.map +1 -1
- package/dist/utils/tsc-build.js +2 -1
- package/dist/utils/tsc-build.js.map +1 -1
- package/dist/utils/vite-config.d.ts +1 -1
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +22 -53
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/utils/vite-pwa-plugin.d.ts +9 -0
- package/dist/utils/vite-pwa-plugin.d.ts.map +1 -0
- package/dist/utils/vite-pwa-plugin.js +139 -0
- package/dist/utils/vite-pwa-plugin.js.map +1 -0
- package/dist/utils/worker-utils.d.ts +2 -5
- package/dist/utils/worker-utils.d.ts.map +1 -1
- package/dist/utils/worker-utils.js +5 -11
- package/dist/utils/worker-utils.js.map +1 -1
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +9 -3
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/library-build.worker.d.ts.map +1 -1
- package/dist/workers/library-build.worker.js +6 -2
- package/dist/workers/library-build.worker.js.map +1 -1
- package/dist/workers/ngtsc-build.worker.js +2 -2
- package/dist/workers/ngtsc-build.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +6 -2
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-runtime.worker.js +4 -4
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/docs/config.md +30 -2
- package/docs/pwa-configuration-types.md +1 -1
- package/package.json +8 -10
- package/src/angular/client-transform-stylesheet.ts +104 -2
- package/src/angular/vite-angular-plugin.ts +92 -31
- package/src/capacitor/capacitor.ts +25 -26
- package/src/commands/check.ts +8 -11
- package/src/commands/device.ts +71 -17
- package/src/commands/lint.ts +2 -3
- package/src/commands/publish.ts +3 -3
- package/src/commands/replace-deps.ts +1 -1
- package/src/commands/typecheck.ts +1 -2
- package/src/electron/electron.ts +62 -43
- package/src/engines/BaseEngine.ts +1 -1
- package/src/engines/NgtscEngine.ts +0 -1
- package/src/engines/ServerEsbuildEngine.ts +0 -1
- package/src/engines/TscEngine.ts +0 -1
- package/src/engines/ViteEngine.ts +9 -1
- package/src/engines/index.ts +0 -10
- package/src/engines/types.ts +0 -1
- package/src/infra/SignalHandler.ts +4 -14
- package/src/orchestrators/BuildOrchestrator.ts +7 -9
- package/src/orchestrators/DevWatchOrchestrator.ts +22 -10
- package/src/sd-cli-entry.ts +17 -24
- package/src/sd-cli.ts +1 -1
- package/src/sd-config.types.ts +13 -2
- package/src/utils/angular-compiler.ts +21 -21
- package/src/utils/esbuild-config.ts +2 -5
- package/src/utils/ngtsc-build-core.ts +7 -0
- package/src/utils/orchestrator-utils.ts +1 -1
- package/src/utils/tsc-build.ts +7 -0
- package/src/utils/vite-config.ts +23 -55
- package/src/utils/vite-pwa-plugin.ts +168 -0
- package/src/utils/worker-utils.ts +5 -11
- package/src/workers/client.worker.ts +11 -3
- package/src/workers/library-build.worker.ts +6 -2
- package/src/workers/ngtsc-build.worker.ts +2 -2
- package/src/workers/server-build.worker.ts +7 -2
- package/src/workers/server-runtime.worker.ts +4 -4
- package/tests/angular/client-transform-stylesheet.spec.ts +43 -0
- package/tests/angular/find-affected-by-scss.spec.ts +37 -0
- package/tests/angular/fixtures/basic-app/scss/_colors.scss +1 -0
- package/tests/angular/fixtures/basic-app/scss/_variables.scss +3 -0
- package/tests/angular/fixtures/basic-app/src/styled.component.ts +14 -0
- package/tests/angular/linker-disk-cache.spec.ts +158 -0
- package/tests/angular/scss-disk-cache.spec.ts +162 -0
- package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +15 -15
- package/tests/angular/vite-angular-plugin-hmr.spec.ts +9 -9
- package/tests/angular/vite-angular-plugin-lint.spec.ts +4 -4
- package/tests/angular/vite-angular-plugin-scss-hmr.spec.ts +87 -0
- package/tests/angular/vite-angular-plugin.spec.ts +15 -15
- package/tests/capacitor/capacitor-icon.spec.ts +2 -4
- package/tests/capacitor/capacitor-init.spec.ts +2 -4
- package/tests/capacitor/capacitor-workspace.spec.ts +2 -4
- package/tests/commands/device.spec.ts +108 -8
- package/tests/commands/publish.spec.ts +2 -2
- package/tests/commands/typecheck.spec.ts +1 -1
- package/tests/electron/electron.spec.ts +24 -17
- package/tests/engines/ngtsc-engine.spec.ts +0 -3
- package/tests/engines/server-esbuild-engine.spec.ts +0 -3
- package/tests/engines/tsc-engine.spec.ts +1 -2
- package/tests/engines/vite-engine.spec.ts +0 -2
- package/tests/infra/signal-handler.spec.ts +1 -12
- package/tests/orchestrators/build-orchestrator.spec.ts +1 -7
- package/tests/orchestrators/dev-watch-orchestrator.spec.ts +24 -66
- package/tests/utils/angular-compiler.spec.ts +1396 -32
- package/tests/utils/esbuild-config.spec.ts +4 -7
- package/tests/utils/{ngtsc-build-core-angular-compiler.spec.ts → ngtsc-build-core.spec.ts} +142 -11
- package/tests/utils/orchestrator-utils.spec.ts +2 -2
- package/tests/utils/sd-config.spec.ts +2 -2
- package/tests/utils/tsc-build.spec.ts +4 -1
- package/tests/utils/vite-config.spec.ts +130 -261
- package/tests/utils/vite-pwa-plugin.acc.spec.ts +143 -0
- package/tests/utils/vite-pwa-plugin.spec.ts +350 -0
- package/tests/utils/worker-utils.spec.ts +8 -7
- package/tests/workers/client-worker.spec.ts +50 -1
- package/tests/workers/dev-port-file.verify.md +6 -0
- package/tests/workers/library-build-lint.spec.ts +1 -1
- package/tests/workers/library-build-worker.spec.ts +1 -1
- package/tests/workers/ngtsc-build-lint.spec.ts +1 -1
- package/tests/workers/server-build-lint.spec.ts +1 -1
- package/tests/workers/server-build-worker.spec.ts +1 -1
- package/tests/workers/server-runtime-worker.spec.ts +8 -1
- package/dist/infra/WorkerManager.d.ts +0 -40
- package/dist/infra/WorkerManager.d.ts.map +0 -1
- package/dist/infra/WorkerManager.js +0 -59
- package/dist/infra/WorkerManager.js.map +0 -1
- package/dist/utils/SdCliReporter.d.ts +0 -18
- package/dist/utils/SdCliReporter.d.ts.map +0 -1
- package/dist/utils/SdCliReporter.js +0 -144
- package/dist/utils/SdCliReporter.js.map +0 -1
- package/src/infra/WorkerManager.ts +0 -65
- package/src/utils/SdCliReporter.ts +0 -177
- package/tests/angular/scss-compiler-async.spec.ts +0 -54
- package/tests/commands/dev.spec.ts +0 -53
- package/tests/commands/watch.spec.ts +0 -53
- package/tests/infra/worker-manager.spec.ts +0 -63
- package/tests/utils/angular-compiler-emit.spec.ts +0 -570
- package/tests/utils/angular-compiler-init.spec.ts +0 -705
- package/tests/utils/angular-compiler-update.spec.ts +0 -293
- package/tests/utils/build-env.spec.ts +0 -33
- package/tests/utils/ngtsc-build-core-transform-stylesheet.spec.ts +0 -124
- package/tests/utils/ngtsc-scss-refactor.spec.ts +0 -47
|
@@ -200,8 +200,8 @@ export class BuildOrchestrator {
|
|
|
200
200
|
|
|
201
201
|
// 결과 수집
|
|
202
202
|
const results: BuildStepResult[] = [];
|
|
203
|
-
// 에러 추적 (
|
|
204
|
-
|
|
203
|
+
// results에 포함되지 않는 에러 추적 (네이티브 빌드 실패, rejected 태스크 등)
|
|
204
|
+
let hasUntrackedError = false;
|
|
205
205
|
|
|
206
206
|
// 파일 캐시 (진단 출력용)
|
|
207
207
|
const fileCache = new Map<string, string>();
|
|
@@ -249,7 +249,6 @@ export class BuildOrchestrator {
|
|
|
249
249
|
warnings: engineResult.build.warnings.length > 0 ? engineResult.build.warnings : undefined,
|
|
250
250
|
diagnostics,
|
|
251
251
|
});
|
|
252
|
-
if (!engineResult.build.success) state.hasError = true;
|
|
253
252
|
|
|
254
253
|
} finally {
|
|
255
254
|
await engine.stop();
|
|
@@ -289,7 +288,6 @@ export class BuildOrchestrator {
|
|
|
289
288
|
warnings: engineResult.build.warnings.length > 0 ? engineResult.build.warnings : undefined,
|
|
290
289
|
diagnostics,
|
|
291
290
|
});
|
|
292
|
-
if (!engineResult.build.success) state.hasError = true;
|
|
293
291
|
|
|
294
292
|
} finally {
|
|
295
293
|
await engine.stop();
|
|
@@ -327,7 +325,6 @@ export class BuildOrchestrator {
|
|
|
327
325
|
warnings: engineResult.build.warnings.length > 0 ? engineResult.build.warnings : undefined,
|
|
328
326
|
diagnostics,
|
|
329
327
|
});
|
|
330
|
-
if (!engineResult.build.success) state.hasError = true;
|
|
331
328
|
|
|
332
329
|
// 네이티브 빌드 (빌드 성공 시에만 실행)
|
|
333
330
|
if (engineResult.build.success) {
|
|
@@ -362,7 +359,7 @@ export class BuildOrchestrator {
|
|
|
362
359
|
const nativeResults = await Promise.allSettled(nativeBuildPromises);
|
|
363
360
|
for (const nativeResult of nativeResults) {
|
|
364
361
|
if (nativeResult.status === "rejected") {
|
|
365
|
-
|
|
362
|
+
hasUntrackedError = true;
|
|
366
363
|
const err = nativeResult.reason;
|
|
367
364
|
this._logger.error(
|
|
368
365
|
`[${name}] 네이티브 빌드 실패: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -391,7 +388,7 @@ export class BuildOrchestrator {
|
|
|
391
388
|
if (stack != null) {
|
|
392
389
|
this._logger.debug(`빌드 예외 스택:\n${stack}`);
|
|
393
390
|
}
|
|
394
|
-
|
|
391
|
+
hasUntrackedError = true;
|
|
395
392
|
}
|
|
396
393
|
}
|
|
397
394
|
this._logger.success("빌드 실행 완료");
|
|
@@ -429,13 +426,14 @@ export class BuildOrchestrator {
|
|
|
429
426
|
// 최종 결과 로그
|
|
430
427
|
const errorCount = results.filter((r) => !r.success).length;
|
|
431
428
|
const warningCount = results.filter((r) => r.warnings != null).length;
|
|
432
|
-
|
|
429
|
+
const hasError = errorCount > 0 || hasUntrackedError;
|
|
430
|
+
if (hasError) {
|
|
433
431
|
this._logger.error("빌드 에러 발생", { errorCount, warningCount });
|
|
434
432
|
} else {
|
|
435
433
|
this._logger.info("빌드 완료", { errorCount, warningCount });
|
|
436
434
|
}
|
|
437
435
|
|
|
438
|
-
return
|
|
436
|
+
return hasError;
|
|
439
437
|
}
|
|
440
438
|
|
|
441
439
|
/**
|
|
@@ -97,7 +97,7 @@ export class DevWatchOrchestrator {
|
|
|
97
97
|
sdConfig = await loadSdConfig({
|
|
98
98
|
cwd: this._cwd,
|
|
99
99
|
dev: true,
|
|
100
|
-
|
|
100
|
+
opt: this._options.options,
|
|
101
101
|
});
|
|
102
102
|
this._logger.debug("sd.config.ts 로드 완료");
|
|
103
103
|
} catch (err) {
|
|
@@ -156,15 +156,11 @@ export class DevWatchOrchestrator {
|
|
|
156
156
|
this._resultCollector = new ResultCollector();
|
|
157
157
|
this._rebuildManager = new RebuildManager(this._logger);
|
|
158
158
|
|
|
159
|
-
// 배치 완료 핸들러
|
|
159
|
+
// 배치 완료 핸들러 (watch 모드만 여기서 등록, dev 모드는 _startDevMode() 끝에서 등록)
|
|
160
160
|
if (this._options.mode === "watch") {
|
|
161
161
|
this._rebuildManager.on("batchComplete", (_completedKeys) => {
|
|
162
162
|
printErrors(this._resultCollector.toMap());
|
|
163
163
|
});
|
|
164
|
-
} else {
|
|
165
|
-
this._rebuildManager.on("batchComplete", (completedKeys) => {
|
|
166
|
-
this._onDevBatchComplete(completedKeys);
|
|
167
|
-
});
|
|
168
164
|
}
|
|
169
165
|
|
|
170
166
|
// 라이브러리 패키지용 BuildEngine 생성 (watch 모드 전용)
|
|
@@ -418,9 +414,26 @@ export class DevWatchOrchestrator {
|
|
|
418
414
|
}
|
|
419
415
|
}
|
|
420
416
|
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
|
|
417
|
+
// 모든 엔진 준비 완료 후 서버 런타임 시작 (클라이언트 포트 확보 보장)
|
|
418
|
+
await this._restartServers();
|
|
419
|
+
|
|
420
|
+
// 독립 클라이언트만 존재하고 서버가 없는 경우 URL 출력 예약
|
|
421
|
+
if (this._serverPackages.length === 0) {
|
|
422
|
+
const hasIndependentClients = this._clientPackages.some(({ name }) => {
|
|
423
|
+
const isServerConnected = [...this._serverClientsMap.values()].some(
|
|
424
|
+
(clients) => clients.includes(name),
|
|
425
|
+
);
|
|
426
|
+
return !isServerConnected && this._getClientPort(name) != null;
|
|
427
|
+
});
|
|
428
|
+
if (hasIndependentClients) {
|
|
429
|
+
this._schedulePrintServers();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// dev 모드 배치 완료 핸들러 등록 (이후 watch 이벤트용)
|
|
434
|
+
this._rebuildManager.on("batchComplete", (completedKeys) => {
|
|
435
|
+
this._onDevBatchComplete(completedKeys);
|
|
436
|
+
});
|
|
424
437
|
}
|
|
425
438
|
|
|
426
439
|
private _onDevBatchComplete(completedKeys: string[]): void {
|
|
@@ -464,7 +477,6 @@ export class DevWatchOrchestrator {
|
|
|
464
477
|
await Promise.all(restartPromises);
|
|
465
478
|
this._logger.debug("서버 재시작 완료");
|
|
466
479
|
printErrors(this._resultCollector.toMap());
|
|
467
|
-
this._schedulePrintServers();
|
|
468
480
|
}
|
|
469
481
|
|
|
470
482
|
private _schedulePrintServers(): void {
|
package/src/sd-cli-entry.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
/* eslint-disable no-console */
|
|
3
3
|
|
|
4
4
|
// 사이드 이펙트: Map/Array prototype 확장 (getOrCreate 등)
|
|
5
|
-
import "@simplysm/core-common";
|
|
5
|
+
import { env } from "@simplysm/core-common";
|
|
6
6
|
import yargs, { type Argv } from "yargs";
|
|
7
7
|
import { hideBin } from "yargs/helpers";
|
|
8
|
-
import {
|
|
8
|
+
import { type CheckType, runCheck } from "./commands/check";
|
|
9
9
|
import { runWatch } from "./commands/watch";
|
|
10
10
|
import { runDev } from "./commands/dev";
|
|
11
11
|
import { runBuild } from "./commands/build";
|
|
@@ -15,14 +15,12 @@ import path from "path";
|
|
|
15
15
|
import fs from "fs";
|
|
16
16
|
import { fileURLToPath } from "url";
|
|
17
17
|
import { EventEmitter } from "node:events";
|
|
18
|
-
import { consola
|
|
19
|
-
import {
|
|
18
|
+
import { consola } from "consola";
|
|
19
|
+
import { setupConsola } from "@simplysm/core-node";
|
|
20
20
|
|
|
21
21
|
Error.stackTraceLimit = Infinity;
|
|
22
22
|
EventEmitter.defaultMaxListeners = 100;
|
|
23
23
|
|
|
24
|
-
consola.options.reporters = [new SdCliReporter()];
|
|
25
|
-
|
|
26
24
|
const COMMAND_NAMES = ["check", "watch", "dev", "device", "build", "publish", "replace-deps"];
|
|
27
25
|
|
|
28
26
|
async function collectYargsHelp(argv: string[]): Promise<string> {
|
|
@@ -36,7 +34,6 @@ async function collectYargsHelp(argv: string[]): Promise<string> {
|
|
|
36
34
|
} catch {
|
|
37
35
|
// yargs가 help 출력 후 throw할 수 있음
|
|
38
36
|
} finally {
|
|
39
|
-
|
|
40
37
|
console.log = orig;
|
|
41
38
|
}
|
|
42
39
|
return lines.join("\n");
|
|
@@ -58,9 +55,9 @@ export function createCliParser(argv: string[]): Argv {
|
|
|
58
55
|
async () => {
|
|
59
56
|
for (const cmdName of COMMAND_NAMES) {
|
|
60
57
|
const helpText = await collectYargsHelp([cmdName, "--help"]);
|
|
61
|
-
|
|
58
|
+
|
|
62
59
|
console.log(helpText);
|
|
63
|
-
|
|
60
|
+
|
|
64
61
|
console.log();
|
|
65
62
|
}
|
|
66
63
|
},
|
|
@@ -78,9 +75,9 @@ export function createCliParser(argv: string[]): Argv {
|
|
|
78
75
|
})
|
|
79
76
|
.middleware((args) => {
|
|
80
77
|
if (args.debug) {
|
|
81
|
-
|
|
82
|
-
process.env["SD_DEBUG"] = "true";
|
|
78
|
+
env("SD_DEBUG", "true");
|
|
83
79
|
}
|
|
80
|
+
setupConsola({ cli: true });
|
|
84
81
|
})
|
|
85
82
|
.command(
|
|
86
83
|
"check [targets..]",
|
|
@@ -113,9 +110,7 @@ export function createCliParser(argv: string[]): Argv {
|
|
|
113
110
|
types: (() => {
|
|
114
111
|
const validTypes = ["typecheck", "lint", "test"] as const;
|
|
115
112
|
const types = args.type.split(",").map((t) => t.trim());
|
|
116
|
-
const invalidTypes = types.filter(
|
|
117
|
-
(t) => !validTypes.includes(t as CheckType),
|
|
118
|
-
);
|
|
113
|
+
const invalidTypes = types.filter((t) => !validTypes.includes(t as CheckType));
|
|
119
114
|
if (invalidTypes.length > 0) {
|
|
120
115
|
throw new Error(
|
|
121
116
|
`Invalid check type(s): ${invalidTypes.join(", ")}. Valid types: ${validTypes.join(", ")}`,
|
|
@@ -186,24 +181,22 @@ export function createCliParser(argv: string[]): Argv {
|
|
|
186
181
|
},
|
|
187
182
|
)
|
|
188
183
|
.command(
|
|
189
|
-
"device",
|
|
184
|
+
"device [target]",
|
|
190
185
|
"Run native app on device/desktop",
|
|
191
186
|
(cmd) =>
|
|
192
187
|
cmd
|
|
193
188
|
.version(false)
|
|
194
189
|
.hide("help")
|
|
190
|
+
.positional("target", {
|
|
191
|
+
type: "string",
|
|
192
|
+
describe: "Client package to run (e.g., my-client-app)",
|
|
193
|
+
})
|
|
195
194
|
.options({
|
|
196
|
-
|
|
197
|
-
type: "string",
|
|
198
|
-
alias: "p",
|
|
199
|
-
description: "Client package name to run",
|
|
200
|
-
demandOption: true,
|
|
201
|
-
},
|
|
202
|
-
"url": {
|
|
195
|
+
url: {
|
|
203
196
|
type: "string",
|
|
204
197
|
description: "Dev server URL (auto-detected from sd.config.ts if omitted)",
|
|
205
198
|
},
|
|
206
|
-
|
|
199
|
+
opt: {
|
|
207
200
|
type: "string",
|
|
208
201
|
array: true,
|
|
209
202
|
alias: "o",
|
|
@@ -214,7 +207,7 @@ export function createCliParser(argv: string[]): Argv {
|
|
|
214
207
|
async (args) => {
|
|
215
208
|
const { runDevice } = await import("./commands/device");
|
|
216
209
|
await runDevice({
|
|
217
|
-
|
|
210
|
+
target: args.target,
|
|
218
211
|
url: args.url,
|
|
219
212
|
options: args.opt,
|
|
220
213
|
});
|
package/src/sd-cli.ts
CHANGED
|
@@ -30,7 +30,7 @@ if (isDev) {
|
|
|
30
30
|
try {
|
|
31
31
|
const { loadSdConfig } = await import("./utils/sd-config.js");
|
|
32
32
|
const { setupReplaceDeps } = await import("./utils/replace-deps.js");
|
|
33
|
-
const sdConfig = await loadSdConfig({ cwd: process.cwd(), dev: false,
|
|
33
|
+
const sdConfig = await loadSdConfig({ cwd: process.cwd(), dev: false, opt: [] });
|
|
34
34
|
if (process.argv[2] !== "replace-deps" && sdConfig.replaceDeps != null) {
|
|
35
35
|
await setupReplaceDeps(process.cwd(), sdConfig.replaceDeps);
|
|
36
36
|
}
|
package/src/sd-config.types.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/** npm package.json 구조 */
|
|
2
|
+
export interface NpmConfig {
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
dependencies?: Record<string, string>;
|
|
7
|
+
devDependencies?: Record<string, string>;
|
|
8
|
+
peerDependencies?: Record<string, string>;
|
|
9
|
+
volta?: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
1
12
|
/**
|
|
2
13
|
* 빌드 타겟 타입 (esbuild로 빌드)
|
|
3
14
|
* - node: Node.js 전용 패키지
|
|
@@ -169,7 +180,7 @@ export interface SdElectronConfig {
|
|
|
169
180
|
//#region PWA 설정 타입
|
|
170
181
|
|
|
171
182
|
/**
|
|
172
|
-
* PWA manifest 설정
|
|
183
|
+
* PWA manifest 설정
|
|
173
184
|
*/
|
|
174
185
|
export interface SdPwaManifestConfig {
|
|
175
186
|
name?: string;
|
|
@@ -325,7 +336,7 @@ export interface SdConfigParams {
|
|
|
325
336
|
/** 개발 모드 플래그 */
|
|
326
337
|
dev: boolean;
|
|
327
338
|
/** 추가 옵션 (CLI의 -o 플래그에서 전달) */
|
|
328
|
-
|
|
339
|
+
opt: string[];
|
|
329
340
|
}
|
|
330
341
|
|
|
331
342
|
/**
|
|
@@ -285,11 +285,16 @@ export class AngularCompiler {
|
|
|
285
285
|
const programFiles = tsProgram.getSourceFiles();
|
|
286
286
|
logger.debug(`ts.Program 소스 파일: ${programFiles.length}개`);
|
|
287
287
|
|
|
288
|
-
// 9. BuilderProgram 생성
|
|
288
|
+
// 9. BuilderProgram 생성 (진단 + affected file 탐지용)
|
|
289
|
+
// .tsbuildinfo에서 이전 상태를 복원하여 프로세스 재시작 후에도 incremental 진단 유지
|
|
290
|
+
let oldBuilderProgram = this._builderProgram;
|
|
291
|
+
if (oldBuilderProgram == null) {
|
|
292
|
+
oldBuilderProgram = ts.readBuilderProgram(mergedOptions, host) ?? undefined;
|
|
293
|
+
}
|
|
289
294
|
const builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
|
|
290
295
|
tsProgram,
|
|
291
296
|
host,
|
|
292
|
-
|
|
297
|
+
oldBuilderProgram,
|
|
293
298
|
);
|
|
294
299
|
|
|
295
300
|
// 10. AOT 분석
|
|
@@ -446,7 +451,7 @@ export class AngularCompiler {
|
|
|
446
451
|
}
|
|
447
452
|
|
|
448
453
|
const angularCompiler = this._ngtscProgram.compiler;
|
|
449
|
-
const
|
|
454
|
+
const tsProgram = this._ngtscProgram.getTsProgram();
|
|
450
455
|
const affectedFiles = this._affectedFiles;
|
|
451
456
|
|
|
452
457
|
// 2. prepareEmit() → Angular transformers 획득
|
|
@@ -466,7 +471,6 @@ export class AngularCompiler {
|
|
|
466
471
|
|
|
467
472
|
// 4. emit 결과를 수집하는 구조
|
|
468
473
|
const emitResults: EmitResult[] = [];
|
|
469
|
-
const emittedSourceFiles = new Set<ts.SourceFile>();
|
|
470
474
|
const emitDeclarationOnly = !!compilerOptions.emitDeclarationOnly;
|
|
471
475
|
|
|
472
476
|
const writeFileCallback: ts.WriteFileCallback = (
|
|
@@ -484,25 +488,16 @@ export class AngularCompiler {
|
|
|
484
488
|
return;
|
|
485
489
|
}
|
|
486
490
|
angularCompiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
|
|
487
|
-
emittedSourceFiles.add(sourceFile);
|
|
488
491
|
emitResults.push({ filename, contents, sourceFileName: sourceFile.fileName });
|
|
489
492
|
};
|
|
490
493
|
|
|
491
|
-
// 5.
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
)
|
|
499
|
-
) {
|
|
500
|
-
/* empty */
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// 6. 2차 루프: TypeScript가 affected로 판단하지 않았지만 Angular이 처리해야 할 파일
|
|
504
|
-
for (const sourceFile of builderProgram.getSourceFiles()) {
|
|
505
|
-
if (emittedSourceFiles.has(sourceFile) || angularCompiler.ignoreForEmit.has(sourceFile)) {
|
|
494
|
+
// 5. ts.Program.emit()으로 직접 emit (NgtscProgram.emit 패턴)
|
|
495
|
+
// EmitAndSemanticDiagnosticsBuilderProgram.emitNextAffectedFile()은 내부적으로
|
|
496
|
+
// emitKind를 DTS-only로 결정할 수 있어 Angular before transformer가 .js를 생성하지 않고
|
|
497
|
+
// DtsTransformRegistry에 메타데이터를 등록하지 않는 문제가 있다.
|
|
498
|
+
// ts.Program.emit()을 직접 호출하면 항상 full emit이 수행된다.
|
|
499
|
+
for (const sourceFile of tsProgram.getSourceFiles()) {
|
|
500
|
+
if (angularCompiler.ignoreForEmit.has(sourceFile)) {
|
|
506
501
|
continue;
|
|
507
502
|
}
|
|
508
503
|
if (sourceFile.isDeclarationFile) {
|
|
@@ -514,7 +509,7 @@ export class AngularCompiler {
|
|
|
514
509
|
) {
|
|
515
510
|
continue;
|
|
516
511
|
}
|
|
517
|
-
|
|
512
|
+
tsProgram.emit(
|
|
518
513
|
sourceFile,
|
|
519
514
|
writeFileCallback,
|
|
520
515
|
undefined,
|
|
@@ -523,6 +518,11 @@ export class AngularCompiler {
|
|
|
523
518
|
);
|
|
524
519
|
}
|
|
525
520
|
|
|
521
|
+
// 6. .tsbuildinfo 영속화 (프로세스 재시작 후 incremental 진단 유지)
|
|
522
|
+
// TS 5.9에서 emitBuildInfo()가 제거됨. emit()이 내부적으로 build info를 기록한다.
|
|
523
|
+
// no-op writeFile로 JS/DTS 재출력 없이 build info만 갱신.
|
|
524
|
+
this._builderProgram.emit(undefined, () => {});
|
|
525
|
+
|
|
526
526
|
// 7. sourceFilter 적용 후 yield
|
|
527
527
|
logger.debug(`emitAffectedFiles 완료 (${emitResults.length}개 파일)`);
|
|
528
528
|
for (const result of emitResults) {
|
|
@@ -14,9 +14,8 @@ const logger = consola.withTag("sd:cli:esbuild-config");
|
|
|
14
14
|
* - 기타 파일(.js.map 등): 원본 내용을 그대로 비교한다
|
|
15
15
|
* - 기존 파일과 내용이 동일하면 타임스탬프 보존을 위해 쓰기를 스킵한다
|
|
16
16
|
*/
|
|
17
|
-
export async function writeChangedOutputFiles(outputFiles: esbuild.OutputFile[]): Promise<
|
|
17
|
+
export async function writeChangedOutputFiles(outputFiles: esbuild.OutputFile[]): Promise<void> {
|
|
18
18
|
logger.debug(`변경된 출력 파일 쓰기 시작 (${outputFiles.length}개)`);
|
|
19
|
-
let hasChanges = false;
|
|
20
19
|
await Promise.all(
|
|
21
20
|
outputFiles.map(async (file) => {
|
|
22
21
|
const finalText = file.path.endsWith(".js")
|
|
@@ -36,13 +35,11 @@ export async function writeChangedOutputFiles(outputFiles: esbuild.OutputFile[])
|
|
|
36
35
|
// 파일이 아직 존재하지 않음
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
hasChanges = true;
|
|
40
38
|
await fs.mkdir(path.dirname(file.path), { recursive: true });
|
|
41
39
|
await fs.writeFile(file.path, finalText);
|
|
42
40
|
}),
|
|
43
41
|
);
|
|
44
|
-
logger.debug(
|
|
45
|
-
return hasChanges;
|
|
42
|
+
logger.debug("변경된 출력 파일 쓰기 완료");
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
/**
|
|
@@ -59,10 +59,17 @@ export function buildCompilerOptions(
|
|
|
59
59
|
pkgDir: string,
|
|
60
60
|
output: BuildOutput,
|
|
61
61
|
): ts.CompilerOptions {
|
|
62
|
+
const needsEmit = output.js || output.dts;
|
|
62
63
|
const options: ts.CompilerOptions = {
|
|
63
64
|
...baseOptions,
|
|
64
65
|
sourceMap: false,
|
|
65
66
|
outDir: path.join(pkgDir, "dist"),
|
|
67
|
+
incremental: true,
|
|
68
|
+
tsBuildInfoFile: path.join(
|
|
69
|
+
pkgDir,
|
|
70
|
+
".cache",
|
|
71
|
+
needsEmit ? "ngtsc-build.tsbuildinfo" : "ngtsc-typecheck.tsbuildinfo",
|
|
72
|
+
),
|
|
66
73
|
};
|
|
67
74
|
|
|
68
75
|
if (output.js && output.dts) {
|
|
@@ -19,7 +19,7 @@ export async function loadAndValidateConfig(params: {
|
|
|
19
19
|
const config = await loadSdConfig({
|
|
20
20
|
cwd: params.cwd,
|
|
21
21
|
dev: params.dev,
|
|
22
|
-
|
|
22
|
+
opt: params.options,
|
|
23
23
|
});
|
|
24
24
|
validateTargets(params.targets, params.packagesForValidation ?? config.packages);
|
|
25
25
|
return config;
|
package/src/utils/tsc-build.ts
CHANGED
|
@@ -30,6 +30,8 @@ export interface TscPackageBuildOptions {
|
|
|
30
30
|
env?: TypecheckEnv;
|
|
31
31
|
/** 타입체크 전용 모드에서 tests/ 파일 포함 여부. 기본값 false. */
|
|
32
32
|
includeTests?: boolean;
|
|
33
|
+
/** 이전 빌드의 BuilderProgram. watch 모드에서 SourceFile 재사용을 위해 전달한다. */
|
|
34
|
+
oldBuilderProgram?: ts.EmitAndSemanticDiagnosticsBuilderProgram;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -46,6 +48,9 @@ export interface TscPackageBuildResult {
|
|
|
46
48
|
/** 이 빌드에서 영향받은 파일 (정규화된 순방향 슬래시 경로).
|
|
47
49
|
* watch 모드에서 증분 lint에 사용한다. */
|
|
48
50
|
affectedFiles?: ReadonlySet<string>;
|
|
51
|
+
/** 다음 빌드에서 SourceFile 재사용을 위한 BuilderProgram.
|
|
52
|
+
* watch 모드에서 이 값을 저장해두고 다음 빌드 시 oldBuilderProgram으로 전달한다. */
|
|
53
|
+
builderProgram?: ts.EmitAndSemanticDiagnosticsBuilderProgram;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
/**
|
|
@@ -142,6 +147,7 @@ export function runTscPackageBuild(options: TscPackageBuildOptions): TscPackageB
|
|
|
142
147
|
rootFiles,
|
|
143
148
|
compilerOptions,
|
|
144
149
|
host,
|
|
150
|
+
options.oldBuilderProgram,
|
|
145
151
|
);
|
|
146
152
|
|
|
147
153
|
// builder program의 증분 분석을 통해 affected 파일을 추적한다.
|
|
@@ -199,6 +205,7 @@ export function runTscPackageBuild(options: TscPackageBuildOptions): TscPackageB
|
|
|
199
205
|
warningCount,
|
|
200
206
|
program: builderProgram.getProgram(),
|
|
201
207
|
affectedFiles,
|
|
208
|
+
builderProgram,
|
|
202
209
|
};
|
|
203
210
|
} catch (err) {
|
|
204
211
|
const message = errNs.message(err);
|
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 tsconfigPaths from "vite-tsconfig-paths";
|
|
4
3
|
import browserslistToEsbuild from "browserslist-to-esbuild";
|
|
5
4
|
import { sdAngularPlugin } from "../angular/vite-angular-plugin.js";
|
|
6
5
|
import solidPlugin from "vite-plugin-solid";
|
|
@@ -10,8 +9,7 @@ import {
|
|
|
10
9
|
} from "./vite-scope-watch-plugin.js";
|
|
11
10
|
import { sdPostCssInlinePlugin } from "../angular/vite-postcss-inline-plugin.js";
|
|
12
11
|
import type { SdPwaConfig } from "../sd-config.types.js";
|
|
13
|
-
import {
|
|
14
|
-
import { generatePwaIcons } from "./generate-pwa-icons.js";
|
|
12
|
+
import { sdPwaPlugin } from "./vite-pwa-plugin.js";
|
|
15
13
|
|
|
16
14
|
/** createClientViteConfig 옵션 */
|
|
17
15
|
export interface CreateClientViteConfigOptions {
|
|
@@ -70,9 +68,9 @@ export interface CreateClientViteConfigOptions {
|
|
|
70
68
|
* Angular AOT 플러그인, tsconfigPaths, env define, server/build 기본 설정,
|
|
71
69
|
* browserslist, PostCSS, polyfills, legacyModule (inlineDynamicImports) 등을 통합 구성한다.
|
|
72
70
|
*/
|
|
73
|
-
export
|
|
71
|
+
export function createClientViteConfig(
|
|
74
72
|
options: CreateClientViteConfigOptions,
|
|
75
|
-
):
|
|
73
|
+
): InlineConfig {
|
|
76
74
|
const name = options.pkgName.replace(/^@[^/]+\//, "");
|
|
77
75
|
|
|
78
76
|
// browserslist → esbuild target
|
|
@@ -101,9 +99,7 @@ export async function createClientViteConfig(
|
|
|
101
99
|
}
|
|
102
100
|
|
|
103
101
|
// plugins
|
|
104
|
-
const plugins: PluginOption[] = [
|
|
105
|
-
tsconfigPaths({ projects: [options.tsconfigPath] }),
|
|
106
|
-
];
|
|
102
|
+
const plugins: PluginOption[] = [];
|
|
107
103
|
|
|
108
104
|
if (options.framework === "solid") {
|
|
109
105
|
plugins.push(solidPlugin());
|
|
@@ -170,59 +166,23 @@ export async function createClientViteConfig(
|
|
|
170
166
|
const config: InlineConfig = {
|
|
171
167
|
root: options.pkgDir,
|
|
172
168
|
base: options.base ?? `/${name}/`,
|
|
169
|
+
resolve: { tsconfigPaths: true },
|
|
173
170
|
define: Object.keys(define).length > 0 ? define : undefined,
|
|
174
171
|
plugins,
|
|
175
172
|
server: serverConfig,
|
|
176
173
|
css: cssConfig,
|
|
177
|
-
esbuild: {
|
|
178
|
-
target: esbuildTarget,
|
|
179
|
-
},
|
|
180
174
|
build: {
|
|
181
175
|
target: esbuildTarget,
|
|
182
176
|
},
|
|
183
177
|
optimizeDeps: {
|
|
184
178
|
...optimizeDepsConfig,
|
|
185
|
-
esbuildOptions: {
|
|
186
|
-
target: esbuildTarget as string[],
|
|
187
|
-
},
|
|
188
179
|
},
|
|
189
180
|
};
|
|
190
181
|
|
|
191
182
|
// PWA (build 모드 + pwa !== false)
|
|
192
183
|
if (options.mode === "build" && options.pwa !== false) {
|
|
193
|
-
const pwaConfig = typeof options.pwa === "object" ? options.pwa : {};
|
|
194
|
-
|
|
195
|
-
// 아이콘 자동 생성 (커스텀 icons 미설정 시)
|
|
196
|
-
let iconsConfig: Record<string, unknown> = {};
|
|
197
|
-
if (pwaConfig.manifest?.icons != null) {
|
|
198
|
-
iconsConfig = { icons: pwaConfig.manifest.icons };
|
|
199
|
-
} else {
|
|
200
|
-
const generatedIcons = await generatePwaIcons(options.pkgDir);
|
|
201
|
-
if (generatedIcons.length > 0) {
|
|
202
|
-
iconsConfig = { icons: generatedIcons };
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const pwaManifest = {
|
|
207
|
-
name: pwaConfig.manifest?.name ?? name,
|
|
208
|
-
short_name: pwaConfig.manifest?.short_name ?? name,
|
|
209
|
-
display: pwaConfig.manifest?.display ?? "standalone",
|
|
210
|
-
theme_color: pwaConfig.manifest?.theme_color ?? "#ffffff",
|
|
211
|
-
background_color: pwaConfig.manifest?.background_color ?? "#ffffff",
|
|
212
|
-
...iconsConfig,
|
|
213
|
-
};
|
|
214
|
-
const pwaWorkbox = {
|
|
215
|
-
globPatterns: pwaConfig.workbox?.globPatterns ?? [
|
|
216
|
-
"**/*.{js,css,html,ico,png,svg,woff2}",
|
|
217
|
-
],
|
|
218
|
-
};
|
|
219
184
|
(config.plugins as PluginOption[]).push(
|
|
220
|
-
|
|
221
|
-
registerType: "prompt",
|
|
222
|
-
injectRegister: "script",
|
|
223
|
-
manifest: pwaManifest,
|
|
224
|
-
workbox: pwaWorkbox,
|
|
225
|
-
}),
|
|
185
|
+
sdPwaPlugin({ pkgDir: options.pkgDir, pkgName: name, pwa: options.pwa }),
|
|
226
186
|
);
|
|
227
187
|
}
|
|
228
188
|
|
|
@@ -271,24 +231,18 @@ export async function createClientViteConfig(
|
|
|
271
231
|
}
|
|
272
232
|
}
|
|
273
233
|
|
|
274
|
-
// legacyModule: true → 코드 스플리팅 비활성화 +
|
|
234
|
+
// legacyModule: true → 코드 스플리팅 비활성화 + import.meta/import() 치환 (Chrome 61 호환)
|
|
275
235
|
if (options.legacyModule === true) {
|
|
276
|
-
config.esbuild = {
|
|
277
|
-
...config.esbuild,
|
|
278
|
-
supported: {
|
|
279
|
-
"import-meta": false,
|
|
280
|
-
},
|
|
281
|
-
};
|
|
282
236
|
config.build = {
|
|
283
237
|
...config.build,
|
|
284
|
-
|
|
238
|
+
rolldownOptions: {
|
|
285
239
|
output: {
|
|
286
240
|
inlineDynamicImports: true,
|
|
287
241
|
},
|
|
288
242
|
},
|
|
289
243
|
};
|
|
290
244
|
|
|
291
|
-
//
|
|
245
|
+
// Rolldown이 인라인하지 못한 잔여 dynamic import()를 제거한다.
|
|
292
246
|
// inlineDynamicImports가 정적 경로를 모두 인라인한 후에도,
|
|
293
247
|
// @vite-ignore나 런타임 계산 경로의 import()가 남을 수 있다.
|
|
294
248
|
// Chrome 61은 import() 구문을 파싱하지 못하므로 no-op 함수로 치환한다.
|
|
@@ -306,6 +260,20 @@ export async function createClientViteConfig(
|
|
|
306
260
|
};
|
|
307
261
|
},
|
|
308
262
|
});
|
|
263
|
+
|
|
264
|
+
// import.meta 구문을 치환한다. Chrome 61은 import.meta를 파싱하지 못한다 (Chrome 64+).
|
|
265
|
+
// Vite/Rolldown이 빌드 시 대부분의 import.meta를 resolve하지만, 잔여분에 대한 안전망이다.
|
|
266
|
+
(config.plugins as PluginOption[]).push({
|
|
267
|
+
name: "sd-legacy-strip-import-meta",
|
|
268
|
+
enforce: "post",
|
|
269
|
+
renderChunk(code) {
|
|
270
|
+
if (!code.includes("import.meta")) return null;
|
|
271
|
+
return {
|
|
272
|
+
code: code.replace(/\bimport\.meta\b/g, "(void 0)"),
|
|
273
|
+
map: null,
|
|
274
|
+
};
|
|
275
|
+
},
|
|
276
|
+
});
|
|
309
277
|
}
|
|
310
278
|
|
|
311
279
|
// build 모드 설정 (프로덕션 빌드 또는 legacyModule dev)
|