@simplysm/sd-cli 14.0.44 → 14.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/deps/server-externals/server-production-files.d.ts +10 -5
  2. package/dist/deps/server-externals/server-production-files.d.ts.map +1 -1
  3. package/dist/deps/server-externals/server-production-files.js +27 -29
  4. package/dist/deps/server-externals/server-production-files.js.map +1 -1
  5. package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts +3 -8
  6. package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts.map +1 -1
  7. package/dist/esbuild/esbuild-angular-compiler-plugin.js +57 -83
  8. package/dist/esbuild/esbuild-angular-compiler-plugin.js.map +1 -1
  9. package/dist/esbuild/esbuild-config.d.ts.map +1 -1
  10. package/dist/esbuild/esbuild-config.js +2 -5
  11. package/dist/esbuild/esbuild-config.js.map +1 -1
  12. package/dist/esbuild/esbuild-worker-plugin.d.ts +52 -0
  13. package/dist/esbuild/esbuild-worker-plugin.d.ts.map +1 -0
  14. package/dist/esbuild/esbuild-worker-plugin.js +319 -0
  15. package/dist/esbuild/esbuild-worker-plugin.js.map +1 -0
  16. package/dist/utils/output-path-rewriter.d.ts +5 -2
  17. package/dist/utils/output-path-rewriter.d.ts.map +1 -1
  18. package/dist/utils/output-path-rewriter.js +60 -12
  19. package/dist/utils/output-path-rewriter.js.map +1 -1
  20. package/dist/workers/server-build.worker.d.ts.map +1 -1
  21. package/dist/workers/server-build.worker.js +6 -5
  22. package/dist/workers/server-build.worker.js.map +1 -1
  23. package/dist/workers/server-esbuild-context.d.ts.map +1 -1
  24. package/dist/workers/server-esbuild-context.js +3 -1
  25. package/dist/workers/server-esbuild-context.js.map +1 -1
  26. package/dist/workers/server-watch-manager.js +1 -1
  27. package/dist/workers/server-watch-manager.js.map +1 -1
  28. package/package.json +7 -4
  29. package/src/deps/server-externals/server-production-files.ts +31 -31
  30. package/src/esbuild/esbuild-angular-compiler-plugin.ts +82 -123
  31. package/src/esbuild/esbuild-config.ts +2 -7
  32. package/src/esbuild/esbuild-worker-plugin.ts +419 -0
  33. package/src/utils/output-path-rewriter.ts +65 -17
  34. package/src/workers/server-build.worker.ts +6 -5
  35. package/src/workers/server-esbuild-context.ts +3 -1
  36. package/src/workers/server-watch-manager.ts +1 -1
  37. package/tests/deps/server-externals/mise-toml-parse-intent.verify.md +16 -0
  38. package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +56 -28
  39. package/tests/esbuild/esbuild-worker-plugin-node.verify.md +11 -0
  40. package/tests/esbuild/esbuild-worker-plugin.acc.spec.ts +318 -0
  41. package/tests/esbuild/esbuild-worker-plugin.spec.ts +606 -0
  42. package/tests/esbuild/esbuild-worker-plugin.verify.md +7 -0
  43. package/tests/esbuild/fixtures/worker-plugin/node-worker.js +2 -0
  44. package/tests/esbuild/fixtures/worker-plugin/shared-worker.js +6 -0
  45. package/tests/esbuild/fixtures/worker-plugin/worker-error.js +1 -0
  46. package/tests/esbuild/fixtures/worker-plugin/worker.js +3 -0
  47. package/tests/esbuild/fixtures/worker-plugin/worker2.js +3 -0
  48. package/tests/workers/server-build-worker-plugin.verify.md +9 -0
  49. package/tests/workers/server-build-worker.spec.ts +26 -12
  50. package/tests/workers/server-esbuild-context.spec.ts +13 -5
  51. package/tests/workers/server-watch-manager.acc.spec.ts +2 -2
  52. package/tests/workers/server-watch-manager.spec.ts +2 -2
  53. package/dist/angular/web-worker-transformer.d.ts +0 -9
  54. package/dist/angular/web-worker-transformer.d.ts.map +0 -1
  55. package/dist/angular/web-worker-transformer.js +0 -73
  56. package/dist/angular/web-worker-transformer.js.map +0 -1
  57. package/src/angular/web-worker-transformer.ts +0 -117
  58. package/tests/angular/web-worker-transformer.spec.ts +0 -154
@@ -27,7 +27,7 @@ export async function startServerWatchLoop(config) {
27
27
  // package.json이 변경된 경우에만 외부 모듈 재수집
28
28
  const hasPackageJsonChange = changes.some((c) => c.path.endsWith("package.json"));
29
29
  if (hasPackageJsonChange) {
30
- cachedExternal = collectAllExternals(info.pkgDir, info.externals);
30
+ cachedExternal = collectAllExternals(info.pkgDir, info.externals).bundleExternals;
31
31
  }
32
32
  if (info.output.js) {
33
33
  await esbuildCtx.recreateContext({
@@ -1 +1 @@
1
- {"version":3,"file":"server-watch-manager.js","sourceRoot":"","sources":["../../src/workers/server-watch-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,GAAG,IAAI,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,EACL,aAAa,EACb,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,UAAU,MAAM,0BAA0B,CAAC;AAqBvD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,MAA6B;IACtE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC5C,IAAI,cAAc,GAAG,CAAC,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAElD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAElD,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEhD,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,CAAC,YAAY,EAAE,CAAC;gBAEtB,sBAAsB;gBACtB,MAAM,eAAe,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACnD,MAAM,cAAc,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;gBAE3E,mCAAmC;gBACnC,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9C,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAChC,CAAC;gBACF,IAAI,oBAAoB,EAAE,CAAC;oBACzB,cAAc,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBACpE,CAAC;gBAED,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;oBACnB,MAAM,UAAU,CAAC,eAAe,CAAC;wBAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;wBACnB,WAAW,EAAE,cAAc;wBAC3B,GAAG,EAAE,IAAI,CAAC,GAAG;wBACb,QAAQ,EAAE,cAAc;qBACzB,CAAC,CAAC;gBACL,CAAC;gBAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,8BAA8B;YAC9B,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC;gBAC7B,MAAM,CAAC,YAAY,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,MAAM,eAAe,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,eAAe,IAAI,IAAI,EAAE,CAAC;gBAC5B,MAAM,CAAC,YAAY,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,qBAAqB;YACrB,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAC9B,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CACpF,CAAC;YAEF,MAAM,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC3C,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;oBAAE,OAAO,IAAI,CAAC;gBAC9C,8CAA8C;gBAC9C,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;oBACtD,OAAO,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACxC,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,iBAAiB,EAAE,CAAC;gBACtB,MAAM,CAAC,YAAY,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"server-watch-manager.js","sourceRoot":"","sources":["../../src/workers/server-watch-manager.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/sd-cli",
3
- "version": "14.0.44",
3
+ "version": "14.0.46",
4
4
  "description": "Simplysm package - CLI tool",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -27,6 +27,7 @@
27
27
  "acorn-walk": "^8.3.5",
28
28
  "browserslist-to-esbuild": "^2.1.1",
29
29
  "consola": "^3.4.2",
30
+ "es-module-lexer": "^2.0.0",
30
31
  "esbuild": "^0.28.0",
31
32
  "eslint": "^9.39.4",
32
33
  "glob": "^13.0.6",
@@ -37,13 +38,15 @@
37
38
  "sass": "^1.99.0",
38
39
  "semver": "^7.7.4",
39
40
  "sharp": "^0.34.5",
41
+ "smol-toml": "^1.6.1",
40
42
  "ssh2": "^1.17.0",
41
43
  "typescript": "^5.9.3",
42
44
  "ws": "^8.20.0",
45
+ "yaml": "^2.8.3",
43
46
  "yargs": "^18.0.0",
44
- "@simplysm/core-common": "14.0.44",
45
- "@simplysm/core-node": "14.0.44",
46
- "@simplysm/storage": "14.0.44"
47
+ "@simplysm/core-common": "14.0.46",
48
+ "@simplysm/core-node": "14.0.46",
49
+ "@simplysm/storage": "14.0.46"
47
50
  },
48
51
  "devDependencies": {
49
52
  "@types/semver": "^7.7.1",
@@ -1,6 +1,8 @@
1
1
  import type { ServerBuildInfo } from "../../workers/server-build.worker";
2
2
  import path from "path";
3
3
  import fs from "fs";
4
+ import YAML from "yaml";
5
+ import TOML from "smol-toml";
4
6
  import { cpx } from "@simplysm/core-node";
5
7
  import { consola } from "consola";
6
8
  import { collectAllDependencyExternals } from "../../esbuild/esbuild-config";
@@ -8,21 +10,29 @@ import { collectAllDependencyExternals } from "../../esbuild/esbuild-config";
8
10
  const logger = consola.withTag("sd:cli:server-production-files");
9
11
 
10
12
  /**
11
- * 가지 소스에서 외부 모듈을 수집하고 병합한다.
12
- * collectAllDependencyExternals를 통한 단일 패스 의존성 트리 순회를 사용한다.
13
+ * 외부 모듈을 용도로 분리하여 수집한다.
14
+ * - bundleExternals: esbuild external 번들에서 제외할 패키지
15
+ * - prodDependencies: dist/package.json dependencies — 런타임에 실제 설치되어야 하는 패키지
16
+ *
17
+ * 미설치 optional peer는 번들 제외만 필요할 뿐 런타임에 쓰이지 않으므로 prodDependencies에 포함하지 않는다.
13
18
  */
14
- export function collectAllExternals(pkgDir: string, manualExternals?: string[]): string[] {
19
+ export function collectAllExternals(
20
+ pkgDir: string,
21
+ manualExternals?: string[],
22
+ ): { bundleExternals: string[]; prodDependencies: string[] } {
15
23
  logger.debug("의존성 트리 스캔 중...");
16
24
  const { optionalPeerDeps, nativeModules } = collectAllDependencyExternals(pkgDir);
17
25
 
18
26
  const manual = manualExternals ?? [];
19
- return [...new Set([...optionalPeerDeps, ...nativeModules, ...manual])];
27
+ return {
28
+ bundleExternals: [...new Set([...optionalPeerDeps, ...nativeModules, ...manual])],
29
+ prodDependencies: [...new Set([...nativeModules, ...manual])],
30
+ };
20
31
  }
21
32
 
22
33
  /**
23
34
  * pnpm-lock.yaml의 packages 섹션을 파싱하여 name→version 맵을 생성한다.
24
- * Lockfile v9 형식: `packages:` 섹션의 `'name@version':` 키를 파싱한다.
25
- * YAML 파서 의존성을 피하기 위해 단순 라인 기반 파싱을 사용한다.
35
+ * 형태: "name@version" · "@scope/name@version" · "name@version(peer@ver)..."
26
36
  */
27
37
  export function parseLockfileVersions(cwd: string): Map<string, string> {
28
38
  const lockfilePath = path.join(cwd, "pnpm-lock.yaml");
@@ -31,30 +41,19 @@ export function parseLockfileVersions(cwd: string): Map<string, string> {
31
41
  }
32
42
 
33
43
  const content = fs.readFileSync(lockfilePath, "utf-8");
44
+ const parsed = YAML.parse(content) as { packages?: Record<string, unknown> };
34
45
  const map = new Map<string, string>();
35
46
 
36
- // "packages:" 섹션을 찾고 "'@scope/name@1.2.3':" 또는 "'name@1.2.3':" 형태의 항목을 파싱
37
- const lines = content.split("\n");
38
- let inPackages = false;
39
- for (const line of lines) {
40
- if (line === "packages:") {
41
- inPackages = true;
42
- continue;
43
- }
44
- if (inPackages && line.length > 0 && !line.startsWith(" ") && !line.startsWith("'")) {
45
- break; // 다음 최상위 섹션
46
- }
47
- if (!inPackages) continue;
48
-
49
- // "'@scope/name@version':" 또는 "'name@version':" 매칭
50
- const match = /^\s{2}'(.+)@(\d[^']*)':\s*$/.exec(line);
51
- if (match != null) {
52
- const name = match[1];
53
- const version = match[2];
54
- // 첫 번째 항목 유지 (lockfile은 각 버전을 한 번만 기록)
55
- if (!map.has(name)) {
56
- map.set(name, version);
57
- }
47
+ for (const key of Object.keys(parsed.packages ?? {})) {
48
+ // 번째 @숫자 기준으로 name / version 분리 (scope 패키지의 선두 @ 보존)
49
+ const m = /^(.+?)@(\d.+)$/.exec(key);
50
+ if (m == null) continue;
51
+ const name = m[1];
52
+ // peerDep suffix "(peer@ver)..." 제거
53
+ const parenIdx = m[2].indexOf("(");
54
+ const version = parenIdx === -1 ? m[2] : m[2].substring(0, parenIdx);
55
+ if (!map.has(name)) {
56
+ map.set(name, version);
58
57
  }
59
58
  }
60
59
 
@@ -112,9 +111,10 @@ export function generateProductionFiles(
112
111
  let nodeVersion = "20";
113
112
  if (fs.existsSync(rootMiseTomlPath)) {
114
113
  const miseContent = fs.readFileSync(rootMiseTomlPath, "utf-8");
115
- const match = /node\s*=\s*"([^"]+)"/.exec(miseContent);
116
- if (match != null) {
117
- nodeVersion = match[1];
114
+ // mise.toml은 저장소에서 관리되는 설정 파일이므로, 파싱 실패 시 폴백하지 않고 예외를 전파하여 설정 오류를 즉시 드러낸다.
115
+ const miseConfig = TOML.parse(miseContent) as { tools?: { node?: string } };
116
+ if (miseConfig.tools?.node != null) {
117
+ nodeVersion = miseConfig.tools.node;
118
118
  }
119
119
  }
120
120
  fs.writeFileSync(path.join(distDir, "mise.toml"), `[tools]\nnode = "${nodeVersion}"\n`);
@@ -5,15 +5,15 @@ import ts from "typescript";
5
5
  import type esbuild from "esbuild";
6
6
  import { consola } from "consola";
7
7
  import { JavaScriptTransformer, Cache as AngularCache } from "@angular/build/private";
8
- import type { AngularSourceFileCache } from "../angular/angular-compiler.js";
9
- import type { SerializedDiagnostic } from "../typecheck/typecheck-serialization.js";
10
- import { SdTsCompiler } from "../ts-compiler/SdTsCompiler.js";
11
- import type { ISdTsCompilerResult } from "../ts-compiler/sd-ts-compiler-result.js";
12
- import { FileReferenceTracker } from "./file-reference-tracker.js";
13
- import { LmdbCacheStore } from "./lmdb-cache-store.js";
14
- import { createCachedLoad, type LoadResultCache } from "./load-result-cache.js";
15
- import { collectHmrCandidates, HMR_MODIFIED_FILE_LIMIT } from "../angular/hmr-candidates.js";
16
- import { createWorkerTransformer } from "../angular/web-worker-transformer.js";
8
+ import type { AngularSourceFileCache } from "../angular/angular-compiler";
9
+ import type { SerializedDiagnostic } from "../typecheck/typecheck-serialization";
10
+ import { SdTsCompiler } from "../ts-compiler/SdTsCompiler";
11
+ import type { ISdTsCompilerResult } from "../ts-compiler/sd-ts-compiler-result";
12
+ import { FileReferenceTracker } from "./file-reference-tracker";
13
+ import { LmdbCacheStore } from "./lmdb-cache-store";
14
+ import { createCachedLoad, type LoadResultCache } from "./load-result-cache";
15
+ import { collectHmrCandidates, HMR_MODIFIED_FILE_LIMIT } from "../angular/hmr-candidates";
16
+ import { transformWorkerPatterns } from "./esbuild-worker-plugin";
17
17
 
18
18
  const logger = consola.withTag("sd:cli:angular-plugin");
19
19
 
@@ -48,12 +48,6 @@ export interface AngularCompilerPluginOptions {
48
48
  stylesheetErrors?: string[];
49
49
  }
50
50
 
51
- interface AdditionalResult {
52
- outputFiles?: esbuild.OutputFile[];
53
- metafile?: esbuild.Metafile;
54
- errors?: esbuild.PartialMessage[];
55
- }
56
-
57
51
  //#endregion
58
52
 
59
53
  //#region compilerOptions 변환
@@ -158,46 +152,6 @@ export function convertSerializedDiagnosticToEsbuild(
158
152
 
159
153
  //#endregion
160
154
 
161
- //#region bundleWebWorker
162
-
163
- /**
164
- * Worker 파일을 esbuild.buildSync()로 별도 ESM 번들로 빌드한다.
165
- * TypeScript transformer 내에서 동기적으로 호출되므로 sync API를 사용한다.
166
- */
167
- export function bundleWebWorker(
168
- build: esbuild.PluginBuild,
169
- sourcemap: boolean,
170
- workerFile: string,
171
- ): esbuild.BuildResult {
172
- try {
173
- return build.esbuild.buildSync({
174
- ...build.initialOptions,
175
- platform: "browser",
176
- write: false,
177
- bundle: true,
178
- metafile: true,
179
- format: "esm",
180
- entryNames: "worker-[hash]",
181
- entryPoints: [workerFile],
182
- sourcemap,
183
- supported: undefined,
184
- plugins: undefined,
185
- });
186
- } catch (error) {
187
- if (
188
- error != null &&
189
- typeof error === "object" &&
190
- "errors" in error &&
191
- "warnings" in error
192
- ) {
193
- return error as esbuild.BuildResult;
194
- }
195
- throw error;
196
- }
197
- }
198
-
199
- //#endregion
200
-
201
155
  //#region onLoad 헬퍼
202
156
 
203
157
  const POTENTIAL_METADATA_REGEX =
@@ -288,7 +242,12 @@ export function createAngularCompilerPlugin(
288
242
  // ── 내부 상태 ──
289
243
  const typeScriptFileCache: Map<string, string | Uint8Array> =
290
244
  pluginOptions.typeScriptFileCache ?? new Map();
291
- const additionalResults = new Map<string, AdditionalResult>();
245
+ // containingFile별 Worker 번들 결과. 증분 빌드에서 변경된 파일만 선택적으로
246
+ // 제거하여, 변경되지 않은 Worker metafile/outputFiles가 유지되도록 함.
247
+ const workerResultsByContainingFile = new Map<
248
+ string,
249
+ { outputFiles?: esbuild.OutputFile[]; metafile?: esbuild.Metafile }
250
+ >();
292
251
  const referencedFileTracker = new FileReferenceTracker();
293
252
  let sdTsCompiler: SdTsCompiler | undefined;
294
253
  let lastResult: ISdTsCompilerResult | undefined;
@@ -308,58 +267,6 @@ export function createAngularCompilerPlugin(
308
267
  return sideEffects;
309
268
  }
310
269
 
311
- // ── 서브함수: WebWorker 프로세서 생성 ──
312
- function createWebWorkerProcessor(
313
- errors: esbuild.PartialMessage[],
314
- warnings: esbuild.PartialMessage[],
315
- ): (workerFile: string, containingFile: string) => string {
316
- return (workerFile: string, containingFile: string): string => {
317
- const fullWorkerPath = path.join(path.dirname(containingFile), workerFile);
318
- const workerResult = bundleWebWorker(build, pluginOptions.sourcemap, fullWorkerPath);
319
-
320
- warnings.push(...workerResult.warnings);
321
-
322
- if (workerResult.errors.length > 0) {
323
- errors.push(...workerResult.errors);
324
- // 에러 파일 경로 추적 (rebuild 허용)
325
- referencedFileTracker.add(
326
- containingFile,
327
- workerResult.errors
328
- .map((e) => e.location?.file)
329
- .filter((f): f is string => f != null)
330
- .map((f) => path.join(cwd, f)),
331
- );
332
- additionalResults.set(fullWorkerPath, { errors: workerResult.errors });
333
- return workerFile;
334
- }
335
-
336
- additionalResults.set(fullWorkerPath, {
337
- outputFiles: workerResult.outputFiles,
338
- metafile: workerResult.metafile,
339
- });
340
-
341
- // metafile.inputs → FileReferenceTracker
342
- if (workerResult.metafile != null) {
343
- referencedFileTracker.add(
344
- containingFile,
345
- Object.keys(workerResult.metafile.inputs).map((input) => path.join(cwd, input)),
346
- );
347
- }
348
-
349
- // worker-[HASH].js 파일 찾기
350
- const workerCodeFile = workerResult.outputFiles?.find((file) =>
351
- /^worker-[A-Z0-9]{8}\.[cm]?js$/.test(path.basename(file.path)),
352
- );
353
- if (workerCodeFile == null) {
354
- errors.push({ text: `Web Worker bundled code file not found: ${fullWorkerPath}`, location: null });
355
- return workerFile;
356
- }
357
- const outdir = build.initialOptions.outdir ?? "";
358
- const workerCodePath = path.relative(outdir, workerCodeFile.path);
359
- return workerCodePath.replaceAll("\\", "/");
360
- };
361
- }
362
-
363
270
  // ── onStart ──
364
271
  build.onStart(async () => {
365
272
  const result: esbuild.OnStartResult = {};
@@ -402,9 +309,10 @@ export function createAngularCompilerPlugin(
402
309
  sourceFileCache.modifiedFiles,
403
310
  );
404
311
 
405
- // stale additionalResults 제거
312
+ // 변경된 파일의 Worker 결과만 선택적 제거 (변경되지 않은 파일의
313
+ // Worker metafile은 유지되어 onEnd에서 재병합됨)
406
314
  for (const file of expandedModifiedFiles) {
407
- additionalResults.delete(file);
315
+ workerResultsByContainingFile.delete(file);
408
316
  }
409
317
  }
410
318
 
@@ -424,19 +332,39 @@ export function createAngularCompilerPlugin(
424
332
  });
425
333
  }
426
334
 
427
- // ── processWebWorker + workerTransformer ──
428
- const processWebWorker = createWebWorkerProcessor(errors, warnings);
429
- const workerTransformer = createWorkerTransformer(processWebWorker);
430
-
431
335
  // ── compileAsync ──
432
336
  const compileResult = await sdTsCompiler.compileAsync(
433
337
  isIncremental ? expandedModifiedFiles : undefined,
434
- { additionalTransformers: { before: [workerTransformer] } },
435
338
  );
436
339
 
437
- // ── emitResults → typeScriptFileCache ──
340
+ // ── emitResults → typeScriptFileCache (Worker 패턴 처리 포함) ──
438
341
  for (const { contents, sourceFileName } of compileResult.emitResults ?? []) {
439
- typeScriptFileCache.set(path.normalize(sourceFileName), contents);
342
+ const normalized = path.normalize(sourceFileName);
343
+ const workerResult = transformWorkerPatterns(contents, normalized, build);
344
+ if (workerResult != null) {
345
+ typeScriptFileCache.set(normalized, workerResult.contents);
346
+ errors.push(...workerResult.errors);
347
+ warnings.push(...workerResult.warnings);
348
+ if (workerResult.workerMetafile != null) {
349
+ referencedFileTracker.add(
350
+ normalized,
351
+ Object.keys(workerResult.workerMetafile.inputs).map((input) =>
352
+ path.join(cwd, input),
353
+ ),
354
+ );
355
+ }
356
+ if (
357
+ workerResult.workerMetafile != null ||
358
+ workerResult.workerOutputFiles != null
359
+ ) {
360
+ workerResultsByContainingFile.set(normalized, {
361
+ outputFiles: workerResult.workerOutputFiles,
362
+ metafile: workerResult.workerMetafile,
363
+ });
364
+ }
365
+ } else {
366
+ typeScriptFileCache.set(normalized, contents);
367
+ }
440
368
  }
441
369
 
442
370
  // ── onLoad 플래그 결정 (첫 빌드에서만) ──
@@ -612,6 +540,37 @@ export function createAngularCompilerPlugin(
612
540
  false, // skipLinker
613
541
  sideEffects,
614
542
  );
543
+
544
+ // Worker 패턴 처리 (D2)
545
+ const textContents = new TextDecoder().decode(contents);
546
+ const workerResult = transformWorkerPatterns(textContents, request, build);
547
+ if (workerResult != null) {
548
+ if (workerResult.workerMetafile != null) {
549
+ referencedFileTracker.add(
550
+ request,
551
+ Object.keys(workerResult.workerMetafile.inputs).map((input) =>
552
+ path.join(cwd, input),
553
+ ),
554
+ );
555
+ }
556
+ if (
557
+ workerResult.workerMetafile != null ||
558
+ workerResult.workerOutputFiles != null
559
+ ) {
560
+ workerResultsByContainingFile.set(request, {
561
+ outputFiles: workerResult.workerOutputFiles,
562
+ metafile: workerResult.workerMetafile,
563
+ });
564
+ }
565
+ return {
566
+ contents: workerResult.contents,
567
+ loader: "js" as const,
568
+ resolveDir: path.dirname(request),
569
+ errors: workerResult.errors.length > 0 ? workerResult.errors : undefined,
570
+ warnings: workerResult.warnings.length > 0 ? workerResult.warnings : undefined,
571
+ };
572
+ }
573
+
615
574
  return {
616
575
  contents,
617
576
  loader: "js" as const,
@@ -622,13 +581,13 @@ export function createAngularCompilerPlugin(
622
581
 
623
582
  // ── onEnd ──
624
583
  build.onEnd((result: esbuild.BuildResult) => {
625
- for (const { outputFiles, metafile } of additionalResults.values()) {
626
- if (outputFiles != null && outputFiles.length > 0) {
627
- result.outputFiles?.push(...outputFiles);
584
+ for (const wr of workerResultsByContainingFile.values()) {
585
+ if (wr.outputFiles != null && wr.outputFiles.length > 0) {
586
+ result.outputFiles?.push(...wr.outputFiles);
628
587
  }
629
- if (result.metafile != null && metafile != null) {
630
- Object.assign(result.metafile.inputs, metafile.inputs);
631
- Object.assign(result.metafile.outputs, metafile.outputs);
588
+ if (result.metafile != null && wr.metafile != null) {
589
+ Object.assign(result.metafile.inputs, wr.metafile.inputs);
590
+ Object.assign(result.metafile.outputs, wr.metafile.outputs);
632
591
  }
633
592
  }
634
593
  });
@@ -4,6 +4,7 @@ import fs from "fs/promises";
4
4
  import { createRequire } from "module";
5
5
  import type esbuild from "esbuild";
6
6
  import { consola } from "consola";
7
+ import { addJsExtensionToImports } from "../utils/output-path-rewriter";
7
8
 
8
9
  const logger = consola.withTag("sd:cli:esbuild-config");
9
10
 
@@ -19,13 +20,7 @@ export async function writeChangedOutputFiles(outputFiles: esbuild.OutputFile[])
19
20
  await Promise.all(
20
21
  outputFiles.map(async (file) => {
21
22
  const finalText = file.path.endsWith(".js")
22
- ? file.text.replace(
23
- /((?:from|import)\s*["'])(\.\.?\/[^"']*?)(["'])/g,
24
- (_match, prefix: string, importPath: string, suffix: string) => {
25
- if (/\.(js|mjs|cjs|json|css|wasm|node)$/i.test(importPath)) return _match;
26
- return `${prefix}${importPath}.js${suffix}`;
27
- },
28
- )
23
+ ? addJsExtensionToImports(file.text)
29
24
  : file.text;
30
25
 
31
26
  try {