@simplysm/sd-cli 14.0.6 → 14.0.8
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/capacitor/capacitor.d.ts +1 -1
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +3 -4
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/check.js +2 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +12 -13
- package/dist/commands/publish.js.map +1 -1
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +24 -19
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +1 -0
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +9 -3
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/sd-cli.js +6 -6
- package/dist/sd-cli.js.map +1 -1
- package/dist/utils/esbuild-config.d.ts +7 -2
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/esbuild-config.js +15 -12
- package/dist/utils/esbuild-config.js.map +1 -1
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +1 -2
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/vitest-plugin.d.ts.map +1 -1
- package/dist/vitest-plugin.js +2 -0
- package/dist/vitest-plugin.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +2 -3
- package/dist/workers/server-build.worker.js.map +1 -1
- package/package.json +4 -6
- package/src/capacitor/capacitor.ts +3 -4
- package/src/commands/check.ts +2 -2
- package/src/commands/publish.ts +12 -13
- package/src/electron/electron.ts +28 -21
- package/src/engines/BaseEngine.ts +1 -0
- package/src/orchestrators/DevWatchOrchestrator.ts +10 -3
- package/src/sd-cli.ts +9 -6
- package/src/utils/esbuild-config.ts +16 -12
- package/src/utils/vite-config.ts +1 -2
- package/src/vitest-plugin.ts +5 -0
- package/src/workers/server-build.worker.ts +2 -3
- package/tests/capacitor/capacitor-build.spec.ts +9 -7
- package/tests/capacitor/capacitor-icon.spec.ts +9 -7
- package/tests/capacitor/capacitor-init.spec.ts +8 -6
- package/tests/capacitor/capacitor-run.spec.ts +13 -11
- package/tests/capacitor/capacitor-workspace.spec.ts +8 -6
- package/tests/commands/check.spec.ts +16 -28
- package/tests/commands/publish.spec.ts +4 -4
- package/tests/electron/electron.spec.ts +69 -58
- package/tests/orchestrators/build-orchestrator.spec.ts +4 -9
- package/tests/orchestrators/dev-watch-orchestrator.spec.ts +3 -5
- package/tests/utils/esbuild-config.spec.ts +38 -8
- package/tests/utils/vite-config.spec.ts +13 -0
- package/tests/workers/server-build-worker.spec.ts +6 -3
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import { execa } from "execa";
|
|
5
4
|
import { symlink } from "fs/promises";
|
|
6
5
|
import { createRequire } from "module";
|
|
7
|
-
import { fsx } from "@simplysm/core-node";
|
|
6
|
+
import { cpx, fsx } from "@simplysm/core-node";
|
|
8
7
|
import { env } from "@simplysm/core-common";
|
|
9
8
|
import { consola } from "consola";
|
|
10
9
|
import type { SdCapacitorConfig } from "../sd-config.types.js";
|
|
@@ -154,11 +153,11 @@ export class Capacitor {
|
|
|
154
153
|
}
|
|
155
154
|
|
|
156
155
|
/**
|
|
157
|
-
* 명령어 실행
|
|
156
|
+
* 명령어 실행
|
|
158
157
|
*/
|
|
159
158
|
private async _exec(command: string, args: string[], cwd: string): Promise<string> {
|
|
160
159
|
Capacitor._logger.debug(`명령어 실행: ${command} ${args.join(" ")}`);
|
|
161
|
-
const { stdout } = await
|
|
160
|
+
const { stdout } = await cpx.exec(command, args, { cwd });
|
|
162
161
|
Capacitor._logger.debug(`실행 결과: ${stdout}`);
|
|
163
162
|
return stdout;
|
|
164
163
|
}
|
package/src/commands/check.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cpx } from "@simplysm/core-node";
|
|
2
2
|
import { err as errNs } from "@simplysm/core-common";
|
|
3
3
|
import { executeTypecheck, type TypecheckResult } from "./typecheck";
|
|
4
4
|
import { executeLint, type LintResult } from "./lint";
|
|
@@ -34,7 +34,7 @@ async function spawnVitest(targets: string[]): Promise<CheckResult> {
|
|
|
34
34
|
const args = ["vitest", ...targets, "--run"];
|
|
35
35
|
logger.debug("vitest 실행", { args });
|
|
36
36
|
logger.start("테스트 실행 중...");
|
|
37
|
-
const result = await
|
|
37
|
+
const result = await cpx.exec("pnpm", args, { cwd: process.cwd(), reject: false });
|
|
38
38
|
const output = result.stdout + result.stderr;
|
|
39
39
|
const code = result.exitCode;
|
|
40
40
|
|
package/src/commands/publish.ts
CHANGED
|
@@ -2,13 +2,12 @@ import path from "path";
|
|
|
2
2
|
import semver from "semver";
|
|
3
3
|
import { consola } from "consola";
|
|
4
4
|
import { StorageFactory } from "@simplysm/storage";
|
|
5
|
-
import { fsx } from "@simplysm/core-node";
|
|
5
|
+
import { cpx, fsx } from "@simplysm/core-node";
|
|
6
6
|
import { env, json } from "@simplysm/core-common";
|
|
7
7
|
import "@simplysm/core-common";
|
|
8
8
|
import type { SdConfig, SdPublishConfig } from "../sd-config.types";
|
|
9
9
|
import { loadSdConfig } from "../utils/sd-config";
|
|
10
10
|
import { validateTargets } from "../utils/package-utils";
|
|
11
|
-
import { execa } from "execa";
|
|
12
11
|
import { runBuild } from "./build";
|
|
13
12
|
import { parseWorkspaceGlobs } from "../utils/replace-deps";
|
|
14
13
|
import os from "os";
|
|
@@ -353,7 +352,7 @@ async function publishPackage(
|
|
|
353
352
|
logger.debug(`[${pkgName}] pnpm ${args.join(" ")}`);
|
|
354
353
|
}
|
|
355
354
|
|
|
356
|
-
await
|
|
355
|
+
await cpx.exec("pnpm", args, { cwd: pkgPath });
|
|
357
356
|
} else if (publishConfig.type === "local-directory") {
|
|
358
357
|
// 로컬 디렉토리에 복사
|
|
359
358
|
const targetPath = replaceEnvVariables(publishConfig.path, version, projectPath);
|
|
@@ -560,7 +559,7 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
560
559
|
if (publishPackages.some((p) => p.config.type === "npm")) {
|
|
561
560
|
logger.debug("npm 인증 검증 중...");
|
|
562
561
|
try {
|
|
563
|
-
const { stdout: whoami } = await
|
|
562
|
+
const { stdout: whoami } = await cpx.exec("npm", ["whoami"]);
|
|
564
563
|
if (whoami.trim() === "") {
|
|
565
564
|
throw new Error("npm 로그인 정보를 찾을 수 없습니다.");
|
|
566
565
|
}
|
|
@@ -590,13 +589,13 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
590
589
|
if (!noBuild && hasGit) {
|
|
591
590
|
logger.debug("git 커밋 상태 확인 중...");
|
|
592
591
|
try {
|
|
593
|
-
const { stdout: diff } = await
|
|
594
|
-
const { stdout: stagedDiff } = await
|
|
592
|
+
const { stdout: diff } = await cpx.exec("git", ["diff", "--name-only"]);
|
|
593
|
+
const { stdout: stagedDiff } = await cpx.exec("git", ["diff", "--cached", "--name-only"]);
|
|
595
594
|
|
|
596
595
|
if (diff.trim() !== "" || stagedDiff.trim() !== "") {
|
|
597
596
|
logger.info("커밋되지 않은 변경사항 감지. claude로 자동 커밋 시도 중...");
|
|
598
597
|
try {
|
|
599
|
-
await
|
|
598
|
+
await cpx.exec("claude", [
|
|
600
599
|
"-p",
|
|
601
600
|
"/sd-commit all",
|
|
602
601
|
"--dangerously-skip-permissions",
|
|
@@ -684,11 +683,11 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
684
683
|
} else {
|
|
685
684
|
logger.debug("Git commit/tag/push...");
|
|
686
685
|
try {
|
|
687
|
-
await
|
|
688
|
-
await
|
|
689
|
-
await
|
|
690
|
-
await
|
|
691
|
-
await
|
|
686
|
+
await cpx.exec("git", ["add", ..._changedFiles]);
|
|
687
|
+
await cpx.exec("git", ["commit", "-m", `v${version}`]);
|
|
688
|
+
await cpx.exec("git", ["tag", "-a", `v${version}`, "-m", `v${version}`]);
|
|
689
|
+
await cpx.exec("git", ["push"]);
|
|
690
|
+
await cpx.exec("git", ["push", "--tags"]);
|
|
692
691
|
logger.debug("Git 작업 완료");
|
|
693
692
|
} catch (err) {
|
|
694
693
|
logger.error(
|
|
@@ -807,7 +806,7 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
807
806
|
logger.info(`[DRY-RUN] 실행 예정: ${cmd} ${args.join(" ")}`);
|
|
808
807
|
} else {
|
|
809
808
|
logger.debug(`실행 중: ${cmd} ${args.join(" ")}`);
|
|
810
|
-
await
|
|
809
|
+
await cpx.exec(cmd, args, { cwd });
|
|
811
810
|
}
|
|
812
811
|
} catch (err) {
|
|
813
812
|
// postPublish 실패 시 경고만 출력 (배포 롤백 불가)
|
package/src/electron/electron.ts
CHANGED
|
@@ -2,10 +2,10 @@ import path from "path";
|
|
|
2
2
|
import os from "os";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import module from "module";
|
|
5
|
-
import { fsx } from "@simplysm/core-node";
|
|
5
|
+
import { cpx, fsx } from "@simplysm/core-node";
|
|
6
6
|
import { consola } from "consola";
|
|
7
|
-
import { execa } from "execa";
|
|
8
7
|
import type { SdElectronConfig } from "../sd-config.types.js";
|
|
8
|
+
import { createEnvBanner } from "../utils/esbuild-config.js";
|
|
9
9
|
|
|
10
10
|
interface NpmConfig {
|
|
11
11
|
name: string;
|
|
@@ -56,7 +56,7 @@ export class Electron {
|
|
|
56
56
|
env?: Record<string, string>,
|
|
57
57
|
): Promise<string> {
|
|
58
58
|
Electron._logger.debug(`실행: ${cmd} ${args.join(" ")}`);
|
|
59
|
-
const { stdout: result } = await
|
|
59
|
+
const { stdout: result } = await cpx.exec(cmd, args, { cwd, env });
|
|
60
60
|
Electron._logger.debug(`결과: ${result}`);
|
|
61
61
|
return result;
|
|
62
62
|
}
|
|
@@ -80,12 +80,6 @@ export class Electron {
|
|
|
80
80
|
|
|
81
81
|
await this.initialize();
|
|
82
82
|
|
|
83
|
-
const runEnv: Record<string, string> = {
|
|
84
|
-
NODE_ENV: "development",
|
|
85
|
-
ELECTRON_DEV_URL: url,
|
|
86
|
-
...this._config.env,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
83
|
const esbuild = await import("esbuild");
|
|
90
84
|
const entryPoint = path.resolve(this._pkgPath, "src/electron-main.ts");
|
|
91
85
|
|
|
@@ -97,14 +91,13 @@ export class Electron {
|
|
|
97
91
|
const reinstallDeps = this._config.reinstallDependencies ?? [];
|
|
98
92
|
await fsx.mkdir(srcPath);
|
|
99
93
|
|
|
100
|
-
let currentElectron:
|
|
94
|
+
let currentElectron: cpx.ExecProcess | null = null;
|
|
101
95
|
let isRestarting = false;
|
|
102
96
|
let resolveTermination: (() => void) | null = null;
|
|
103
97
|
|
|
104
98
|
const spawnElectron = () => {
|
|
105
|
-
currentElectron =
|
|
99
|
+
currentElectron = cpx.exec(this._localBin("electron"), ["."], {
|
|
106
100
|
cwd: srcPath,
|
|
107
|
-
env: { ...process.env, ...runEnv },
|
|
108
101
|
stdio: "inherit",
|
|
109
102
|
reject: false,
|
|
110
103
|
});
|
|
@@ -118,6 +111,8 @@ export class Electron {
|
|
|
118
111
|
});
|
|
119
112
|
};
|
|
120
113
|
|
|
114
|
+
const envBanner = createEnvBanner({ ELECTRON_DEV_URL: url, ...this._config.env });
|
|
115
|
+
|
|
121
116
|
const ctx = await esbuild.context({
|
|
122
117
|
entryPoints: [entryPoint],
|
|
123
118
|
outfile: path.resolve(srcPath, "electron-main.js"),
|
|
@@ -125,7 +120,8 @@ export class Electron {
|
|
|
125
120
|
target: "node20",
|
|
126
121
|
format: "cjs",
|
|
127
122
|
bundle: true,
|
|
128
|
-
external: ["electron", ...builtinModules, ...reinstallDeps],
|
|
123
|
+
external: ["electron", ...builtinModules, ...reinstallDeps, ...this._exclude],
|
|
124
|
+
banner: { js: envBanner },
|
|
129
125
|
plugins: [
|
|
130
126
|
{
|
|
131
127
|
name: "electron-restart",
|
|
@@ -158,15 +154,22 @@ export class Electron {
|
|
|
158
154
|
await ctx.watch();
|
|
159
155
|
|
|
160
156
|
await new Promise<void>((resolve) => {
|
|
161
|
-
|
|
157
|
+
let disposed = false;
|
|
158
|
+
|
|
159
|
+
const cleanup = () => {
|
|
160
|
+
if (disposed) return;
|
|
161
|
+
disposed = true;
|
|
162
|
+
process.removeListener("SIGINT", signalHandler);
|
|
163
|
+
process.removeListener("SIGTERM", signalHandler);
|
|
162
164
|
void ctx.dispose();
|
|
163
165
|
resolve();
|
|
164
166
|
};
|
|
165
167
|
|
|
168
|
+
resolveTermination = cleanup;
|
|
169
|
+
|
|
166
170
|
const signalHandler = () => {
|
|
167
171
|
if (currentElectron != null) currentElectron.kill();
|
|
168
|
-
|
|
169
|
-
resolve();
|
|
172
|
+
cleanup();
|
|
170
173
|
};
|
|
171
174
|
|
|
172
175
|
process.once("SIGINT", signalHandler);
|
|
@@ -241,6 +244,8 @@ export class Electron {
|
|
|
241
244
|
|
|
242
245
|
await fsx.mkdir(outDir);
|
|
243
246
|
|
|
247
|
+
const envBanner = createEnvBanner(this._config.env);
|
|
248
|
+
|
|
244
249
|
await esbuild.build({
|
|
245
250
|
entryPoints: [entryPoint],
|
|
246
251
|
outfile: path.resolve(outDir, "electron-main.js"),
|
|
@@ -248,7 +253,8 @@ export class Electron {
|
|
|
248
253
|
target: "node20",
|
|
249
254
|
format: "cjs",
|
|
250
255
|
bundle: true,
|
|
251
|
-
external: ["electron", ...builtinModules, ...reinstallDeps],
|
|
256
|
+
external: ["electron", ...builtinModules, ...reinstallDeps, ...this._exclude],
|
|
257
|
+
banner: { js: envBanner },
|
|
252
258
|
});
|
|
253
259
|
}
|
|
254
260
|
|
|
@@ -295,7 +301,7 @@ export class Electron {
|
|
|
295
301
|
|
|
296
302
|
const builderConfig: Record<string, unknown> = {
|
|
297
303
|
appId: this._config.appId,
|
|
298
|
-
productName: this._npmConfig.description,
|
|
304
|
+
productName: this._npmConfig.description ?? this._npmConfig.name,
|
|
299
305
|
asar: false,
|
|
300
306
|
win: {
|
|
301
307
|
target: this._config.portable === true ? "portable" : "nsis",
|
|
@@ -329,12 +335,13 @@ export class Electron {
|
|
|
329
335
|
const electronOutPath = path.resolve(outPath, "electron");
|
|
330
336
|
await fsx.mkdir(electronOutPath);
|
|
331
337
|
|
|
332
|
-
const
|
|
338
|
+
const rawName = this._npmConfig.description ?? this._npmConfig.name;
|
|
339
|
+
const safeName = rawName.replace(/[<>:"/\\|?*]/g, "");
|
|
333
340
|
const version = this._npmConfig.version;
|
|
334
341
|
const isPortable = this._config.portable === true;
|
|
335
342
|
|
|
336
343
|
// exe 파일 동적 탐색 — Setup 또는 portable exe를 우선 선택
|
|
337
|
-
const allExeFiles = await fsx.glob("*.exe"
|
|
344
|
+
const allExeFiles = await fsx.glob(path.resolve(distPath, "*.exe"));
|
|
338
345
|
if (allExeFiles.length === 0) {
|
|
339
346
|
Electron._logger.warn(`빌드 산출물(.exe)을 찾을 수 없습니다: ${distPath}`);
|
|
340
347
|
return;
|
|
@@ -343,7 +350,7 @@ export class Electron {
|
|
|
343
350
|
const sourcePath =
|
|
344
351
|
allExeFiles.find((f) => f.toLowerCase().includes(keyword.toLowerCase())) ?? allExeFiles[0];
|
|
345
352
|
|
|
346
|
-
const latestFileName = `${
|
|
353
|
+
const latestFileName = `${safeName}${isPortable ? "-portable" : ""}-latest.exe`;
|
|
347
354
|
await fsx.copy(sourcePath, path.resolve(electronOutPath, latestFileName));
|
|
348
355
|
|
|
349
356
|
const updatesPath = path.resolve(electronOutPath, "updates");
|
|
@@ -289,9 +289,16 @@ export class DevWatchOrchestrator {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
// Start all engines
|
|
292
|
-
this.
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
const total = this._libraryEngines.length;
|
|
293
|
+
this._logger.start(`초기 빌드 실행 중... (${total}개 패키지)`);
|
|
294
|
+
let completed = 0;
|
|
295
|
+
|
|
296
|
+
const watchPromises = this._libraryEngines.map(async (engine, i) => {
|
|
297
|
+
const pkgName = this._libraryPackages[i].name;
|
|
298
|
+
await engine.startWatch({ js: true, dts: true, lint: true });
|
|
299
|
+
completed++;
|
|
300
|
+
this._logger.info(` [${completed}/${total}] ${pkgName} 완료`);
|
|
301
|
+
});
|
|
295
302
|
|
|
296
303
|
await Promise.allSettled(watchPromises);
|
|
297
304
|
this._logger.success("초기 빌드 실행 완료");
|
package/src/sd-cli.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* .js execution (production): run replaceDeps then spawn sd-cli-entry in new process
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { cpx } from "@simplysm/core-node";
|
|
11
11
|
import os from "os";
|
|
12
12
|
import path from "path";
|
|
13
13
|
import { fileURLToPath } from "url";
|
|
@@ -31,7 +31,7 @@ if (isDev) {
|
|
|
31
31
|
const { loadSdConfig } = await import("./utils/sd-config.js");
|
|
32
32
|
const { setupReplaceDeps } = await import("./utils/replace-deps.js");
|
|
33
33
|
const sdConfig = await loadSdConfig({ cwd: process.cwd(), dev: false, options: [] });
|
|
34
|
-
if (sdConfig.replaceDeps != null) {
|
|
34
|
+
if (process.argv[2] !== "replace-deps" && sdConfig.replaceDeps != null) {
|
|
35
35
|
await setupReplaceDeps(process.cwd(), sdConfig.replaceDeps);
|
|
36
36
|
}
|
|
37
37
|
} catch {
|
|
@@ -40,7 +40,7 @@ if (isDev) {
|
|
|
40
40
|
|
|
41
41
|
// Phase 2: Run actual CLI in new process (reset module cache)
|
|
42
42
|
const cliEntryFilePath = path.join(__dirname, "sd-cli-entry.js");
|
|
43
|
-
const subprocess =
|
|
43
|
+
const subprocess = cpx.exec(
|
|
44
44
|
"node",
|
|
45
45
|
[
|
|
46
46
|
"--max-old-space-size=8192",
|
|
@@ -52,7 +52,7 @@ if (isDev) {
|
|
|
52
52
|
);
|
|
53
53
|
if (subprocess.pid != null) configureAffinityAndPriority(subprocess.pid);
|
|
54
54
|
const result = await subprocess;
|
|
55
|
-
process.exitCode = result.exitCode
|
|
55
|
+
process.exitCode = result.exitCode;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
@@ -94,8 +94,11 @@ function configureAffinityAndPriority(pid: number): void {
|
|
|
94
94
|
command = `taskset -p ${mask} ${pid} && renice +10 -p ${pid}`;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
cpx.exec(command, [], { shell: true }).catch((err: unknown) => {
|
|
98
98
|
// eslint-disable-next-line no-console
|
|
99
|
-
console.warn(
|
|
99
|
+
console.warn(
|
|
100
|
+
"Failed to configure CPU affinity/priority:",
|
|
101
|
+
err instanceof Error ? err.message : String(err),
|
|
102
|
+
);
|
|
100
103
|
});
|
|
101
104
|
}
|
|
@@ -57,22 +57,29 @@ export interface ServerEsbuildOptions {
|
|
|
57
57
|
dev?: boolean;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Generate a JS banner snippet that merges env vars into process.env at runtime.
|
|
62
|
+
* Uses ??= so that runtime ENV (e.g. `DEV=false node server.js`) takes precedence
|
|
63
|
+
* over build-time defaults.
|
|
64
|
+
*/
|
|
65
|
+
export function createEnvBanner(env?: Record<string, string>): string {
|
|
66
|
+
if (env == null || Object.keys(env).length === 0) return "";
|
|
67
|
+
return `for(const[__k,__v]of Object.entries(${JSON.stringify(env)})){process.env[__k]??=__v;}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
/**
|
|
61
71
|
* Create esbuild config for Server build
|
|
62
72
|
*
|
|
63
73
|
* Used for server package builds
|
|
64
74
|
* - bundle: true (single bundle with all dependencies)
|
|
65
75
|
* - minify: true (minify for code protection)
|
|
66
|
-
* - banner: createRequire shim for CJS package require() support
|
|
67
|
-
* - Replace env with define option (process.env.KEY format)
|
|
76
|
+
* - banner: createRequire shim for CJS package require() support + env injection
|
|
68
77
|
*/
|
|
69
78
|
export function createServerEsbuildOptions(options: ServerEsbuildOptions): esbuild.BuildOptions {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
}
|
|
79
|
+
const envBanner = createEnvBanner(options.env);
|
|
80
|
+
const bannerJs =
|
|
81
|
+
"import { createRequire } from 'module'; const require = createRequire(import.meta.url);" +
|
|
82
|
+
envBanner;
|
|
76
83
|
|
|
77
84
|
return {
|
|
78
85
|
entryPoints: options.entryPoints,
|
|
@@ -82,11 +89,8 @@ export function createServerEsbuildOptions(options: ServerEsbuildOptions): esbui
|
|
|
82
89
|
platform: "node",
|
|
83
90
|
target: "node20",
|
|
84
91
|
bundle: true,
|
|
85
|
-
banner: {
|
|
86
|
-
js: "import { createRequire } from 'module'; const require = createRequire(import.meta.url);",
|
|
87
|
-
},
|
|
92
|
+
banner: { js: bannerJs },
|
|
88
93
|
external: options.external,
|
|
89
|
-
define,
|
|
90
94
|
tsconfig: path.join(options.pkgDir, "tsconfig.json"),
|
|
91
95
|
logLevel: "silent",
|
|
92
96
|
};
|
package/src/utils/vite-config.ts
CHANGED
|
@@ -82,10 +82,9 @@ export async function createClientViteConfig(
|
|
|
82
82
|
: [options.browserslist]
|
|
83
83
|
: undefined;
|
|
84
84
|
|
|
85
|
-
// define: 환경변수 주입
|
|
85
|
+
// define: 환경변수 주입 (import.meta.env.KEY → Vite가 bare import.meta.env 객체를 자동 구성)
|
|
86
86
|
const define: Record<string, string> = {};
|
|
87
87
|
if (options.env != null) {
|
|
88
|
-
define["process.env"] = JSON.stringify(options.env);
|
|
89
88
|
for (const [key, value] of Object.entries(options.env)) {
|
|
90
89
|
define[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
91
90
|
}
|
package/src/vitest-plugin.ts
CHANGED
|
@@ -31,8 +31,13 @@ export function angularVitestPlugin(options: AngularVitestPluginOptions): Plugin
|
|
|
31
31
|
(f) => f.includes("/src/") || f.includes(".fixture."),
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
+
const angularCompilerOptions = configFile.config?.angularCompilerOptions as
|
|
35
|
+
| Record<string, unknown>
|
|
36
|
+
| undefined;
|
|
37
|
+
|
|
34
38
|
const compilerOptions: ts.CompilerOptions = {
|
|
35
39
|
...parsedConfig.options,
|
|
40
|
+
...(angularCompilerOptions as ts.CompilerOptions | undefined),
|
|
36
41
|
noEmit: false,
|
|
37
42
|
declaration: false,
|
|
38
43
|
declarationMap: false,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import { execaSync } from "execa";
|
|
4
3
|
import esbuild from "esbuild";
|
|
5
|
-
import { createWorker, FsWatcher, pathx } from "@simplysm/core-node";
|
|
4
|
+
import { cpx, createWorker, FsWatcher, pathx } from "@simplysm/core-node";
|
|
6
5
|
import { err as errNs } from "@simplysm/core-common";
|
|
7
6
|
import { consola } from "consola";
|
|
8
7
|
import type { BuildOutput } from "../engines/types";
|
|
@@ -231,7 +230,7 @@ function generateProductionFiles(
|
|
|
231
230
|
distPkgJson["dependencies"] = resolveLockedVersions(info.cwd, externals);
|
|
232
231
|
}
|
|
233
232
|
if (info.packageManager === "volta") {
|
|
234
|
-
const nodeVersion =
|
|
233
|
+
const nodeVersion = cpx.execSync("node", ["-v"]).stdout.trim();
|
|
235
234
|
distPkgJson["volta"] = { node: nodeVersion };
|
|
236
235
|
}
|
|
237
236
|
fs.writeFileSync(path.join(distDir, "package.json"), JSON.stringify(distPkgJson, undefined, 2));
|
|
@@ -25,6 +25,10 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
25
25
|
glob: mockFsxGlob,
|
|
26
26
|
copy: mockFsxCopy,
|
|
27
27
|
},
|
|
28
|
+
cpx: {
|
|
29
|
+
exec: mockCpxExec,
|
|
30
|
+
execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
31
|
+
},
|
|
28
32
|
}));
|
|
29
33
|
|
|
30
34
|
// env mock
|
|
@@ -35,14 +39,12 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
35
39
|
}),
|
|
36
40
|
}));
|
|
37
41
|
|
|
38
|
-
//
|
|
42
|
+
// cpx mock (was execa)
|
|
39
43
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
40
|
-
vi.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}),
|
|
45
|
-
}));
|
|
44
|
+
const mockCpxExec = vi.fn((...args: unknown[]) => {
|
|
45
|
+
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
46
|
+
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
47
|
+
});
|
|
46
48
|
|
|
47
49
|
const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
|
|
48
50
|
vi.mock("node:fs", () => ({
|
|
@@ -23,6 +23,10 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
23
23
|
rm: mockFsxRm,
|
|
24
24
|
glob: mockFsxGlob,
|
|
25
25
|
},
|
|
26
|
+
cpx: {
|
|
27
|
+
exec: mockCpxExec,
|
|
28
|
+
execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
29
|
+
},
|
|
26
30
|
}));
|
|
27
31
|
|
|
28
32
|
// env mock
|
|
@@ -33,14 +37,12 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
33
37
|
}),
|
|
34
38
|
}));
|
|
35
39
|
|
|
36
|
-
//
|
|
40
|
+
// cpx mock (was execa)
|
|
37
41
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
38
|
-
vi.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}),
|
|
43
|
-
}));
|
|
42
|
+
const mockCpxExec = vi.fn((...args: unknown[]) => {
|
|
43
|
+
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
44
|
+
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
45
|
+
});
|
|
44
46
|
|
|
45
47
|
const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
|
|
46
48
|
vi.mock("node:fs", () => ({
|
|
@@ -24,6 +24,10 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
24
24
|
glob: mockFsxGlob,
|
|
25
25
|
copy: mockFsxCopy,
|
|
26
26
|
},
|
|
27
|
+
cpx: {
|
|
28
|
+
exec: mockCpxExec,
|
|
29
|
+
execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
30
|
+
},
|
|
27
31
|
}));
|
|
28
32
|
|
|
29
33
|
let mockEnv: Record<string, unknown> = {};
|
|
@@ -34,12 +38,10 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
34
38
|
}));
|
|
35
39
|
|
|
36
40
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
37
|
-
vi.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}),
|
|
42
|
-
}));
|
|
41
|
+
const mockCpxExec = vi.fn((...args: unknown[]) => {
|
|
42
|
+
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
43
|
+
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
44
|
+
});
|
|
43
45
|
|
|
44
46
|
const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
|
|
45
47
|
vi.mock("node:fs", () => ({
|
|
@@ -25,6 +25,10 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
25
25
|
glob: mockFsxGlob,
|
|
26
26
|
copy: mockFsxCopy,
|
|
27
27
|
},
|
|
28
|
+
cpx: {
|
|
29
|
+
exec: mockCpxExec,
|
|
30
|
+
execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
31
|
+
},
|
|
28
32
|
}));
|
|
29
33
|
|
|
30
34
|
// env mock
|
|
@@ -35,17 +39,15 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
35
39
|
}),
|
|
36
40
|
}));
|
|
37
41
|
|
|
38
|
-
//
|
|
42
|
+
// cpx mock (was execa) — tracks commands and resolves immediately
|
|
39
43
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
40
|
-
let execaFactory: (...args: unknown[]) => Promise<{ stdout: string; stderr: string }> = () =>
|
|
41
|
-
Promise.resolve({ stdout: "", stderr: "" });
|
|
44
|
+
let execaFactory: (...args: unknown[]) => Promise<{ stdout: string; stderr: string; exitCode: number }> = () =>
|
|
45
|
+
Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
42
46
|
|
|
43
|
-
vi.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}),
|
|
48
|
-
}));
|
|
47
|
+
const mockCpxExec = vi.fn((...args: unknown[]) => {
|
|
48
|
+
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
49
|
+
return execaFactory(...args);
|
|
50
|
+
});
|
|
49
51
|
|
|
50
52
|
const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
|
|
51
53
|
vi.mock("node:fs", () => ({
|
|
@@ -135,7 +137,7 @@ export default config;`;
|
|
|
135
137
|
mockEnv = { ANDROID_HOME: "C:/Android/Sdk" };
|
|
136
138
|
|
|
137
139
|
execaCalls.length = 0;
|
|
138
|
-
execaFactory = () => Promise.resolve({ stdout: "", stderr: "" });
|
|
140
|
+
execaFactory = () => Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
139
141
|
mockFsWriteFile.mockReset();
|
|
140
142
|
mockFsWriteFile.mockResolvedValue(undefined);
|
|
141
143
|
}
|
|
@@ -195,7 +197,7 @@ describe("Capacitor.run()", () => {
|
|
|
195
197
|
return Promise.reject(new Error("cap run failed"));
|
|
196
198
|
}
|
|
197
199
|
}
|
|
198
|
-
return Promise.resolve({ stdout: "", stderr: "" });
|
|
200
|
+
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
199
201
|
};
|
|
200
202
|
|
|
201
203
|
const cap = await Capacitor.create(PKG_PATH, {
|
|
@@ -24,6 +24,10 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
24
24
|
glob: mockFsxGlob,
|
|
25
25
|
copy: mockFsxCopy,
|
|
26
26
|
},
|
|
27
|
+
cpx: {
|
|
28
|
+
exec: mockCpxExec,
|
|
29
|
+
execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
30
|
+
},
|
|
27
31
|
}));
|
|
28
32
|
|
|
29
33
|
let mockEnv: Record<string, unknown> = {};
|
|
@@ -34,12 +38,10 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
34
38
|
}));
|
|
35
39
|
|
|
36
40
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
37
|
-
vi.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}),
|
|
42
|
-
}));
|
|
41
|
+
const mockCpxExec = vi.fn((...args: unknown[]) => {
|
|
42
|
+
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
43
|
+
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
44
|
+
});
|
|
43
45
|
|
|
44
46
|
const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
|
|
45
47
|
vi.mock("node:fs", () => ({
|