@simplysm/sd-cli 12.15.37 → 12.15.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/pkg-builders/client/SdNgBundler.js +9 -5
- package/dist/pkg-builders/client/createSdNgPlugin.js +1 -1
- package/dist/pkg-builders/commons/SdWorkerPathPlugin.d.ts +2 -0
- package/dist/pkg-builders/commons/SdWorkerPathPlugin.js +92 -0
- package/dist/pkg-builders/lib/SdCliIndexFileGenerator.js +3 -1
- package/dist/pkg-builders/server/SdServerBuildRunner.js +1 -1
- package/dist/pkg-builders/server/SdServerBundler.js +6 -2
- package/dist/pkg-builders/server/createSdServerPlugin.js +1 -1
- package/package.json +5 -5
- package/src/pkg-builders/client/SdNgBundler.ts +9 -7
- package/src/pkg-builders/client/createSdNgPlugin.ts +1 -1
- package/src/pkg-builders/commons/SdWorkerPathPlugin.ts +118 -0
- package/src/pkg-builders/lib/SdCliIndexFileGenerator.ts +4 -1
- package/src/pkg-builders/server/SdServerBuildRunner.ts +1 -1
- package/src/pkg-builders/server/SdServerBundler.ts +6 -2
- package/src/pkg-builders/server/createSdServerPlugin.ts +1 -1
|
@@ -21,6 +21,7 @@ import { resolveAssets } from "@angular/build/src/utils/resolve-assets";
|
|
|
21
21
|
import { createSdNgPlugin } from "./createSdNgPlugin";
|
|
22
22
|
import { SdCliPerformanceTimer } from "../../utils/SdCliPerformanceTimer";
|
|
23
23
|
import nodeModule from "module";
|
|
24
|
+
import { SdWorkerPathPlugin } from "../commons/SdWorkerPathPlugin";
|
|
24
25
|
export class SdNgBundler {
|
|
25
26
|
#logger = SdLogger.get(["simplysm", "sd-cli", "SdNgBundler"]);
|
|
26
27
|
#modifiedFileSet = new Set();
|
|
@@ -79,8 +80,8 @@ export class SdNgBundler {
|
|
|
79
80
|
const perf = new SdCliPerformanceTimer("ng bundle");
|
|
80
81
|
this.#debug(`Preparing build contexts...`);
|
|
81
82
|
if (!this.#contexts) {
|
|
82
|
-
this.#contexts =
|
|
83
|
-
|
|
83
|
+
this.#contexts = perf.run("Preparing build contexts", () => [
|
|
84
|
+
this.#getAppContext(),
|
|
84
85
|
...(FsUtils.exists(path.resolve(this._opt.pkgPath, "src/styles.scss"))
|
|
85
86
|
? [this.#getStyleContext()]
|
|
86
87
|
: []),
|
|
@@ -336,8 +337,10 @@ export class SdNgBundler {
|
|
|
336
337
|
async #genServiceWorkerAsync(outputFiles, assetFiles) {
|
|
337
338
|
return await augmentAppWithServiceWorkerEsbuild(this._opt.pkgPath, this.#swConfFilePath, this.#baseHref, "index.html", outputFiles, assetFiles);
|
|
338
339
|
}
|
|
339
|
-
|
|
340
|
-
const workerEntries = (
|
|
340
|
+
#getAppContext() {
|
|
341
|
+
/*const workerEntries = (
|
|
342
|
+
await FsUtils.globAsync(path.resolve(this._opt.pkgPath, "src/workers/!*.ts"))
|
|
343
|
+
).toObject((p) => "workers/" + path.basename(p, path.extname(p)));*/
|
|
341
344
|
return new SdNgBundlerContext(this._opt.pkgPath, !!this._opt.watch, {
|
|
342
345
|
absWorkingDir: this._opt.pkgPath,
|
|
343
346
|
bundle: true,
|
|
@@ -385,7 +388,7 @@ export class SdNgBundler {
|
|
|
385
388
|
"cordova-entry": path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../../lib/cordova-entry.js`),
|
|
386
389
|
}
|
|
387
390
|
: {}),
|
|
388
|
-
...workerEntries,
|
|
391
|
+
// ...workerEntries,
|
|
389
392
|
},
|
|
390
393
|
supported: { "async-await": false, "object-rest-spread": false },
|
|
391
394
|
loader: {
|
|
@@ -440,6 +443,7 @@ export class SdNgBundler {
|
|
|
440
443
|
...(this._conf.builderType === "electron"
|
|
441
444
|
? []
|
|
442
445
|
: [nodeStdLibBrowserPlugin(nodeStdLibBrowser)]),
|
|
446
|
+
SdWorkerPathPlugin(path.resolve(this._opt.pkgPath, "dist")),
|
|
443
447
|
// {
|
|
444
448
|
// name: "log-circular",
|
|
445
449
|
// setup(build) {
|
|
@@ -12,7 +12,7 @@ export function createSdNgPlugin(opt, modifiedFileSet, resultCache) {
|
|
|
12
12
|
logger.debug(`[${path.basename(opt.pkgPath)}]`, ...msg);
|
|
13
13
|
};
|
|
14
14
|
return {
|
|
15
|
-
name: "sd-ng-
|
|
15
|
+
name: "sd-ng-plugin",
|
|
16
16
|
setup: (build) => {
|
|
17
17
|
const tsCompiler = new SdTsCompiler(opt, true);
|
|
18
18
|
let tsCompileResult;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import esbuild from "esbuild";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { FsUtils, HashUtils } from "@simplysm/sd-core-node";
|
|
4
|
+
export function SdWorkerPathPlugin(outdir) {
|
|
5
|
+
return {
|
|
6
|
+
name: "sd-worker-path-plugin",
|
|
7
|
+
setup(build) {
|
|
8
|
+
build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => {
|
|
9
|
+
const originalSource = await FsUtils.readFileAsync(args.path);
|
|
10
|
+
// 정규식: import.meta.resolve('...') 또는 "..." 캡쳐
|
|
11
|
+
// 워커 파일뿐만 아니라 필요한 모든 리소스를 처리할 수 있지만, 일단 worker만 타겟팅
|
|
12
|
+
const regex = /import\.meta\.resolve\(\s*(['"])([^'"]+?\.worker)(?:\.[a-z]+)?\1\s*\)/g;
|
|
13
|
+
if (!regex.test(originalSource)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
// 매칭되는 모든 import.meta.resolve를 찾아서 처리
|
|
17
|
+
const newSource = await replaceAsync(originalSource, regex, async (match, quote, relPath) => {
|
|
18
|
+
// 1. 실제 워커 파일 경로 계산
|
|
19
|
+
const workerSourcePath = path.resolve(path.dirname(args.path), relPath);
|
|
20
|
+
// 확장자가 없을 경우 자동 탐색 (js, ts 등)
|
|
21
|
+
const resolvedWorkerPath = resolveFile(workerSourcePath);
|
|
22
|
+
if (resolvedWorkerPath == null) {
|
|
23
|
+
// 파일이 없으면 건드리지 않음 (런타임 에러로 넘김)
|
|
24
|
+
return match;
|
|
25
|
+
}
|
|
26
|
+
// 2. 출력될 워커 파일명 결정 (캐싱 및 중복 방지를 위해 해시 사용 권장)
|
|
27
|
+
// 예: dist/workers/protocol.worker-X7A8B9.js
|
|
28
|
+
const fileContent = await FsUtils.readFileBufferAsync(resolvedWorkerPath);
|
|
29
|
+
const hash = HashUtils.get(fileContent).substring(0, 8);
|
|
30
|
+
const workerBaseName = path.basename(resolvedWorkerPath, path.extname(resolvedWorkerPath));
|
|
31
|
+
const outputFileName = `${workerBaseName}-${hash}.js`;
|
|
32
|
+
const outputFilePath = path.join(outdir, "workers", outputFileName);
|
|
33
|
+
// 3. 워커 파일 빌드 (존재하지 않거나 변경되었을 때만)
|
|
34
|
+
// (간단하게 하기 위해 매번 빌드 시도하거나, 해시로 체크 가능. 여기선 esbuild 증분 빌드에 맡김)
|
|
35
|
+
// *중요*: 워커도 번들링해야 함.
|
|
36
|
+
await esbuild.build({
|
|
37
|
+
...build.initialOptions,
|
|
38
|
+
plugins: build.initialOptions.plugins?.filter((item) => item.name !== "sd-worker-path-plugin" &&
|
|
39
|
+
item.name !== "sd-ng-plugin" &&
|
|
40
|
+
item.name !== "sd-server-plugin") ?? [],
|
|
41
|
+
outdir: undefined,
|
|
42
|
+
entryPoints: [resolvedWorkerPath],
|
|
43
|
+
bundle: true,
|
|
44
|
+
write: true,
|
|
45
|
+
splitting: false,
|
|
46
|
+
outfile: outputFilePath,
|
|
47
|
+
// platform: build.initialOptions.platform,
|
|
48
|
+
// target: build.initialOptions.target,
|
|
49
|
+
// format: build.initialOptions.format,
|
|
50
|
+
// minify: build.initialOptions.minify,
|
|
51
|
+
// banner: build.initialOptions.banner,
|
|
52
|
+
// sourcemap: build.initialOptions.sourcemap,
|
|
53
|
+
// external: build.initialOptions.external, // 외부 의존성 설정 상속
|
|
54
|
+
// 플러그인 상속 주의: 무한 루프 방지를 위해 이 플러그인은 제외해야 함
|
|
55
|
+
});
|
|
56
|
+
// 4. 경로 치환
|
|
57
|
+
// 번들링된 메인 파일(dist/main.js) 기준으로 workers 폴더는 ./workers/ 임
|
|
58
|
+
return `import.meta.resolve(${quote}./workers/${outputFileName}${quote})`;
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
contents: newSource,
|
|
62
|
+
loader: "ts", // 또는 js, 파일 확장자에 따라 다르게 처리 가능하나 보통 ts로 넘겨도 됨
|
|
63
|
+
// 워커 파일이 변경되면 이 파일도 다시 빌드되어야 함을 알림
|
|
64
|
+
// (정확히 하려면 워커의 의존성까지 다 넣어야 하지만, 최소한 워커 엔트리는 넣음)
|
|
65
|
+
// watchFiles: ... (esbuild가 내부적으로 처리해주길 기대)
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// 정규식 비동기 replace 헬퍼
|
|
72
|
+
async function replaceAsync(str, regex, asyncFn) {
|
|
73
|
+
const promises = [];
|
|
74
|
+
str.replace(regex, (match, ...args) => {
|
|
75
|
+
promises.push(asyncFn(match, ...args));
|
|
76
|
+
return match;
|
|
77
|
+
});
|
|
78
|
+
const data = await Promise.all(promises);
|
|
79
|
+
return str.replace(regex, () => data.shift());
|
|
80
|
+
}
|
|
81
|
+
// 파일 확장자 찾기 헬퍼
|
|
82
|
+
function resolveFile(filePathWithoutExt) {
|
|
83
|
+
if (FsUtils.exists(filePathWithoutExt))
|
|
84
|
+
return filePathWithoutExt;
|
|
85
|
+
const exts = [".ts", ".js", ".mjs", ".cjs"];
|
|
86
|
+
for (const ext of exts) {
|
|
87
|
+
const p = filePathWithoutExt + ext;
|
|
88
|
+
if (FsUtils.exists(p))
|
|
89
|
+
return p;
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
@@ -69,7 +69,9 @@ export class SdCliIndexFileGenerator {
|
|
|
69
69
|
indexFilePath,
|
|
70
70
|
path.resolve(pkgPath, "src/**/*.d.ts"),
|
|
71
71
|
path.resolve(pkgPath, "src/index.ts"),
|
|
72
|
-
|
|
72
|
+
path.resolve(pkgPath, "src/workers/**/*{.ts,.tsx}"),
|
|
73
|
+
// TODO: index에 없는 파일은 watch가 안됨... 처리 필요함.
|
|
74
|
+
// path.resolve(pkgPath, "src/internal/**/*{.ts,.tsx}"),
|
|
73
75
|
].map((item) => item.replace(/\\/g, "/"));
|
|
74
76
|
}
|
|
75
77
|
}
|
|
@@ -6,7 +6,7 @@ import { SdServerBundler } from "./SdServerBundler";
|
|
|
6
6
|
export class SdServerBuildRunner extends SdBuildRunnerBase {
|
|
7
7
|
constructor() {
|
|
8
8
|
super(...arguments);
|
|
9
|
-
this._logger = SdLogger.get(["simplysm", "sd-cli", "
|
|
9
|
+
this._logger = SdLogger.get(["simplysm", "sd-cli", "SdServerBuildRunner"]);
|
|
10
10
|
}
|
|
11
11
|
#serverBundler;
|
|
12
12
|
async _runAsync(modifiedFileSet) {
|
|
@@ -6,6 +6,7 @@ import { createSdServerPlugin } from "./createSdServerPlugin";
|
|
|
6
6
|
import { BuildOutputFileType, } from "@angular/build/src/tools/esbuild/bundler-context";
|
|
7
7
|
import { convertOutputFile } from "@angular/build/src/tools/esbuild/utils";
|
|
8
8
|
import { resolveAssets } from "@angular/build/src/utils/resolve-assets";
|
|
9
|
+
import { SdWorkerPathPlugin } from "../commons/SdWorkerPathPlugin";
|
|
9
10
|
export class SdServerBundler {
|
|
10
11
|
#logger = SdLogger.get(["simplysm", "sd-cli", "SdServerBundler"]);
|
|
11
12
|
#context;
|
|
@@ -19,7 +20,7 @@ export class SdServerBundler {
|
|
|
19
20
|
this.#esbuildOptions = {
|
|
20
21
|
entryPoints: [
|
|
21
22
|
path.resolve(this._opt.pkgPath, "src/main.ts"),
|
|
22
|
-
...FsUtils.glob(path.resolve(this._opt.pkgPath, "src/workers/*.ts")),
|
|
23
|
+
// ...FsUtils.glob(path.resolve(this._opt.pkgPath, "src/workers/*.ts")),
|
|
23
24
|
],
|
|
24
25
|
keepNames: true,
|
|
25
26
|
bundle: true,
|
|
@@ -78,7 +79,10 @@ const require = __createRequire__(import.meta.url);
|
|
|
78
79
|
const __filename = __fileURLToPath__(import.meta.url);
|
|
79
80
|
const __dirname = __path__.dirname(__filename);`.trim(),
|
|
80
81
|
},
|
|
81
|
-
plugins: [
|
|
82
|
+
plugins: [
|
|
83
|
+
createSdServerPlugin(this._opt, this.#modifiedFileSet, this.#resultCache),
|
|
84
|
+
SdWorkerPathPlugin(path.resolve(this._opt.pkgPath, "dist")),
|
|
85
|
+
],
|
|
82
86
|
};
|
|
83
87
|
}
|
|
84
88
|
async bundleAsync(modifiedFileSet) {
|
|
@@ -3,7 +3,7 @@ import { PathUtils } from "@simplysm/sd-core-node";
|
|
|
3
3
|
import { SdTsCompiler } from "../../ts-compiler/SdTsCompiler";
|
|
4
4
|
export function createSdServerPlugin(conf, modifiedFileSet, resultCache) {
|
|
5
5
|
return {
|
|
6
|
-
name: "sd-server-
|
|
6
|
+
name: "sd-server-plugin",
|
|
7
7
|
setup: (build) => {
|
|
8
8
|
const tsCompiler = new SdTsCompiler(conf, true);
|
|
9
9
|
let tsCompileResult;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/sd-cli",
|
|
3
|
-
"version": "12.15.
|
|
3
|
+
"version": "12.15.39",
|
|
4
4
|
"description": "심플리즘 패키지 - CLI",
|
|
5
5
|
"author": "김석래",
|
|
6
6
|
"repository": {
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"@angular/compiler-cli": "^20.3.15",
|
|
18
18
|
"@anthropic-ai/sdk": "^0.71.0",
|
|
19
19
|
"@electron/rebuild": "^4.0.1",
|
|
20
|
-
"@simplysm/sd-core-common": "12.15.
|
|
21
|
-
"@simplysm/sd-core-node": "12.15.
|
|
22
|
-
"@simplysm/sd-service-server": "12.15.
|
|
23
|
-
"@simplysm/sd-storage": "12.15.
|
|
20
|
+
"@simplysm/sd-core-common": "12.15.39",
|
|
21
|
+
"@simplysm/sd-core-node": "12.15.39",
|
|
22
|
+
"@simplysm/sd-service-server": "12.15.39",
|
|
23
|
+
"@simplysm/sd-storage": "12.15.39",
|
|
24
24
|
"browserslist": "^4.28.0",
|
|
25
25
|
"cordova": "^13.0.0",
|
|
26
26
|
"electron": "^39.2.4",
|
|
@@ -40,6 +40,7 @@ import { ISdCliNgPluginResultCache } from "../../types/plugin/ISdCliNgPluginResu
|
|
|
40
40
|
import { INpmConfig } from "../../types/common-config/INpmConfig";
|
|
41
41
|
import { ISdBuildResult } from "../../types/build/ISdBuildResult";
|
|
42
42
|
import { ISdTsCompilerOptions } from "../../types/build/ISdTsCompilerOptions";
|
|
43
|
+
import { SdWorkerPathPlugin } from "../commons/SdWorkerPathPlugin";
|
|
43
44
|
|
|
44
45
|
export class SdNgBundler {
|
|
45
46
|
#logger = SdLogger.get(["simplysm", "sd-cli", "SdNgBundler"]);
|
|
@@ -109,8 +110,8 @@ export class SdNgBundler {
|
|
|
109
110
|
this.#debug(`Preparing build contexts...`);
|
|
110
111
|
|
|
111
112
|
if (!this.#contexts) {
|
|
112
|
-
this.#contexts =
|
|
113
|
-
|
|
113
|
+
this.#contexts = perf.run("Preparing build contexts", () => [
|
|
114
|
+
this.#getAppContext(),
|
|
114
115
|
...(FsUtils.exists(path.resolve(this._opt.pkgPath, "src/styles.scss"))
|
|
115
116
|
? [this.#getStyleContext()]
|
|
116
117
|
: []),
|
|
@@ -440,10 +441,10 @@ export class SdNgBundler {
|
|
|
440
441
|
);
|
|
441
442
|
}
|
|
442
443
|
|
|
443
|
-
|
|
444
|
-
const workerEntries = (
|
|
445
|
-
await FsUtils.globAsync(path.resolve(this._opt.pkgPath, "src/workers
|
|
446
|
-
).toObject((p) => "workers/" + path.basename(p, path.extname(p)))
|
|
444
|
+
#getAppContext() {
|
|
445
|
+
/*const workerEntries = (
|
|
446
|
+
await FsUtils.globAsync(path.resolve(this._opt.pkgPath, "src/workers/!*.ts"))
|
|
447
|
+
).toObject((p) => "workers/" + path.basename(p, path.extname(p)));*/
|
|
447
448
|
|
|
448
449
|
return new SdNgBundlerContext(this._opt.pkgPath, !!this._opt.watch, {
|
|
449
450
|
absWorkingDir: this._opt.pkgPath,
|
|
@@ -500,7 +501,7 @@ export class SdNgBundler {
|
|
|
500
501
|
}
|
|
501
502
|
: {}),
|
|
502
503
|
|
|
503
|
-
...workerEntries,
|
|
504
|
+
// ...workerEntries,
|
|
504
505
|
},
|
|
505
506
|
supported: { "async-await": false, "object-rest-spread": false },
|
|
506
507
|
loader: {
|
|
@@ -557,6 +558,7 @@ export class SdNgBundler {
|
|
|
557
558
|
...(this._conf.builderType === "electron"
|
|
558
559
|
? []
|
|
559
560
|
: [nodeStdLibBrowserPlugin(nodeStdLibBrowser)]),
|
|
561
|
+
SdWorkerPathPlugin(path.resolve(this._opt.pkgPath, "dist")),
|
|
560
562
|
// {
|
|
561
563
|
// name: "log-circular",
|
|
562
564
|
// setup(build) {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import esbuild from "esbuild";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { FsUtils, HashUtils } from "@simplysm/sd-core-node";
|
|
4
|
+
|
|
5
|
+
export function SdWorkerPathPlugin(outdir: string): esbuild.Plugin {
|
|
6
|
+
return {
|
|
7
|
+
name: "sd-worker-path-plugin",
|
|
8
|
+
setup(build) {
|
|
9
|
+
build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => {
|
|
10
|
+
const originalSource = await FsUtils.readFileAsync(args.path);
|
|
11
|
+
|
|
12
|
+
// 정규식: import.meta.resolve('...') 또는 "..." 캡쳐
|
|
13
|
+
// 워커 파일뿐만 아니라 필요한 모든 리소스를 처리할 수 있지만, 일단 worker만 타겟팅
|
|
14
|
+
const regex = /import\.meta\.resolve\(\s*(['"])([^'"]+?\.worker)(?:\.[a-z]+)?\1\s*\)/g;
|
|
15
|
+
|
|
16
|
+
if (!regex.test(originalSource)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 매칭되는 모든 import.meta.resolve를 찾아서 처리
|
|
21
|
+
const newSource = await replaceAsync(
|
|
22
|
+
originalSource,
|
|
23
|
+
regex,
|
|
24
|
+
async (match, quote, relPath) => {
|
|
25
|
+
// 1. 실제 워커 파일 경로 계산
|
|
26
|
+
const workerSourcePath = path.resolve(path.dirname(args.path), relPath);
|
|
27
|
+
|
|
28
|
+
// 확장자가 없을 경우 자동 탐색 (js, ts 등)
|
|
29
|
+
const resolvedWorkerPath = resolveFile(workerSourcePath);
|
|
30
|
+
if (resolvedWorkerPath == null) {
|
|
31
|
+
// 파일이 없으면 건드리지 않음 (런타임 에러로 넘김)
|
|
32
|
+
return match;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. 출력될 워커 파일명 결정 (캐싱 및 중복 방지를 위해 해시 사용 권장)
|
|
36
|
+
// 예: dist/workers/protocol.worker-X7A8B9.js
|
|
37
|
+
const fileContent = await FsUtils.readFileBufferAsync(resolvedWorkerPath);
|
|
38
|
+
const hash = HashUtils.get(fileContent).substring(0, 8);
|
|
39
|
+
const workerBaseName = path.basename(
|
|
40
|
+
resolvedWorkerPath,
|
|
41
|
+
path.extname(resolvedWorkerPath),
|
|
42
|
+
);
|
|
43
|
+
const outputFileName = `${workerBaseName}-${hash}.js`;
|
|
44
|
+
const outputFilePath = path.join(outdir, "workers", outputFileName);
|
|
45
|
+
|
|
46
|
+
// 3. 워커 파일 빌드 (존재하지 않거나 변경되었을 때만)
|
|
47
|
+
// (간단하게 하기 위해 매번 빌드 시도하거나, 해시로 체크 가능. 여기선 esbuild 증분 빌드에 맡김)
|
|
48
|
+
// *중요*: 워커도 번들링해야 함.
|
|
49
|
+
await esbuild.build({
|
|
50
|
+
...build.initialOptions,
|
|
51
|
+
plugins:
|
|
52
|
+
build.initialOptions.plugins?.filter(
|
|
53
|
+
(item) =>
|
|
54
|
+
item.name !== "sd-worker-path-plugin" &&
|
|
55
|
+
item.name !== "sd-ng-plugin" &&
|
|
56
|
+
item.name !== "sd-server-plugin",
|
|
57
|
+
) ?? [],
|
|
58
|
+
outdir: undefined,
|
|
59
|
+
|
|
60
|
+
entryPoints: [resolvedWorkerPath],
|
|
61
|
+
bundle: true,
|
|
62
|
+
write: true,
|
|
63
|
+
splitting: false,
|
|
64
|
+
outfile: outputFilePath,
|
|
65
|
+
// platform: build.initialOptions.platform,
|
|
66
|
+
// target: build.initialOptions.target,
|
|
67
|
+
// format: build.initialOptions.format,
|
|
68
|
+
// minify: build.initialOptions.minify,
|
|
69
|
+
// banner: build.initialOptions.banner,
|
|
70
|
+
// sourcemap: build.initialOptions.sourcemap,
|
|
71
|
+
// external: build.initialOptions.external, // 외부 의존성 설정 상속
|
|
72
|
+
// 플러그인 상속 주의: 무한 루프 방지를 위해 이 플러그인은 제외해야 함
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// 4. 경로 치환
|
|
76
|
+
// 번들링된 메인 파일(dist/main.js) 기준으로 workers 폴더는 ./workers/ 임
|
|
77
|
+
return `import.meta.resolve(${quote}./workers/${outputFileName}${quote})`;
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
contents: newSource,
|
|
83
|
+
loader: "ts", // 또는 js, 파일 확장자에 따라 다르게 처리 가능하나 보통 ts로 넘겨도 됨
|
|
84
|
+
// 워커 파일이 변경되면 이 파일도 다시 빌드되어야 함을 알림
|
|
85
|
+
// (정확히 하려면 워커의 의존성까지 다 넣어야 하지만, 최소한 워커 엔트리는 넣음)
|
|
86
|
+
// watchFiles: ... (esbuild가 내부적으로 처리해주길 기대)
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 정규식 비동기 replace 헬퍼
|
|
94
|
+
async function replaceAsync(
|
|
95
|
+
str: string,
|
|
96
|
+
regex: RegExp,
|
|
97
|
+
asyncFn: (match: string, ...args: any[]) => Promise<string>,
|
|
98
|
+
) {
|
|
99
|
+
const promises: Promise<string>[] = [];
|
|
100
|
+
str.replace(regex, (match, ...args) => {
|
|
101
|
+
promises.push(asyncFn(match, ...args));
|
|
102
|
+
return match;
|
|
103
|
+
});
|
|
104
|
+
const data = await Promise.all(promises);
|
|
105
|
+
return str.replace(regex, () => data.shift()!);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 파일 확장자 찾기 헬퍼
|
|
109
|
+
function resolveFile(filePathWithoutExt: string): string | undefined {
|
|
110
|
+
if (FsUtils.exists(filePathWithoutExt)) return filePathWithoutExt;
|
|
111
|
+
|
|
112
|
+
const exts = [".ts", ".js", ".mjs", ".cjs"];
|
|
113
|
+
for (const ext of exts) {
|
|
114
|
+
const p = filePathWithoutExt + ext;
|
|
115
|
+
if (FsUtils.exists(p)) return p;
|
|
116
|
+
}
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
@@ -83,7 +83,10 @@ export class SdCliIndexFileGenerator {
|
|
|
83
83
|
indexFilePath,
|
|
84
84
|
path.resolve(pkgPath, "src/**/*.d.ts"),
|
|
85
85
|
path.resolve(pkgPath, "src/index.ts"),
|
|
86
|
-
|
|
86
|
+
path.resolve(pkgPath, "src/workers/**/*{.ts,.tsx}"),
|
|
87
|
+
|
|
88
|
+
// TODO: index에 없는 파일은 watch가 안됨... 처리 필요함.
|
|
89
|
+
// path.resolve(pkgPath, "src/internal/**/*{.ts,.tsx}"),
|
|
87
90
|
].map((item) => item.replace(/\\/g, "/"));
|
|
88
91
|
}
|
|
89
92
|
}
|
|
@@ -7,7 +7,7 @@ import { ISdBuildResult } from "../../types/build/ISdBuildResult";
|
|
|
7
7
|
import { INpmConfig } from "../../types/common-config/INpmConfig";
|
|
8
8
|
|
|
9
9
|
export class SdServerBuildRunner extends SdBuildRunnerBase<"server"> {
|
|
10
|
-
protected override _logger = SdLogger.get(["simplysm", "sd-cli", "
|
|
10
|
+
protected override _logger = SdLogger.get(["simplysm", "sd-cli", "SdServerBuildRunner"]);
|
|
11
11
|
|
|
12
12
|
#serverBundler?: SdServerBundler;
|
|
13
13
|
|
|
@@ -12,6 +12,7 @@ import { resolveAssets } from "@angular/build/src/utils/resolve-assets";
|
|
|
12
12
|
import { ISdCliServerPluginResultCache } from "../../types/plugin/ISdCliServerPluginResultCache";
|
|
13
13
|
import { ISdBuildResult } from "../../types/build/ISdBuildResult";
|
|
14
14
|
import { ISdTsCompilerOptions } from "../../types/build/ISdTsCompilerOptions";
|
|
15
|
+
import { SdWorkerPathPlugin } from "../commons/SdWorkerPathPlugin";
|
|
15
16
|
|
|
16
17
|
export class SdServerBundler {
|
|
17
18
|
#logger = SdLogger.get(["simplysm", "sd-cli", "SdServerBundler"]);
|
|
@@ -32,7 +33,7 @@ export class SdServerBundler {
|
|
|
32
33
|
this.#esbuildOptions = {
|
|
33
34
|
entryPoints: [
|
|
34
35
|
path.resolve(this._opt.pkgPath, "src/main.ts"),
|
|
35
|
-
...FsUtils.glob(path.resolve(this._opt.pkgPath, "src/workers/*.ts")),
|
|
36
|
+
// ...FsUtils.glob(path.resolve(this._opt.pkgPath, "src/workers/*.ts")),
|
|
36
37
|
],
|
|
37
38
|
keepNames: true,
|
|
38
39
|
bundle: true,
|
|
@@ -91,7 +92,10 @@ const require = __createRequire__(import.meta.url);
|
|
|
91
92
|
const __filename = __fileURLToPath__(import.meta.url);
|
|
92
93
|
const __dirname = __path__.dirname(__filename);`.trim(),
|
|
93
94
|
},
|
|
94
|
-
plugins: [
|
|
95
|
+
plugins: [
|
|
96
|
+
createSdServerPlugin(this._opt, this.#modifiedFileSet, this.#resultCache),
|
|
97
|
+
SdWorkerPathPlugin(path.resolve(this._opt.pkgPath, "dist")),
|
|
98
|
+
],
|
|
95
99
|
};
|
|
96
100
|
}
|
|
97
101
|
|
|
@@ -12,7 +12,7 @@ export function createSdServerPlugin(
|
|
|
12
12
|
resultCache: ISdCliServerPluginResultCache,
|
|
13
13
|
): esbuild.Plugin {
|
|
14
14
|
return {
|
|
15
|
-
name: "sd-server-
|
|
15
|
+
name: "sd-server-plugin",
|
|
16
16
|
setup: (build: esbuild.PluginBuild) => {
|
|
17
17
|
const tsCompiler = new SdTsCompiler(conf, true);
|
|
18
18
|
|