@simplysm/sd-cli 14.0.37 → 14.0.39
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/dist/angular/angular-build-pipeline.d.ts +1 -1
- package/dist/angular/angular-build-pipeline.js +1 -1
- package/dist/angular/client-transform-stylesheet.d.ts +1 -1
- package/dist/angular/client-transform-stylesheet.js +3 -3
- package/dist/angular/vite-angular-plugin.d.ts +2 -5
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +19 -72
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/commands/publish/storage-publisher.js +1 -0
- package/dist/commands/publish/storage-publisher.js.map +1 -1
- package/dist/dev-server/hmr-service.d.ts +2 -0
- package/dist/dev-server/hmr-service.d.ts.map +1 -1
- package/dist/dev-server/hmr-service.js +24 -10
- package/dist/dev-server/hmr-service.js.map +1 -1
- package/dist/electron/electron.js +4 -4
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +10 -1
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/EsbuildClientEngine.d.ts.map +1 -1
- package/dist/engines/EsbuildClientEngine.js +12 -1
- package/dist/engines/EsbuildClientEngine.js.map +1 -1
- package/dist/engines/engine-factory.d.ts +0 -4
- package/dist/engines/engine-factory.d.ts.map +1 -1
- package/dist/engines/engine-factory.js.map +1 -1
- package/dist/esbuild/esbuild-client-config.d.ts +0 -2
- package/dist/esbuild/esbuild-client-config.d.ts.map +1 -1
- package/dist/esbuild/esbuild-client-config.js +24 -14
- package/dist/esbuild/esbuild-client-config.js.map +1 -1
- package/dist/esbuild/esbuild-postcss-plugin.d.ts +8 -0
- package/dist/esbuild/esbuild-postcss-plugin.d.ts.map +1 -0
- package/dist/esbuild/esbuild-postcss-plugin.js +105 -0
- package/dist/esbuild/esbuild-postcss-plugin.js.map +1 -0
- package/dist/esbuild/esbuild-tsc-plugin.d.ts +23 -0
- package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -0
- package/dist/esbuild/esbuild-tsc-plugin.js +60 -0
- package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -0
- package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevOrchestrator.js +0 -5
- package/dist/orchestrators/DevOrchestrator.js.map +1 -1
- package/dist/orchestrators/TypecheckOrchestrator.js +2 -2
- package/dist/orchestrators/TypecheckOrchestrator.js.map +1 -1
- package/dist/sd-cli.js +2 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/utils/output-utils.d.ts.map +1 -1
- package/dist/utils/output-utils.js +3 -2
- package/dist/utils/output-utils.js.map +1 -1
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +39 -3
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +129 -90
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-esbuild-context.d.ts +27 -0
- package/dist/workers/server-esbuild-context.d.ts.map +1 -1
- package/dist/workers/server-esbuild-context.js +43 -3
- package/dist/workers/server-esbuild-context.js.map +1 -1
- package/package.json +6 -4
- package/src/angular/angular-build-pipeline.ts +2 -2
- package/src/angular/client-transform-stylesheet.ts +4 -4
- package/src/angular/vite-angular-plugin.ts +19 -82
- package/src/commands/publish/storage-publisher.ts +1 -0
- package/src/dev-server/hmr-service.ts +28 -13
- package/src/electron/electron.ts +5 -5
- package/src/engines/BaseEngine.ts +10 -1
- package/src/engines/EsbuildClientEngine.ts +13 -1
- package/src/engines/engine-factory.ts +0 -1
- package/src/esbuild/esbuild-client-config.ts +27 -18
- package/src/esbuild/esbuild-postcss-plugin.ts +117 -0
- package/src/esbuild/esbuild-tsc-plugin.ts +83 -0
- package/src/orchestrators/DevOrchestrator.ts +0 -6
- package/src/orchestrators/TypecheckOrchestrator.ts +2 -2
- package/src/sd-cli.ts +2 -1
- package/src/utils/output-utils.ts +3 -2
- package/src/workers/client.worker.ts +40 -3
- package/src/workers/server-build.worker.ts +136 -97
- package/src/workers/server-esbuild-context.ts +59 -3
- package/tests/angular/_vite-angular-plugin-test-setup.ts +3 -30
- package/tests/angular/client-transform-stylesheet.spec.ts +1 -1
- package/tests/angular/vite-angular-plugin-legacy-watch.spec.ts +14 -31
- package/tests/angular/vite-angular-plugin-vitest.spec.ts +4 -34
- package/tests/angular/vite-angular-plugin.spec.ts +24 -60
- package/tests/commands/typecheck.spec.ts +1 -1
- package/tests/engines/base-engine.spec.ts +25 -0
- package/tests/engines/engine-adapter-isolation.spec.ts +3 -3
- package/tests/engines/esbuild-client-engine.acc.spec.ts +29 -0
- package/tests/engines/esbuild-client-engine.spec.ts +26 -0
- package/tests/esbuild/esbuild-tsc-plugin.acc.spec.ts +349 -0
- package/tests/esbuild/esbuild-tsc-plugin.spec.ts +230 -0
- package/tests/orchestrators/build-orchestrator.spec.ts +1 -1
- package/tests/orchestrators/dev-orchestrator.spec.ts +1 -1
- package/tests/orchestrators/typecheck-orchestrator.spec.ts +1 -1
- package/tests/orchestrators/watch-orchestrator.spec.ts +1 -1
- package/tests/utils/esbuild-client-config-postcss.verify.md +6 -0
- package/tests/utils/esbuild-client-config.acc.spec.ts +30 -15
- package/tests/utils/esbuild-client-config.spec.ts +73 -11
- package/tests/utils/esbuild-postcss-plugin.acc.spec.ts +299 -0
- package/tests/utils/esbuild-postcss-plugin.spec.ts +290 -0
- package/tests/utils/esbuild-scss-plugin.acc.spec.ts +1 -0
- package/tests/utils/hmr-service-dispatcher.acc.spec.ts +70 -0
- package/tests/workers/client-worker-initial-build-error.verify.md +8 -0
- package/tests/workers/server-build-lint.spec.ts +43 -0
- package/tests/workers/server-build-worker-refactoring.verify.md +14 -0
- package/tests/workers/server-build-worker.spec.ts +122 -9
- package/tests/workers/server-esbuild-context-tsc.verify.md +7 -0
- package/tests/workers/server-esbuild-context.acc.spec.ts +156 -2
- package/tests/workers/server-esbuild-context.spec.ts +320 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-esbuild-context.js","sourceRoot":"","sources":["../../src/workers/server-esbuild-context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server-esbuild-context.js","sourceRoot":"","sources":["../../src/workers/server-esbuild-context.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,eAAe,EAAwB,MAAM,+BAA+B,CAAC;AAqBtF,wCAAwC;AACxC,IAAI,OAAyC,CAAC;AAE9C,iCAAiC;AACjC,IAAI,YAA0C,CAAC;AAE/C,gCAAgC;AAChC,IAAI,SAAsC,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA8B;IAChE,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,SAAS,GAAG,eAAe,CAAC;YAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG;YACpB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM;YAC1B,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG;YACpB,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;SACvC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,WAAW,GAAG,0BAA0B,CAAC;QAC7C,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,GAAG,EAAE,IAAI;KACV,CAAC,CAAC;IAEH,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;QAC9B,GAAG,WAAW;QACd,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;QACpD,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO;IAK3B,IAAI,OAAO,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IAEvC,IAAI,MAAM,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC5B,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,MAAM,uBAAuB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC/C,MAAM,SAAS,GAAG,CAAC,GAAG,aAAa,EAAE,GAAG,SAAS,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEpD,OAAO;QACL,OAAO,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC;QAC/B,MAAM,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACpD,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;KACrD,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA8B;IAClE,MAAM,UAAU,GAAG,OAAO,CAAC;IAC3B,OAAO,GAAG,SAAS,CAAC;IACpB,YAAY,GAAG,SAAS,CAAC;IAEzB,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACtB,SAAS,CAAC,mBAAmB,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,MAAM,gBAAgB,GAAG,OAAO,CAAC;IACjC,OAAO,GAAG,SAAS,CAAC;IACpB,YAAY,GAAG,SAAS,CAAC;IACzB,SAAS,GAAG,SAAS,CAAC;IAEtB,IAAI,gBAAgB,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,gBAAgB,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,IAAI,IAAI,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,SAAS,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,SAAS,EAAE,gBAAgB,EAAE,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/sd-cli",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.39",
|
|
4
4
|
"description": "Simplysm package - CLI tool",
|
|
5
5
|
"author": "simplysm",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
],
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"acorn": "^8.14.1",
|
|
23
|
+
"acorn-walk": "^8.3.4",
|
|
22
24
|
"@angular/build": "^21.2.7",
|
|
23
25
|
"@angular/compiler-cli": "^21.2.8",
|
|
24
26
|
"@fastify/http-proxy": "^11.4.3",
|
|
@@ -38,9 +40,9 @@
|
|
|
38
40
|
"typescript": "^5.9.3",
|
|
39
41
|
"ws": "^8.20.0",
|
|
40
42
|
"yargs": "^18.0.0",
|
|
41
|
-
"@simplysm/core-common": "14.0.
|
|
42
|
-
"@simplysm/core-node": "14.0.
|
|
43
|
-
"@simplysm/storage": "14.0.
|
|
43
|
+
"@simplysm/core-common": "14.0.39",
|
|
44
|
+
"@simplysm/core-node": "14.0.39",
|
|
45
|
+
"@simplysm/storage": "14.0.39"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
48
|
"@types/semver": "^7.7.1",
|
|
@@ -65,7 +65,7 @@ export interface AngularBuildPipelineOptions {
|
|
|
65
65
|
compilerOptionsTransformer?: (opts: ts.CompilerOptions) => ts.CompilerOptions;
|
|
66
66
|
|
|
67
67
|
// client 모드 전용
|
|
68
|
-
|
|
68
|
+
postcssPlugins?: unknown[];
|
|
69
69
|
scssCacheDir?: string;
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -210,7 +210,7 @@ export class AngularBuildPipeline {
|
|
|
210
210
|
this._options.mode === "client"
|
|
211
211
|
? createClientTransformStylesheet({
|
|
212
212
|
loadPaths,
|
|
213
|
-
|
|
213
|
+
postcssPlugins: this._options.postcssPlugins,
|
|
214
214
|
scssErrors: this._scssErrors,
|
|
215
215
|
scssDependencies: this._scssDependencies,
|
|
216
216
|
cacheDir: this._options.scssCacheDir,
|
|
@@ -6,7 +6,7 @@ import { compileScssFileAsync, compileScssStringAsync } from "./scss-compiler.js
|
|
|
6
6
|
|
|
7
7
|
export interface ClientTransformStylesheetOptions {
|
|
8
8
|
loadPaths: string[];
|
|
9
|
-
|
|
9
|
+
postcssPlugins?: unknown[];
|
|
10
10
|
scssErrors: string[];
|
|
11
11
|
scssDependencies: Map<string, Set<string>>;
|
|
12
12
|
/** SCSS 캐시 디렉토리 (미지정 시 캐시 비활성화) */
|
|
@@ -57,11 +57,11 @@ async function readFileHash(filePath: string): Promise<string | undefined> {
|
|
|
57
57
|
export function createClientTransformStylesheet(
|
|
58
58
|
options: ClientTransformStylesheetOptions,
|
|
59
59
|
): (data: string, containingFile: string, stylesheetFile?: string) => Promise<string | null> {
|
|
60
|
-
const { loadPaths,
|
|
60
|
+
const { loadPaths, postcssPlugins, scssErrors, scssDependencies, cacheDir } = options;
|
|
61
61
|
|
|
62
62
|
const postCssProcessor =
|
|
63
|
-
|
|
64
|
-
? postcss(
|
|
63
|
+
postcssPlugins != null && postcssPlugins.length > 0
|
|
64
|
+
? postcss(postcssPlugins as postcss.AcceptedPlugin[])
|
|
65
65
|
: undefined;
|
|
66
66
|
|
|
67
67
|
return async (
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
|
-
import { JavaScriptTransformer } from "@angular/build/private";
|
|
3
|
-
import os from "os";
|
|
4
2
|
import path from "path";
|
|
5
3
|
import ts from "typescript";
|
|
6
4
|
import { consola } from "consola";
|
|
@@ -11,8 +9,6 @@ import {
|
|
|
11
9
|
AngularBuildPipeline,
|
|
12
10
|
type PipelineDiagnosticResult,
|
|
13
11
|
} from "./angular-build-pipeline.js";
|
|
14
|
-
import { loadSdConfig } from "../utils/sd-config.js";
|
|
15
|
-
import type { SdPackageConfig } from "../sd-config.types.js";
|
|
16
12
|
|
|
17
13
|
const logger = consola.withTag("sd:cli:angular");
|
|
18
14
|
|
|
@@ -25,39 +21,18 @@ export interface SdAngularPluginOptions {
|
|
|
25
21
|
/**
|
|
26
22
|
* Angular AOT 컴파일을 수행하는 Vite 플러그인 (Vitest 전용).
|
|
27
23
|
*
|
|
28
|
-
* AngularBuildPipeline
|
|
29
|
-
*
|
|
30
|
-
* - buildStart: Pipeline 초기화 + 컴파일 + emit
|
|
31
|
-
* - transform: .ts 파일에 대해 컴파일된 JS 반환 + JavaScriptTransformer 적용
|
|
32
|
-
* - buildEnd: 리소스 정리
|
|
24
|
+
* AngularBuildPipeline으로 패키지의 .ts 파일을 AOT 컴파일하고,
|
|
25
|
+
* transform 훅에서 컴파일된 JS를 반환한다.
|
|
33
26
|
*/
|
|
34
27
|
export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
|
|
35
28
|
let pipeline: AngularBuildPipeline | undefined;
|
|
36
29
|
let sourceFileCache: AngularSourceFileCache | undefined;
|
|
37
|
-
let jsTransformer: JavaScriptTransformer | undefined;
|
|
38
30
|
|
|
39
31
|
/** Vitest watch 모드에서 변경된 파일 경로를 수집한다. buildStart 재호출 시 캐시 무효화에 사용. */
|
|
40
32
|
const pendingWatchChanges = new Set<string>();
|
|
41
33
|
|
|
42
|
-
// config() 훅에서 초기화
|
|
43
|
-
let isDev = false;
|
|
44
|
-
let enableSourcemap = true;
|
|
45
|
-
let pkgConfig: SdPackageConfig | undefined;
|
|
46
34
|
let resolvedPkgDir: string | undefined;
|
|
47
35
|
|
|
48
|
-
function createJsTransformer(): JavaScriptTransformer {
|
|
49
|
-
const maxThreads = Math.max(1, Math.floor((os.cpus().length * 2) / 3));
|
|
50
|
-
return new JavaScriptTransformer(
|
|
51
|
-
{
|
|
52
|
-
sourcemap: enableSourcemap,
|
|
53
|
-
thirdPartySourcemaps: enableSourcemap,
|
|
54
|
-
advancedOptimizations: !isDev,
|
|
55
|
-
jit: false,
|
|
56
|
-
},
|
|
57
|
-
maxThreads,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
36
|
return {
|
|
62
37
|
name: "sd-angular",
|
|
63
38
|
enforce: "pre",
|
|
@@ -66,24 +41,8 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
|
|
|
66
41
|
pendingWatchChanges.add(pathx.posix(id));
|
|
67
42
|
},
|
|
68
43
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
isDev = env.mode === "development";
|
|
72
|
-
|
|
73
|
-
// sd.config.ts 로딩
|
|
74
|
-
const sdConfig = await loadSdConfig({ cwd, dev: isDev, opt: [] });
|
|
75
|
-
const rawPkgConfig = sdConfig.packages[options.pkg];
|
|
76
|
-
if (rawPkgConfig == null) {
|
|
77
|
-
throw new Error(`sd.config.ts에 패키지 "${options.pkg}"가 정의되어 있지 않습니다.`);
|
|
78
|
-
}
|
|
79
|
-
pkgConfig = rawPkgConfig;
|
|
80
|
-
|
|
81
|
-
// 패키지 디렉토리 resolve
|
|
82
|
-
resolvedPkgDir = path.resolve(cwd, "packages", options.pkg);
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
configResolved(resolved: { build: { sourcemap: unknown } }) {
|
|
86
|
-
enableSourcemap = resolved.build.sourcemap !== false || isDev;
|
|
44
|
+
config() {
|
|
45
|
+
resolvedPkgDir = path.resolve(process.cwd(), "packages", options.pkg);
|
|
87
46
|
},
|
|
88
47
|
|
|
89
48
|
async buildStart() {
|
|
@@ -110,12 +69,6 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
|
|
|
110
69
|
pendingWatchChanges.clear();
|
|
111
70
|
}
|
|
112
71
|
|
|
113
|
-
// postCssPlugins from sd.config.ts (client 패키지에만 존재)
|
|
114
|
-
const browserSupport = pkgConfig?.target === "client"
|
|
115
|
-
? (pkgConfig).browserSupport
|
|
116
|
-
: undefined;
|
|
117
|
-
const postCssPlugins = browserSupport?.postCss?.plugins;
|
|
118
|
-
|
|
119
72
|
// Pipeline 생성 (최초) 또는 재사용
|
|
120
73
|
pipeline ??= new AngularBuildPipeline({
|
|
121
74
|
mode: "client",
|
|
@@ -132,16 +85,14 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
|
|
|
132
85
|
noEmit: false,
|
|
133
86
|
declaration: false,
|
|
134
87
|
declarationMap: false,
|
|
88
|
+
removeComments: false,
|
|
89
|
+
sourceMap: false,
|
|
90
|
+
inlineSourceMap: true,
|
|
135
91
|
rootDir: process.cwd(),
|
|
136
|
-
...(isDev ? { removeComments: false } : {}),
|
|
137
92
|
}),
|
|
138
|
-
postCssPlugins,
|
|
139
93
|
scssCacheDir: path.join(resolvedPkgDir, ".cache", "scss"),
|
|
140
94
|
});
|
|
141
95
|
|
|
142
|
-
// JavaScriptTransformer 생성
|
|
143
|
-
jsTransformer ??= createJsTransformer();
|
|
144
|
-
|
|
145
96
|
// Pipeline 초기화 — 이미 초기화됐고 변경 파일이 없으면 건너뜀
|
|
146
97
|
if (pipeline.getEmittedFiles().size > 0 && !hadPendingChanges) {
|
|
147
98
|
logger.debug("Pipeline 이미 초기화됨, 변경 없음 — buildStart 건너뜀");
|
|
@@ -158,46 +109,32 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
|
|
|
158
109
|
}
|
|
159
110
|
},
|
|
160
111
|
|
|
161
|
-
|
|
162
|
-
if (jsTransformer == null) return;
|
|
163
|
-
|
|
112
|
+
transform(_code, id) {
|
|
164
113
|
// query param 제거
|
|
165
114
|
const cleanId = id.split("?")[0];
|
|
166
|
-
let code = _code;
|
|
167
|
-
|
|
168
|
-
// Phase 1: TS 컴파일 — .ts 파일은 Pipeline이 emit한 JS로 교체
|
|
169
|
-
if (cleanId.endsWith(".ts")) {
|
|
170
|
-
const normalizedId = pathx.posix(cleanId);
|
|
171
|
-
const emittedContent = pipeline?.getEmittedFile(normalizedId);
|
|
172
|
-
if (emittedContent == null) return;
|
|
173
|
-
code = emittedContent;
|
|
174
|
-
} else if (!cleanId.endsWith(".mjs") && !cleanId.endsWith(".js")) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
115
|
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
116
|
+
// Pipeline이 emit한 .ts 파일만 처리
|
|
117
|
+
if (!cleanId.endsWith(".ts")) return;
|
|
118
|
+
|
|
119
|
+
const normalizedId = pathx.posix(cleanId);
|
|
120
|
+
const emittedContent = pipeline?.getEmittedFile(normalizedId);
|
|
121
|
+
if (emittedContent == null) return;
|
|
181
122
|
|
|
182
|
-
// 인라인 소스맵 분리 (
|
|
183
|
-
const inlineMapMatch =
|
|
123
|
+
// 인라인 소스맵 분리 (Vite 호환)
|
|
124
|
+
const inlineMapMatch = emittedContent.match(
|
|
184
125
|
/\/\/# sourceMappingURL=data:application\/json;(?:charset=utf-8;)?base64,(.+)$/m,
|
|
185
126
|
);
|
|
186
127
|
if (inlineMapMatch != null) {
|
|
187
128
|
const mapJson = atob(inlineMapMatch[1]);
|
|
188
129
|
return {
|
|
189
|
-
code:
|
|
130
|
+
code: emittedContent.slice(0, inlineMapMatch.index),
|
|
190
131
|
map: JSON.parse(mapJson),
|
|
191
132
|
};
|
|
192
133
|
}
|
|
193
|
-
return { code:
|
|
134
|
+
return { code: emittedContent, map: null };
|
|
194
135
|
},
|
|
195
136
|
|
|
196
|
-
|
|
197
|
-
if (jsTransformer != null) {
|
|
198
|
-
await jsTransformer.close();
|
|
199
|
-
jsTransformer = undefined;
|
|
200
|
-
}
|
|
137
|
+
buildEnd() {
|
|
201
138
|
pipeline = undefined;
|
|
202
139
|
},
|
|
203
140
|
};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type http from "node:http";
|
|
2
2
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import crypto from "crypto";
|
|
3
6
|
import type esbuild from "esbuild";
|
|
4
7
|
import { WebSocketServer, type WebSocket } from "ws";
|
|
5
8
|
|
|
@@ -10,6 +13,8 @@ export interface HmrServiceOptions {
|
|
|
10
13
|
basePath: string;
|
|
11
14
|
/** templateUpdates Map (createCompilerPlugin과 공유) */
|
|
12
15
|
templateUpdates: Map<string, string>;
|
|
16
|
+
/** 빌드 출력 디렉토리 경로. 설정 시 파일 내용 hash로 변경 감지 (bytes 대신) */
|
|
17
|
+
outDir?: string;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
export interface HmrService {
|
|
@@ -24,7 +29,7 @@ export interface HmrService {
|
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export function createHmrService(options: HmrServiceOptions): HmrService {
|
|
27
|
-
const { httpServer, basePath, templateUpdates } = options;
|
|
32
|
+
const { httpServer, basePath, templateUpdates, outDir } = options;
|
|
28
33
|
const clients = new Set<WebSocket>();
|
|
29
34
|
|
|
30
35
|
const wss = new WebSocketServer({ server: httpServer });
|
|
@@ -36,7 +41,7 @@ export function createHmrService(options: HmrServiceOptions): HmrService {
|
|
|
36
41
|
});
|
|
37
42
|
});
|
|
38
43
|
|
|
39
|
-
let prevOutputs: Map<string,
|
|
44
|
+
let prevOutputs: Map<string, string> | undefined;
|
|
40
45
|
let debounceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
41
46
|
let pendingMetafile: esbuild.Metafile | undefined;
|
|
42
47
|
|
|
@@ -49,12 +54,22 @@ export function createHmrService(options: HmrServiceOptions): HmrService {
|
|
|
49
54
|
}, 100);
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
function collectOutputs(metafile: esbuild.Metafile): Map<string,
|
|
53
|
-
const outputs = new Map<string,
|
|
57
|
+
function collectOutputs(metafile: esbuild.Metafile): Map<string, string> {
|
|
58
|
+
const outputs = new Map<string, string>();
|
|
54
59
|
for (const [outputPath, output] of Object.entries(metafile.outputs)) {
|
|
55
60
|
const normalizedPath = outputPath.replace(/\\/g, "/");
|
|
56
61
|
if (normalizedPath.endsWith(".js") || normalizedPath.endsWith(".css")) {
|
|
57
|
-
|
|
62
|
+
let fingerprint = String(output.bytes);
|
|
63
|
+
if (outDir != null) {
|
|
64
|
+
try {
|
|
65
|
+
const filePath = path.resolve(outDir, normalizedPath);
|
|
66
|
+
const content = fs.readFileSync(filePath);
|
|
67
|
+
fingerprint = crypto.createHash("md5").update(content).digest("hex");
|
|
68
|
+
} catch {
|
|
69
|
+
// 파일 읽기 실패 시 bytes 폴백
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
outputs.set(normalizedPath, fingerprint);
|
|
58
73
|
}
|
|
59
74
|
}
|
|
60
75
|
return outputs;
|
|
@@ -91,12 +106,12 @@ export function createHmrService(options: HmrServiceOptions): HmrService {
|
|
|
91
106
|
let cssChanged = false;
|
|
92
107
|
const changedCssFiles: string[] = [];
|
|
93
108
|
|
|
94
|
-
for (const [
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
97
|
-
if (
|
|
109
|
+
for (const [outputPath, fingerprint] of currentOutputs) {
|
|
110
|
+
const prevFingerprint = prevOutputs.get(outputPath);
|
|
111
|
+
if (prevFingerprint !== fingerprint) {
|
|
112
|
+
if (outputPath.endsWith(".css")) {
|
|
98
113
|
cssChanged = true;
|
|
99
|
-
changedCssFiles.push(
|
|
114
|
+
changedCssFiles.push(outputPath.split("/").pop() ?? outputPath);
|
|
100
115
|
} else {
|
|
101
116
|
jsChanged = true;
|
|
102
117
|
}
|
|
@@ -104,9 +119,9 @@ export function createHmrService(options: HmrServiceOptions): HmrService {
|
|
|
104
119
|
}
|
|
105
120
|
|
|
106
121
|
// 삭제된 파일 체크
|
|
107
|
-
for (const [
|
|
108
|
-
if (!currentOutputs.has(
|
|
109
|
-
if (
|
|
122
|
+
for (const [outputPath] of prevOutputs) {
|
|
123
|
+
if (!currentOutputs.has(outputPath)) {
|
|
124
|
+
if (outputPath.endsWith(".css")) {
|
|
110
125
|
cssChanged = true;
|
|
111
126
|
} else {
|
|
112
127
|
jsChanged = true;
|
package/src/electron/electron.ts
CHANGED
|
@@ -97,7 +97,7 @@ export class Electron {
|
|
|
97
97
|
|
|
98
98
|
let currentElectron: cpx.SpawnProcess | null = null;
|
|
99
99
|
let isRestarting = false;
|
|
100
|
-
let resolveTermination: (() => void) | null = null;
|
|
100
|
+
let resolveTermination: (() => void | Promise<void>) | null = null;
|
|
101
101
|
|
|
102
102
|
const spawnElectron = () => {
|
|
103
103
|
Electron._logger.debug("Electron 프로세스 시작");
|
|
@@ -112,7 +112,7 @@ export class Electron {
|
|
|
112
112
|
currentElectron = null;
|
|
113
113
|
if (!isRestarting && resolveTermination != null) {
|
|
114
114
|
Electron._logger.info("Electron이 종료되었습니다.");
|
|
115
|
-
resolveTermination();
|
|
115
|
+
void resolveTermination();
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
118
|
};
|
|
@@ -160,13 +160,13 @@ export class Electron {
|
|
|
160
160
|
await new Promise<void>((resolve) => {
|
|
161
161
|
let disposed = false;
|
|
162
162
|
|
|
163
|
-
const cleanup = () => {
|
|
163
|
+
const cleanup = async () => {
|
|
164
164
|
if (disposed) return;
|
|
165
165
|
disposed = true;
|
|
166
166
|
Electron._logger.debug("cleanup 시작");
|
|
167
167
|
process.removeListener("SIGINT", signalHandler);
|
|
168
168
|
process.removeListener("SIGTERM", signalHandler);
|
|
169
|
-
|
|
169
|
+
await ctx.dispose();
|
|
170
170
|
resolve();
|
|
171
171
|
};
|
|
172
172
|
|
|
@@ -175,7 +175,7 @@ export class Electron {
|
|
|
175
175
|
const signalHandler = () => {
|
|
176
176
|
Electron._logger.debug("시그널 수신, Electron 종료 중");
|
|
177
177
|
if (currentElectron != null) currentElectron.kill();
|
|
178
|
-
cleanup();
|
|
178
|
+
void cleanup();
|
|
179
179
|
};
|
|
180
180
|
|
|
181
181
|
process.once("SIGINT", signalHandler);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Worker, type WorkerProxy } from "@simplysm/core-node";
|
|
2
|
+
import { err as errNs } from "@simplysm/core-common";
|
|
2
3
|
import { consola } from "consola";
|
|
3
4
|
import type { BuildResult, ResultCollector } from "../runtime/ResultCollector";
|
|
4
5
|
import { stopEngineWorker } from "../runtime/engine-stop";
|
|
@@ -182,7 +183,15 @@ export abstract class BaseEngine<
|
|
|
182
183
|
}
|
|
183
184
|
});
|
|
184
185
|
|
|
185
|
-
this._callStartWatch(output).catch(() => {
|
|
186
|
+
this._callStartWatch(output).catch((err: unknown) => {
|
|
187
|
+
logger.error(`[${this._pkg.name}] startWatch 실패:`, errNs.message(err));
|
|
188
|
+
this._resultCollector?.add({
|
|
189
|
+
name: this._pkg.name,
|
|
190
|
+
target: this._getTarget(),
|
|
191
|
+
type: "build",
|
|
192
|
+
status: "error",
|
|
193
|
+
message: errNs.message(err),
|
|
194
|
+
});
|
|
186
195
|
resolveInitialBuild();
|
|
187
196
|
});
|
|
188
197
|
|
|
@@ -121,7 +121,7 @@ export class EsbuildClientEngine implements BuildEngine {
|
|
|
121
121
|
? this._pkg.config.server
|
|
122
122
|
: undefined;
|
|
123
123
|
|
|
124
|
-
await this._worker!.startWatch({
|
|
124
|
+
const result = await this._worker!.startWatch({
|
|
125
125
|
name: this._pkg.name,
|
|
126
126
|
cwd: this._cwd,
|
|
127
127
|
pkgDir: this._pkg.dir,
|
|
@@ -131,6 +131,18 @@ export class EsbuildClientEngine implements BuildEngine {
|
|
|
131
131
|
pwa: this._pkg.config.pwa,
|
|
132
132
|
browserSupport: this._pkg.config.browserSupport,
|
|
133
133
|
});
|
|
134
|
+
|
|
135
|
+
if (!result.success) {
|
|
136
|
+
const errorDetail = result.errors?.join("; ") ?? "unknown error";
|
|
137
|
+
logger.error(`[${this._pkg.name}] 초기 빌드 실패: ${errorDetail}`);
|
|
138
|
+
this._resultCollector?.add({
|
|
139
|
+
name: this._pkg.name,
|
|
140
|
+
target: "client",
|
|
141
|
+
type: "build",
|
|
142
|
+
status: "error",
|
|
143
|
+
message: errorDetail,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
134
146
|
}
|
|
135
147
|
|
|
136
148
|
/**
|
|
@@ -24,7 +24,6 @@ export function createBuildEngine(
|
|
|
24
24
|
options: {
|
|
25
25
|
cwd: string;
|
|
26
26
|
replaceDeps?: Record<string, string>;
|
|
27
|
-
resolvedReplaceDeps?: Array<{ packageName: string; sourcePath: string }>;
|
|
28
27
|
resultCollector?: ResultCollector;
|
|
29
28
|
rebuildManager?: RebuildManager;
|
|
30
29
|
/** 클라이언트 빌드 출력 경로 (EsbuildClientEngine에만 적용) */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fs from "fs";
|
|
3
|
+
import { createRequire } from "module";
|
|
3
4
|
import esbuild from "esbuild";
|
|
4
5
|
import browserslistToEsbuild from "browserslist-to-esbuild";
|
|
6
|
+
import type { AcceptedPlugin } from "postcss";
|
|
5
7
|
import {
|
|
6
8
|
createCompilerPlugin,
|
|
7
9
|
SourceFileCache,
|
|
@@ -9,6 +11,7 @@ import {
|
|
|
9
11
|
type BundleStylesheetOptions,
|
|
10
12
|
} from "@angular/build/private";
|
|
11
13
|
import { createScssPlugin } from "./esbuild-scss-plugin";
|
|
14
|
+
import { createPostcssPlugin } from "./esbuild-postcss-plugin";
|
|
12
15
|
|
|
13
16
|
export interface CreateClientEsbuildOptions {
|
|
14
17
|
/** 패키지 디렉토리 경로 */
|
|
@@ -29,8 +32,6 @@ export interface CreateClientEsbuildOptions {
|
|
|
29
32
|
onEnd?: (result: esbuild.BuildResult) => void | Promise<void>;
|
|
30
33
|
/** PostCSS 플러그인 ([name, options] 튜플 배열) */
|
|
31
34
|
postcssPlugins?: [string, (object | string)?][];
|
|
32
|
-
/** PostCSS 설정 기준 경로 */
|
|
33
|
-
postcssConfigPath?: string;
|
|
34
35
|
/** 빌드 출력 경로 (기본: pkgDir/dist) */
|
|
35
36
|
outdir?: string;
|
|
36
37
|
/** browserslist 쿼리. 미설정 시 "es2022" 기본값 */
|
|
@@ -65,16 +66,16 @@ export async function createClientEsbuildContext(
|
|
|
65
66
|
const sourceFileCache = new SourceFileCache(cachePath);
|
|
66
67
|
|
|
67
68
|
// CompilerPluginOptions
|
|
68
|
-
const pluginOptions: CompilerPluginOptions
|
|
69
|
+
const pluginOptions: CompilerPluginOptions = {
|
|
69
70
|
tsconfig: options.tsconfig ?? path.join(options.pkgDir, "tsconfig.json"),
|
|
70
71
|
sourcemap: isDev,
|
|
71
72
|
advancedOptimizations: !isDev,
|
|
72
73
|
thirdPartySourcemaps: isDev,
|
|
73
|
-
incremental:
|
|
74
|
+
incremental: isDev,
|
|
74
75
|
sourceFileCache,
|
|
75
76
|
loadResultCache: sourceFileCache.loadResultCache,
|
|
76
77
|
templateUpdates: options.templateUpdates,
|
|
77
|
-
|
|
78
|
+
includeTestMetadata: isDev,
|
|
78
79
|
};
|
|
79
80
|
|
|
80
81
|
// BundleStylesheetOptions
|
|
@@ -91,22 +92,27 @@ export async function createClientEsbuildContext(
|
|
|
91
92
|
path: cachePath,
|
|
92
93
|
basePath: cachePath,
|
|
93
94
|
},
|
|
94
|
-
postcssConfiguration:
|
|
95
|
-
options.postcssPlugins != null
|
|
96
|
-
? {
|
|
97
|
-
config: { plugins: options.postcssPlugins },
|
|
98
|
-
configPath: options.postcssConfigPath ?? options.pkgDir,
|
|
99
|
-
}
|
|
100
|
-
: undefined,
|
|
95
|
+
postcssConfiguration: undefined,
|
|
101
96
|
inlineStyleLanguage: "scss",
|
|
102
97
|
};
|
|
103
98
|
|
|
104
99
|
const angularPlugin = createCompilerPlugin(pluginOptions, styleOptions);
|
|
105
100
|
|
|
101
|
+
// PostCSS 플러그인 로딩 (튜플 → 인스턴스)
|
|
102
|
+
let loadedPostcssPlugins: AcceptedPlugin[] | undefined;
|
|
103
|
+
if (options.postcssPlugins != null && options.postcssPlugins.length > 0) {
|
|
104
|
+
const req = createRequire(path.join(options.pkgDir, "package.json"));
|
|
105
|
+
loadedPostcssPlugins = options.postcssPlugins.map(([name, pluginOpts]) => {
|
|
106
|
+
const pluginFn = req(name);
|
|
107
|
+
const fn = pluginFn.default ?? pluginFn;
|
|
108
|
+
return pluginOpts != null ? fn(pluginOpts) : fn;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
106
112
|
// SCSS side-effect import 처리 플러그인
|
|
107
113
|
const scssPlugin = createScssPlugin({
|
|
108
114
|
loadPaths: [
|
|
109
|
-
path.join(options.pkgDir, "
|
|
115
|
+
path.join(options.pkgDir, "node_modules"),
|
|
110
116
|
path.join(options.cwd, "node_modules"),
|
|
111
117
|
],
|
|
112
118
|
});
|
|
@@ -126,10 +132,10 @@ export async function createClientEsbuildContext(
|
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
// 커스텀 env
|
|
135
|
+
// esbuild define은 정적 패턴만 치환하므로, import.meta.env 객체 자체를 주입해야
|
|
136
|
+
// env() 함수의 동적 접근(import.meta.env?.[key])이 동작한다.
|
|
129
137
|
if (options.env != null) {
|
|
130
|
-
|
|
131
|
-
define[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
132
|
-
}
|
|
138
|
+
define["import.meta.env"] = JSON.stringify(options.env);
|
|
133
139
|
}
|
|
134
140
|
|
|
135
141
|
// import.meta.hot 폴리필 banner (Angular HMR 런타임용)
|
|
@@ -156,7 +162,7 @@ export async function createClientEsbuildContext(
|
|
|
156
162
|
],
|
|
157
163
|
target: esbuildTarget,
|
|
158
164
|
entryNames: isDev ? "[name]" : "[name]-[hash]",
|
|
159
|
-
chunkNames:
|
|
165
|
+
chunkNames: "[name]-[hash]",
|
|
160
166
|
assetNames: isDev ? "[name]" : "[name]-[hash]",
|
|
161
167
|
bundle: true,
|
|
162
168
|
splitting: options.legacyModule !== true,
|
|
@@ -166,7 +172,7 @@ export async function createClientEsbuildContext(
|
|
|
166
172
|
metafile: true,
|
|
167
173
|
write: true,
|
|
168
174
|
sourcemap: isDev ? "linked" : false,
|
|
169
|
-
logLevel: "silent",
|
|
175
|
+
logLevel: isDev ? "warning" : "silent",
|
|
170
176
|
tsconfig: options.tsconfig ?? path.join(options.pkgDir, "tsconfig.json"),
|
|
171
177
|
define,
|
|
172
178
|
banner: hmrBanner != null ? { js: hmrBanner } : undefined,
|
|
@@ -187,6 +193,9 @@ export async function createClientEsbuildContext(
|
|
|
187
193
|
angularPlugin,
|
|
188
194
|
scssPlugin,
|
|
189
195
|
...(options.plugins ?? []),
|
|
196
|
+
...(loadedPostcssPlugins != null
|
|
197
|
+
? [createPostcssPlugin({ plugins: loadedPostcssPlugins })]
|
|
198
|
+
: []),
|
|
190
199
|
...(options.legacyModule === true
|
|
191
200
|
? [
|
|
192
201
|
{
|