@simplysm/sd-cli 7.0.210 → 7.0.220
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/build-tool/SdCliElectron.mjs +6 -2
- package/dist/builder/SdCliClientBuilder.d.ts +1 -2
- package/dist/builder/SdCliClientBuilder.mjs +44 -72
- package/dist/builder/SdCliServerBuilder.mjs +9 -1
- package/dist/entry-points/SdCliWorkspace.mjs +55 -13
- package/dist/packages/SdCliPackage.d.ts +1 -3
- package/dist/packages/SdCliPackage.mjs +72 -30
- package/dist/utils/SdCliConfigUtil.mjs +4 -4
- package/dist/worker/build-worker.d.ts +1 -0
- package/dist/worker/build-worker.mjs +67 -0
- package/package.json +7 -12
- package/src/build-tool/SdCliElectron.ts +7 -2
- package/src/builder/SdCliClientBuilder.ts +46 -75
- package/src/builder/SdCliServerBuilder.ts +8 -0
- package/src/entry-points/SdCliWorkspace.ts +61 -12
- package/src/packages/SdCliPackage.ts +85 -34
- package/src/utils/SdCliConfigUtil.ts +3 -3
- package/src/worker/build-worker.ts +74 -0
- package/tsconfig-build.json +2 -1
- package/tsconfig.json +2 -1
- package/lib/ts-node-esm-paths.mjs +0 -15
|
@@ -16,10 +16,6 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
|
|
16
16
|
import { AngularWebpackPlugin } from "@ngtools/webpack";
|
|
17
17
|
import { IndexHtmlWebpackPlugin } from "@angular-devkit/build-angular/src/webpack/plugins/index-html-webpack-plugin";
|
|
18
18
|
import { SassWorkerImplementation } from "@angular-devkit/build-angular/src/sass/sass-service";
|
|
19
|
-
import { HmrLoader } from "@angular-devkit/build-angular/src/webpack/plugins/hmr/hmr-loader";
|
|
20
|
-
import wdm from "webpack-dev-middleware";
|
|
21
|
-
import whm from "webpack-hot-middleware";
|
|
22
|
-
import { NextHandleFunction } from "connect";
|
|
23
19
|
import { LicenseWebpackPlugin } from "license-webpack-plugin";
|
|
24
20
|
import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
|
|
25
21
|
import { createHash } from "crypto";
|
|
@@ -94,7 +90,7 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
94
90
|
return super.on(event, listener);
|
|
95
91
|
}
|
|
96
92
|
|
|
97
|
-
public async watchAsync(): Promise<
|
|
93
|
+
public async watchAsync(): Promise<void> {
|
|
98
94
|
// DIST 비우기
|
|
99
95
|
await FsUtil.removeAsync(path.resolve(this._rootPath, ".electron"));
|
|
100
96
|
await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
|
|
@@ -102,7 +98,7 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
102
98
|
// NgModule 생성
|
|
103
99
|
await this._ngModuleGenerator.runAsync();
|
|
104
100
|
|
|
105
|
-
// CORDOVA
|
|
101
|
+
// CORDOVA 초기화
|
|
106
102
|
if (this._cordova) {
|
|
107
103
|
this._logger.debug("CORDOVA 구성...");
|
|
108
104
|
await this._cordova.initializeAsync();
|
|
@@ -112,7 +108,7 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
112
108
|
const webpackConfigs = (Object.keys(this._config.builder ?? { web: {} }) as ("web" | "cordova" | "electron")[])
|
|
113
109
|
.map((builderType) => this._getWebpackConfig(true, builderType));
|
|
114
110
|
const multiCompiler = webpack(webpackConfigs);
|
|
115
|
-
|
|
111
|
+
await new Promise<void>((resolve, reject) => {
|
|
116
112
|
multiCompiler.hooks.invalid.tap(this.constructor.name, (fileName) => {
|
|
117
113
|
if (fileName != null) {
|
|
118
114
|
this._logger.debug("파일변경 감지", fileName);
|
|
@@ -132,22 +128,20 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
132
128
|
this._logger.debug("Webpack 빌드 수행...");
|
|
133
129
|
});
|
|
134
130
|
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
multiCompiler.watch({}, async (err, multiStats) => {
|
|
132
|
+
if (err != null || multiStats == null) {
|
|
137
133
|
this.emit("complete", [{
|
|
138
134
|
filePath: undefined,
|
|
139
135
|
line: undefined,
|
|
140
136
|
char: undefined,
|
|
141
137
|
code: undefined,
|
|
142
138
|
severity: "error",
|
|
143
|
-
message: err
|
|
139
|
+
message: err?.stack ?? "알 수 없는 오류 (multiStats=null)"
|
|
144
140
|
}]);
|
|
145
141
|
reject(err);
|
|
146
142
|
return;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
143
|
+
}
|
|
149
144
|
|
|
150
|
-
multiCompiler.hooks.done.tap(this.constructor.name, async (multiStats) => {
|
|
151
145
|
// 결과 반환
|
|
152
146
|
const results = multiStats.stats.mapMany((stats) => SdCliBuildResultUtil.convertFromWebpackStats(stats));
|
|
153
147
|
|
|
@@ -162,22 +156,10 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
162
156
|
|
|
163
157
|
// 마무리
|
|
164
158
|
this._logger.debug("Webpack 빌드 완료");
|
|
165
|
-
resolve(
|
|
159
|
+
resolve();
|
|
166
160
|
|
|
167
161
|
this.emit("complete", results);
|
|
168
162
|
});
|
|
169
|
-
|
|
170
|
-
const middlewares = multiCompiler.compilers.mapMany((compiler) => [
|
|
171
|
-
wdm(compiler, {
|
|
172
|
-
publicPath: compiler.options.output.publicPath,
|
|
173
|
-
index: "index.html",
|
|
174
|
-
stats: false
|
|
175
|
-
}),
|
|
176
|
-
whm(compiler, {
|
|
177
|
-
path: `${compiler.options.output.publicPath}__webpack_hmr`,
|
|
178
|
-
log: false
|
|
179
|
-
})
|
|
180
|
-
]);
|
|
181
163
|
});
|
|
182
164
|
}
|
|
183
165
|
|
|
@@ -189,6 +171,12 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
189
171
|
// NgModule 생성
|
|
190
172
|
await this._ngModuleGenerator.runAsync();
|
|
191
173
|
|
|
174
|
+
// CORDOVA 초기화
|
|
175
|
+
if (this._cordova) {
|
|
176
|
+
this._logger.debug("CORDOVA 구성...");
|
|
177
|
+
await this._cordova.initializeAsync();
|
|
178
|
+
}
|
|
179
|
+
|
|
192
180
|
// 빌드
|
|
193
181
|
this._logger.debug("Webpack 빌드 수행...");
|
|
194
182
|
const builderTypes = (Object.keys(this._config.builder ?? { web: {} }) as ("web" | "cordova" | "electron")[]);
|
|
@@ -222,11 +210,8 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
222
210
|
);
|
|
223
211
|
}
|
|
224
212
|
|
|
225
|
-
// CORDOVA
|
|
213
|
+
// CORDOVA 빌드
|
|
226
214
|
if (this._cordova) {
|
|
227
|
-
this._logger.debug("CORDOVA 구성...");
|
|
228
|
-
await this._cordova.initializeAsync();
|
|
229
|
-
|
|
230
215
|
this._logger.debug("CORDOVA 빌드...");
|
|
231
216
|
await this._cordova.buildAsync(path.resolve(this._parsedTsconfig.options.outDir!, "cordova"));
|
|
232
217
|
}
|
|
@@ -245,6 +230,8 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
245
230
|
throw new Error("ELECTRON 빌드 패키지의 'dependencies'에는 'dotenv'가 반드시 포함되어야 합니다.");
|
|
246
231
|
}
|
|
247
232
|
|
|
233
|
+
const remoteVersion = npmConfig.dependencies?.["@electron/remote"];
|
|
234
|
+
|
|
248
235
|
const electronSrcPath = path.resolve(this._rootPath, `.electron/src`);
|
|
249
236
|
const electronDistPath = path.resolve(this._rootPath, `.electron/dist`);
|
|
250
237
|
|
|
@@ -259,7 +246,10 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
259
246
|
"electron": electronVersion.replace("^", "")
|
|
260
247
|
},
|
|
261
248
|
dependencies: {
|
|
262
|
-
"dotenv": dotenvVersion
|
|
249
|
+
"dotenv": dotenvVersion,
|
|
250
|
+
...remoteVersion !== undefined ? {
|
|
251
|
+
"@electron/remote": remoteVersion
|
|
252
|
+
} : {}
|
|
263
253
|
}
|
|
264
254
|
});
|
|
265
255
|
|
|
@@ -325,8 +315,6 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
325
315
|
const internalModuleCachePaths = watch ? this._getInternalModuleCachePaths(workspaceName) : undefined;
|
|
326
316
|
|
|
327
317
|
const npmConfig = this._getNpmConfig(this._rootPath)!;
|
|
328
|
-
// const pkgVersion = npmConfig.version;
|
|
329
|
-
// const ngVersion = this._getNpmConfig(FsUtil.findAllParentChildDirPaths("node_modules/@angular/core", this._rootPath, this._workspaceRootPath)[0])!.version;
|
|
330
318
|
|
|
331
319
|
const workspacePkgLockContent = FsUtil.readFile(path.resolve(this._workspaceRootPath, "package-lock.json"));
|
|
332
320
|
|
|
@@ -334,7 +322,6 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
334
322
|
const publicPath = builderType === "web" ? `/${pkgKey}/` : watch ? `/${pkgKey}/${builderType}/` : ``;
|
|
335
323
|
|
|
336
324
|
const cacheBasePath = path.resolve(this._rootPath, ".cache");
|
|
337
|
-
// const cachePath = path.resolve(cacheBasePath, pkgVersion);
|
|
338
325
|
|
|
339
326
|
const distPath = (builderType === "cordova" && !watch) ? path.resolve(this._cordova!.cordovaPath, "www")
|
|
340
327
|
: (builderType === "electron" && !watch) ? path.resolve(this._rootPath, ".electron/src")
|
|
@@ -355,7 +342,7 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
355
342
|
profile: false,
|
|
356
343
|
resolve: {
|
|
357
344
|
roots: [this._rootPath],
|
|
358
|
-
extensions: [".ts", ".tsx", ".mjs", ".cjs", ".js"],
|
|
345
|
+
extensions: [".ts", ".tsx", ".mjs", ".cjs", ".js", ".jsx"],
|
|
359
346
|
symlinks: true,
|
|
360
347
|
modules: [this._workspaceRootPath, "node_modules"],
|
|
361
348
|
mainFields: ["es2015", "browser", "module", "main"],
|
|
@@ -366,14 +353,9 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
366
353
|
},
|
|
367
354
|
context: this._workspaceRootPath,
|
|
368
355
|
entry: {
|
|
369
|
-
main: [
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
] : [],
|
|
373
|
-
mainFilePath
|
|
374
|
-
],
|
|
375
|
-
...FsUtil.exists(polyfillsFilePath) ? { polyfills: polyfillsFilePath } : {},
|
|
376
|
-
...FsUtil.exists(stylesFilePath) ? { styles: stylesFilePath } : {}
|
|
356
|
+
main: [mainFilePath],
|
|
357
|
+
...FsUtil.exists(polyfillsFilePath) ? { polyfills: [polyfillsFilePath] } : {},
|
|
358
|
+
...FsUtil.exists(stylesFilePath) ? { styles: [stylesFilePath] } : {}
|
|
377
359
|
},
|
|
378
360
|
output: {
|
|
379
361
|
uniqueName: pkgKey,
|
|
@@ -389,7 +371,10 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
389
371
|
scriptType: "module"
|
|
390
372
|
},
|
|
391
373
|
watch: false,
|
|
392
|
-
watchOptions: {
|
|
374
|
+
watchOptions: {
|
|
375
|
+
poll: undefined,
|
|
376
|
+
ignored: undefined
|
|
377
|
+
},
|
|
393
378
|
performance: { hints: false },
|
|
394
379
|
ignoreWarnings: [
|
|
395
380
|
/Failed to parse source map from/,
|
|
@@ -411,7 +396,6 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
411
396
|
.update(watch.toString())
|
|
412
397
|
.digest("hex")
|
|
413
398
|
},
|
|
414
|
-
// cache: { type: "memory", maxGenerations: 1 },
|
|
415
399
|
...watch ? {
|
|
416
400
|
snapshot: {
|
|
417
401
|
immutablePaths: internalModuleCachePaths,
|
|
@@ -484,27 +468,6 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
484
468
|
test: /[/\\]rxjs[/\\]add[/\\].+\.js$/,
|
|
485
469
|
sideEffects: true
|
|
486
470
|
},
|
|
487
|
-
...watch ? [
|
|
488
|
-
{
|
|
489
|
-
loader: HmrLoader,
|
|
490
|
-
include: [mainFilePath]
|
|
491
|
-
}
|
|
492
|
-
] : [],
|
|
493
|
-
...watch ? [
|
|
494
|
-
{
|
|
495
|
-
test: /\.[cm]?jsx?$/,
|
|
496
|
-
enforce: "pre" as const,
|
|
497
|
-
loader: "source-map-loader",
|
|
498
|
-
options: {
|
|
499
|
-
filterSourceMappingUrl: (mapUri: string, resourcePath: string) => {
|
|
500
|
-
const workspaceRegex = new RegExp(`node_modules[\\\\/]@${workspaceName}[\\\\/]`);
|
|
501
|
-
return !resourcePath.includes("node_modules")
|
|
502
|
-
|| (/node_modules[\\/]@simplysm[\\/]/).test(resourcePath)
|
|
503
|
-
|| workspaceRegex.test(resourcePath);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
] : [],
|
|
508
471
|
{
|
|
509
472
|
test: /\.[cm]?[tj]sx?$/,
|
|
510
473
|
resolve: { fullySpecified: false },
|
|
@@ -522,10 +485,25 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
522
485
|
}
|
|
523
486
|
]
|
|
524
487
|
},
|
|
488
|
+
...watch ? [
|
|
489
|
+
{
|
|
490
|
+
test: /\.[cm]?jsx?$/,
|
|
491
|
+
enforce: "pre" as const,
|
|
492
|
+
loader: "source-map-loader",
|
|
493
|
+
options: {
|
|
494
|
+
filterSourceMappingUrl: (mapUri: string, resourcePath: string) => {
|
|
495
|
+
const workspaceRegex = new RegExp(`node_modules[\\\\/]@${workspaceName}[\\\\/]`);
|
|
496
|
+
return !resourcePath.includes("node_modules")
|
|
497
|
+
|| (/node_modules[\\/]@simplysm[\\/]/).test(resourcePath)
|
|
498
|
+
|| workspaceRegex.test(resourcePath);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
] : [],
|
|
525
503
|
{
|
|
526
504
|
test: /\.[cm]?tsx?$/,
|
|
527
505
|
loader: "@ngtools/webpack",
|
|
528
|
-
exclude: [/[/\\](?:css-loader|mini-css-extract-plugin|webpack
|
|
506
|
+
exclude: [/[/\\](?:css-loader|mini-css-extract-plugin|webpack)[/\\]/]
|
|
529
507
|
},
|
|
530
508
|
{
|
|
531
509
|
test: /\.css$/i,
|
|
@@ -678,9 +656,6 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
678
656
|
emitNgModuleScope: watch,
|
|
679
657
|
inlineStyleFileExtension: "scss"
|
|
680
658
|
}),
|
|
681
|
-
// new AnyComponentStyleBudgetChecker(watch ? [] : [
|
|
682
|
-
// { type: Type.AnyComponentStyle, maximumWarning: "2kb", maximumError: "4kb" }
|
|
683
|
-
// ]),
|
|
684
659
|
{
|
|
685
660
|
apply: (compiler: webpack.Compiler) => {
|
|
686
661
|
compiler.hooks.shutdown.tap("sass-worker", () => {
|
|
@@ -690,13 +665,12 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
690
665
|
},
|
|
691
666
|
new MiniCssExtractPlugin({ filename: "[name].css" }),
|
|
692
667
|
new SuppressExtractedTextChunksWebpackPlugin(),
|
|
693
|
-
// NgBuildAnalyticsPlugin,
|
|
694
668
|
new IndexHtmlWebpackPlugin({
|
|
695
669
|
indexPath: path.resolve(this._rootPath, "src/index.html"),
|
|
696
670
|
outputPath: "index.html",
|
|
697
671
|
baseHref: publicPath,
|
|
698
672
|
entrypoints: [
|
|
699
|
-
["runtime",
|
|
673
|
+
["runtime", !watch],
|
|
700
674
|
["polyfills", true],
|
|
701
675
|
["styles", false],
|
|
702
676
|
["vendor", true],
|
|
@@ -718,9 +692,6 @@ export class SdCliClientBuilder extends EventEmitter {
|
|
|
718
692
|
crossOrigin: "none",
|
|
719
693
|
lang: undefined
|
|
720
694
|
}),
|
|
721
|
-
...watch ? [
|
|
722
|
-
new webpack.HotModuleReplacementPlugin()
|
|
723
|
-
] : [],
|
|
724
695
|
new webpack.EnvironmentPlugin({
|
|
725
696
|
SD_VERSION: this._getNpmConfig(this._rootPath)!.version,
|
|
726
697
|
...this._config.env
|
|
@@ -58,6 +58,14 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
58
58
|
|
|
59
59
|
compiler.watch({}, async (err, stats) => {
|
|
60
60
|
if (err != null || stats == null) {
|
|
61
|
+
this.emit("complete", [{
|
|
62
|
+
filePath: undefined,
|
|
63
|
+
line: undefined,
|
|
64
|
+
char: undefined,
|
|
65
|
+
code: undefined,
|
|
66
|
+
severity: "error",
|
|
67
|
+
message: err?.stack ?? "알 수 없는 오류 (stats=null)"
|
|
68
|
+
}]);
|
|
61
69
|
reject(err);
|
|
62
70
|
return;
|
|
63
71
|
}
|
|
@@ -8,8 +8,9 @@ import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
|
|
|
8
8
|
import semver from "semver/preload";
|
|
9
9
|
import { SdCliConfigUtil } from "../utils/SdCliConfigUtil";
|
|
10
10
|
import { SdServiceServer } from "@simplysm/sd-service-server";
|
|
11
|
-
import { SdCliNpm } from "./SdCliNpm";
|
|
12
11
|
import { SdCliLocalUpdate } from "./SdCliLocalUpdate";
|
|
12
|
+
import url from "url";
|
|
13
|
+
import mime from "mime";
|
|
13
14
|
import { NextHandleFunction } from "connect";
|
|
14
15
|
|
|
15
16
|
export class SdCliWorkspace {
|
|
@@ -37,6 +38,7 @@ export class SdCliWorkspace {
|
|
|
37
38
|
|
|
38
39
|
this._logger.debug("패키지 이벤트 설정...");
|
|
39
40
|
let changeCount = 0;
|
|
41
|
+
let changePkgs: SdCliPackage[] = [];
|
|
40
42
|
const totalResultMap = new Map<string, ISdCliPackageBuildResult[]>();
|
|
41
43
|
for (const pkg of pkgs) {
|
|
42
44
|
pkg
|
|
@@ -47,17 +49,35 @@ export class SdCliWorkspace {
|
|
|
47
49
|
changeCount++;
|
|
48
50
|
this._logger.debug(`[${pkg.name}] 빌드를 시작합니다...`);
|
|
49
51
|
})
|
|
50
|
-
.on("complete",
|
|
51
|
-
|
|
52
|
-
await this._restartServerAsync(pkg);
|
|
53
|
-
}
|
|
52
|
+
.on("complete", (results) => {
|
|
53
|
+
changePkgs.push(pkg);
|
|
54
54
|
|
|
55
55
|
this._logger.debug(`[${pkg.name}] 빌드가 완료되었습니다.`);
|
|
56
56
|
totalResultMap.set(pkg.name, results);
|
|
57
57
|
|
|
58
|
-
setTimeout(() => {
|
|
58
|
+
setTimeout(async () => {
|
|
59
59
|
changeCount--;
|
|
60
60
|
if (changeCount === 0) {
|
|
61
|
+
const currChangePkgs = [...changePkgs];
|
|
62
|
+
changePkgs = [];
|
|
63
|
+
|
|
64
|
+
for (const changePkg of currChangePkgs) {
|
|
65
|
+
if (changePkg.config.type === "server" && !results.some((item) => item.severity === "error")) {
|
|
66
|
+
await this._restartServerAsync(changePkg);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (changePkg.config.type === "client") {
|
|
70
|
+
if (typeof changePkg.config.server === "string") {
|
|
71
|
+
const serverInfo = this._serverInfoMap.get(changePkg.config.server);
|
|
72
|
+
serverInfo?.server?.broadcastReload();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const serverInfo = this._serverInfoMap.get("PORT:" + changePkg.config.server.port);
|
|
76
|
+
serverInfo?.server?.broadcastReload();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
61
81
|
this._loggingResults(totalResultMap);
|
|
62
82
|
this._loggingOpenClientHrefs();
|
|
63
83
|
this._logger.info("모든 빌드가 완료되었습니다.");
|
|
@@ -78,11 +98,37 @@ export class SdCliWorkspace {
|
|
|
78
98
|
await pkgs.parallelAsync(async (pkg) => {
|
|
79
99
|
await Wait.until(() => !pkg.allDependencies.some((dep) => pkgNames.includes(dep) && !buildCompletedPackageNames.includes(dep)));
|
|
80
100
|
if (pkg.config.type === "client") {
|
|
81
|
-
|
|
101
|
+
await pkg.watchAsync();
|
|
102
|
+
|
|
103
|
+
const pkgMiddleware: NextHandleFunction = (req, res, next) => {
|
|
104
|
+
if (req.method === "GET") {
|
|
105
|
+
const urlObj = url.parse(req.url!, true, false);
|
|
106
|
+
const urlPathChain = decodeURI(urlObj.pathname!.slice(1)).split("/");
|
|
107
|
+
if (urlPathChain[0] === pkg.name.split("/").last()!) {
|
|
108
|
+
let targetFilePath = path.resolve(pkg.rootPath, "dist", ...urlPathChain.slice(1));
|
|
109
|
+
targetFilePath = FsUtil.exists(targetFilePath) && FsUtil.stat(targetFilePath).isDirectory() ? path.resolve(targetFilePath, "index.html") : targetFilePath;
|
|
110
|
+
|
|
111
|
+
if (FsUtil.exists(targetFilePath) && !path.basename(targetFilePath).startsWith(".")) {
|
|
112
|
+
const fileStream = FsUtil.createReadStream(targetFilePath);
|
|
113
|
+
const targetFileSize = FsUtil.lstat(targetFilePath).size;
|
|
114
|
+
|
|
115
|
+
fileStream.on("open", () => {
|
|
116
|
+
res.setHeader("Content-Length", targetFileSize);
|
|
117
|
+
res.setHeader("Content-Type", mime.getType(targetFilePath)!);
|
|
118
|
+
res.writeHead(200);
|
|
119
|
+
});
|
|
120
|
+
fileStream.pipe(res);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
next();
|
|
127
|
+
};
|
|
82
128
|
|
|
83
129
|
if (typeof pkg.config.server === "string") {
|
|
84
130
|
const serverInfo = this._serverInfoMap.getOrCreate(pkg.config.server, { middlewares: [], clientInfos: [] });
|
|
85
|
-
serverInfo.middlewares.push(
|
|
131
|
+
serverInfo.middlewares.push(pkgMiddleware);
|
|
86
132
|
serverInfo.clientInfos.push({
|
|
87
133
|
pkgKey: pkg.name.split("/").last()!,
|
|
88
134
|
platforms: pkg.config.builder ? Object.keys(pkg.config.builder) : ["web"],
|
|
@@ -90,7 +136,10 @@ export class SdCliWorkspace {
|
|
|
90
136
|
});
|
|
91
137
|
}
|
|
92
138
|
else { // DEV SERVER
|
|
93
|
-
const serverInfo = this._serverInfoMap.getOrCreate("
|
|
139
|
+
const serverInfo = this._serverInfoMap.getOrCreate("PORT:" + pkg.config.server.port, {
|
|
140
|
+
middlewares: [],
|
|
141
|
+
clientInfos: []
|
|
142
|
+
});
|
|
94
143
|
if (serverInfo.server === undefined) {
|
|
95
144
|
const server = new SdServiceServer({
|
|
96
145
|
rootPath: process.cwd(),
|
|
@@ -99,7 +148,7 @@ export class SdCliWorkspace {
|
|
|
99
148
|
});
|
|
100
149
|
await server.listenAsync();
|
|
101
150
|
serverInfo.server = server;
|
|
102
|
-
serverInfo.server.devMiddlewares =
|
|
151
|
+
serverInfo.server.devMiddlewares = [pkgMiddleware];
|
|
103
152
|
serverInfo.clientInfos.push({
|
|
104
153
|
pkgKey: pkg.name.split("/").last()!,
|
|
105
154
|
platforms: pkg.config.builder ? Object.keys(pkg.config.builder) : ["web"],
|
|
@@ -245,8 +294,8 @@ export class SdCliWorkspace {
|
|
|
245
294
|
|
|
246
295
|
// 빌드
|
|
247
296
|
if (!opt.noBuild) {
|
|
248
|
-
this._logger.debug("노드패키지 업데이트...");
|
|
249
|
-
await new SdCliNpm(this._rootPath).updateAsync();
|
|
297
|
+
// this._logger.debug("노드패키지 업데이트...");
|
|
298
|
+
// await new SdCliNpm(this._rootPath).updateAsync();
|
|
250
299
|
|
|
251
300
|
this._logger.debug("빌드를 시작합니다...");
|
|
252
301
|
await this._buildPkgsAsync(pkgs);
|
|
@@ -2,16 +2,13 @@ import { INpmConfig, ISdCliPackageBuildResult, ITsconfig, TSdCliPackageConfig }
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { FsUtil, PathUtil, SdProcess } from "@simplysm/sd-core-node";
|
|
4
4
|
import { EventEmitter } from "events";
|
|
5
|
-
import { NeverEntryError, ObjectUtil, StringUtil } from "@simplysm/sd-core-common";
|
|
6
|
-
import { SdCliTsLibBuilder } from "../builder/SdCliTsLibBuilder";
|
|
7
|
-
import { SdCliJsLibBuilder } from "../builder/SdCliJsLibBuilder";
|
|
8
|
-
import { SdCliServerBuilder } from "../builder/SdCliServerBuilder";
|
|
5
|
+
import { JsonConvert, NeverEntryError, ObjectUtil, StringUtil } from "@simplysm/sd-core-common";
|
|
9
6
|
import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
|
|
10
|
-
import { SdCliClientBuilder } from "../builder/SdCliClientBuilder";
|
|
11
|
-
import { NextHandleFunction } from "connect";
|
|
12
7
|
import { SdStorage } from "@simplysm/sd-storage";
|
|
13
8
|
import ts from "typescript";
|
|
14
9
|
import { SdCliGithubApi } from "../build-tool/SdCliGithubApi";
|
|
10
|
+
import cp from "child_process";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
15
12
|
|
|
16
13
|
export class SdCliPackage extends EventEmitter {
|
|
17
14
|
private readonly _npmConfig: INpmConfig;
|
|
@@ -70,19 +67,91 @@ export class SdCliPackage extends EventEmitter {
|
|
|
70
67
|
await FsUtil.writeJsonAsync(npmConfigFilePath, this._npmConfig, { space: 2 });
|
|
71
68
|
}
|
|
72
69
|
|
|
73
|
-
public async watchAsync(): Promise<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
public async watchAsync(): Promise<void> {
|
|
71
|
+
const isTs = FsUtil.exists(path.resolve(this.rootPath, "tsconfig.json"));
|
|
72
|
+
|
|
73
|
+
if (isTs) {
|
|
74
|
+
await this._genBuildTsconfigAsync();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const workerPath = fileURLToPath(await import.meta.resolve!("../worker/build-worker"));
|
|
78
|
+
await new Promise<void>((resolve, reject) => {
|
|
79
|
+
const worker = cp.fork(workerPath, [
|
|
80
|
+
"watch",
|
|
81
|
+
this.rootPath,
|
|
82
|
+
JsonConvert.stringify(this.config),
|
|
83
|
+
this._workspaceRootPath
|
|
84
|
+
], {
|
|
85
|
+
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
86
|
+
env: process.env
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
worker.on("error", (err) => {
|
|
90
|
+
reject(err);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
worker.stdout!.pipe(process.stdout);
|
|
94
|
+
worker.stderr!.pipe(process.stderr);
|
|
95
|
+
|
|
96
|
+
worker.on("message", (json: string) => {
|
|
97
|
+
const msg = JsonConvert.parse(json);
|
|
98
|
+
if (msg.event === "ready") {
|
|
99
|
+
resolve();
|
|
100
|
+
}
|
|
101
|
+
else if (msg.event === "change") {
|
|
102
|
+
this.emit("change");
|
|
103
|
+
}
|
|
104
|
+
else if (msg.event === "complete") {
|
|
105
|
+
this.emit("complete", msg.body);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
throw new NeverEntryError();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
82
112
|
}
|
|
83
113
|
|
|
84
114
|
public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
|
|
85
|
-
|
|
115
|
+
const isTs = FsUtil.exists(path.resolve(this.rootPath, "tsconfig.json"));
|
|
116
|
+
|
|
117
|
+
if (isTs) {
|
|
118
|
+
await this._genBuildTsconfigAsync();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const workerPath = fileURLToPath(await import.meta.resolve!("../worker/build-worker"));
|
|
122
|
+
return await new Promise<ISdCliPackageBuildResult[]>((resolve, reject) => {
|
|
123
|
+
const worker = cp.fork(workerPath, [
|
|
124
|
+
"build",
|
|
125
|
+
this.rootPath,
|
|
126
|
+
JsonConvert.stringify(this.config),
|
|
127
|
+
this._workspaceRootPath
|
|
128
|
+
], {
|
|
129
|
+
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
130
|
+
env: process.env
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
worker.on("error", (err) => {
|
|
134
|
+
reject(err);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
worker.stdout!.pipe(process.stdout);
|
|
138
|
+
worker.stderr!.pipe(process.stderr);
|
|
139
|
+
|
|
140
|
+
let result: ISdCliPackageBuildResult[] = [];
|
|
141
|
+
|
|
142
|
+
worker.on("message", (json: string) => {
|
|
143
|
+
result = JsonConvert.parse(json);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
worker.on("exit", (code) => {
|
|
147
|
+
if (code !== 0) {
|
|
148
|
+
reject(new Error(`오류와 함께 닫힘 (${code})`));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
resolve(result);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
86
155
|
}
|
|
87
156
|
|
|
88
157
|
public async publishAsync(): Promise<void> {
|
|
@@ -156,24 +225,6 @@ export class SdCliPackage extends EventEmitter {
|
|
|
156
225
|
}
|
|
157
226
|
}
|
|
158
227
|
|
|
159
|
-
private async _createBuilderAsync(): Promise<SdCliJsLibBuilder | SdCliTsLibBuilder | SdCliServerBuilder | SdCliClientBuilder> {
|
|
160
|
-
const isTs = FsUtil.exists(path.resolve(this.rootPath, "tsconfig.json"));
|
|
161
|
-
|
|
162
|
-
if (isTs) {
|
|
163
|
-
await this._genBuildTsconfigAsync();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (this.config.type === "library") {
|
|
167
|
-
return isTs ? new SdCliTsLibBuilder(this.rootPath, this.config, this._workspaceRootPath) : new SdCliJsLibBuilder(this.rootPath);
|
|
168
|
-
}
|
|
169
|
-
else if (this.config.type === "server") {
|
|
170
|
-
return new SdCliServerBuilder(this.rootPath, this.config, this._workspaceRootPath);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
return new SdCliClientBuilder(this.rootPath, this.config, this._workspaceRootPath);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
228
|
private async _genBuildTsconfigAsync(): Promise<void> {
|
|
178
229
|
const baseTsconfigFilePath = path.resolve(this.rootPath, "tsconfig.json");
|
|
179
230
|
const baseTsconfig: ITsconfig = await FsUtil.readJsonAsync(baseTsconfigFilePath);
|
|
@@ -74,10 +74,10 @@ export class SdCliConfigUtil {
|
|
|
74
74
|
return pkgConf;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
private static _mergeObj<A, B>(
|
|
78
|
-
return ObjectUtil.merge(
|
|
77
|
+
private static _mergeObj<A, B>(orig: A, target: B): A & B {
|
|
78
|
+
return ObjectUtil.merge(orig, target, {
|
|
79
79
|
arrayProcess: "replace",
|
|
80
|
-
|
|
80
|
+
useDelTargetNull: true
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { SdCliTsLibBuilder } from "../builder/SdCliTsLibBuilder";
|
|
2
|
+
import { SdCliJsLibBuilder } from "../builder/SdCliJsLibBuilder";
|
|
3
|
+
import { SdCliServerBuilder } from "../builder/SdCliServerBuilder";
|
|
4
|
+
import { SdCliClientBuilder } from "../builder/SdCliClientBuilder";
|
|
5
|
+
import { FsUtil, Logger, LoggerSeverity } from "@simplysm/sd-core-node";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { JsonConvert } from "@simplysm/sd-core-common";
|
|
8
|
+
import { TSdCliPackageConfig } from "../commons";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if (process.env["SD_CLI_LOGGER_SEVERITY"] === "DEBUG") {
|
|
12
|
+
Logger.setConfig({
|
|
13
|
+
console: {
|
|
14
|
+
level: LoggerSeverity.debug
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
Logger.setConfig({
|
|
20
|
+
dot: true
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const type = process.argv[2] as ("build" | "watch");
|
|
25
|
+
const rootPath = process.argv[3];
|
|
26
|
+
const config = JsonConvert.parse(process.argv[4]) as TSdCliPackageConfig;
|
|
27
|
+
const workspaceRootPath = process.argv[5];
|
|
28
|
+
|
|
29
|
+
function createBuilder(): SdCliJsLibBuilder | SdCliTsLibBuilder | SdCliServerBuilder | SdCliClientBuilder {
|
|
30
|
+
const isTs = FsUtil.exists(path.resolve(rootPath, "tsconfig.json"));
|
|
31
|
+
|
|
32
|
+
if (config.type === "library") {
|
|
33
|
+
return isTs ? new SdCliTsLibBuilder(rootPath, config, workspaceRootPath) : new SdCliJsLibBuilder(rootPath);
|
|
34
|
+
}
|
|
35
|
+
else if (config.type === "server") {
|
|
36
|
+
return new SdCliServerBuilder(rootPath, config, workspaceRootPath);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return new SdCliClientBuilder(rootPath, config, workspaceRootPath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const builder = createBuilder();
|
|
44
|
+
|
|
45
|
+
if (type === "build") {
|
|
46
|
+
builder.buildAsync()
|
|
47
|
+
.then((result) => {
|
|
48
|
+
process.send!(JsonConvert.stringify(result));
|
|
49
|
+
process.exit(0);
|
|
50
|
+
})
|
|
51
|
+
.catch((err) => {
|
|
52
|
+
// eslint-disable-next-line no-console
|
|
53
|
+
console.error(err);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
builder
|
|
59
|
+
.on("change", () => {
|
|
60
|
+
process.send!(JsonConvert.stringify({ event: "change" }));
|
|
61
|
+
})
|
|
62
|
+
.on("complete", (results) => {
|
|
63
|
+
process.send!(JsonConvert.stringify({ event: "complete", body: results }));
|
|
64
|
+
})
|
|
65
|
+
.watchAsync()
|
|
66
|
+
.then(() => {
|
|
67
|
+
process.send!(JsonConvert.stringify({ event: "ready" }));
|
|
68
|
+
})
|
|
69
|
+
.catch((err) => {
|
|
70
|
+
// eslint-disable-next-line no-console
|
|
71
|
+
console.error(err);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
});
|
|
74
|
+
}
|