@simplysm/sd-cli 7.0.23 → 7.0.24
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/bin/sd-cli.d.ts +1 -1
- package/dist/bin/sd-cli.mjs +15 -3
- package/dist/builder/SdCliServerBuilder.d.ts +21 -0
- package/dist/builder/SdCliServerBuilder.mjs +260 -0
- package/dist/builder/SdCliTsLibBuilder.mjs +2 -2
- package/dist/commons.d.ts +2 -4
- package/dist/entry-points/SdCliNpm.d.ts +6 -0
- package/dist/entry-points/SdCliNpm.mjs +18 -0
- package/dist/entry-points/SdCliPrepare.d.ts +5 -0
- package/dist/entry-points/SdCliPrepare.mjs +54 -0
- package/dist/entry-points/SdCliWorkspace.d.ts +1 -0
- package/dist/entry-points/SdCliWorkspace.mjs +34 -31
- package/dist/packages/SdCliPackage.mjs +12 -9
- package/dist/utils/SdCliBuildResultUtil.d.ts +4 -1
- package/dist/utils/SdCliBuildResultUtil.mjs +25 -2
- package/dist/utils/SdCliNpmConfigUtil.d.ts +4 -0
- package/dist/utils/SdCliNpmConfigUtil.mjs +11 -0
- package/package.json +11 -5
- package/src/bin/sd-cli.ts +22 -2
- package/src/builder/SdCliServerBuilder.ts +287 -0
- package/src/builder/SdCliTsLibBuilder.ts +1 -1
- package/src/commons.ts +2 -5
- package/src/entry-points/SdCliNpm.ts +22 -0
- package/src/entry-points/SdCliPrepare.ts +54 -0
- package/src/entry-points/SdCliWorkspace.ts +40 -37
- package/src/packages/SdCliPackage.ts +12 -8
- package/src/utils/SdCliBuildResultUtil.ts +31 -1
- package/src/utils/SdCliNpmConfigUtil.ts +12 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { INpmConfig, ISdCliPackageBuildResult, ISdCliServerPackageConfig } from "../commons";
|
|
2
|
+
import { EventEmitter } from "events";
|
|
3
|
+
import { FsUtil, Logger, PathUtil } from "@simplysm/sd-core-node";
|
|
4
|
+
import webpack from "webpack";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import ts from "typescript";
|
|
7
|
+
import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
|
|
8
|
+
import { ErrorInfo } from "ts-loader/dist/interfaces";
|
|
9
|
+
import os from "os";
|
|
10
|
+
import { ESLint } from "eslint";
|
|
11
|
+
import webpackMerge from "webpack-merge";
|
|
12
|
+
import TerserPlugin from "terser-webpack-plugin";
|
|
13
|
+
import { StringUtil } from "@simplysm/sd-core-common";
|
|
14
|
+
import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
|
|
15
|
+
import ESLintWebpackPlugin from "eslint-webpack-plugin";
|
|
16
|
+
import CopyWebpackPlugin from "copy-webpack-plugin";
|
|
17
|
+
import LintResult = ESLint.LintResult;
|
|
18
|
+
|
|
19
|
+
export class SdCliServerBuilder extends EventEmitter {
|
|
20
|
+
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
21
|
+
|
|
22
|
+
private readonly _parsedTsconfig: ts.ParsedCommandLine;
|
|
23
|
+
private readonly _npmConfigMap = new Map<string, INpmConfig>();
|
|
24
|
+
|
|
25
|
+
public constructor(private readonly _rootPath: string,
|
|
26
|
+
private readonly _config: ISdCliServerPackageConfig,
|
|
27
|
+
private readonly _workspaceRootPath: string) {
|
|
28
|
+
super();
|
|
29
|
+
|
|
30
|
+
// tsconfig
|
|
31
|
+
const tsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
|
|
32
|
+
const tsconfig = FsUtil.readJson(tsconfigFilePath);
|
|
33
|
+
this._parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._rootPath);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public override on(event: "change", listener: () => void): this;
|
|
37
|
+
public override on(event: "complete", listener: (results: ISdCliPackageBuildResult[]) => void): this;
|
|
38
|
+
public override on(event: string | symbol, listener: (...args: any[]) => void): this {
|
|
39
|
+
return super.on(event, listener);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async watchAsync(): Promise<void> {
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
|
|
46
|
+
// DIST 비우기
|
|
47
|
+
await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
|
|
48
|
+
|
|
49
|
+
// 빌드 준비
|
|
50
|
+
const extModuleNames = this._findExternalModules(false).map((item) => item.name);
|
|
51
|
+
|
|
52
|
+
// 빌드
|
|
53
|
+
this._logger.debug("Webpack 빌드 수행...");
|
|
54
|
+
const webpackConfig = this._getWebpackBuildConfig(extModuleNames);
|
|
55
|
+
const compiler = webpack(webpackConfig);
|
|
56
|
+
const buildResults = await new Promise<ISdCliPackageBuildResult[]>((resolve, reject) => {
|
|
57
|
+
compiler.run((err, stats) => {
|
|
58
|
+
if (err != null || stats == null) {
|
|
59
|
+
reject(err);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 결과 리턴
|
|
64
|
+
const results = SdCliBuildResultUtil.convertFromWebpackStats(stats);
|
|
65
|
+
resolve(results);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
this._logger.debug("Webpack 빌드 완료");
|
|
69
|
+
|
|
70
|
+
return buildResults;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private get _webpackCommonConfig(): webpack.Configuration {
|
|
74
|
+
return {
|
|
75
|
+
devtool: false,
|
|
76
|
+
target: ["node", "es2020"],
|
|
77
|
+
profile: false,
|
|
78
|
+
resolve: {
|
|
79
|
+
roots: [this._rootPath],
|
|
80
|
+
extensions: [".ts", ".js", ".mjs", ".cjs"],
|
|
81
|
+
symlinks: true,
|
|
82
|
+
mainFields: ["es2020", "default", "module", "main"]
|
|
83
|
+
},
|
|
84
|
+
context: this._workspaceRootPath,
|
|
85
|
+
entry: {
|
|
86
|
+
main: [
|
|
87
|
+
path.resolve(this._rootPath, "src/main.ts")
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
output: {
|
|
91
|
+
clean: true,
|
|
92
|
+
path: this._parsedTsconfig.options.outDir,
|
|
93
|
+
filename: "[name].js",
|
|
94
|
+
chunkFilename: "[name].js",
|
|
95
|
+
assetModuleFilename: "resources/[name][ext][query]"
|
|
96
|
+
},
|
|
97
|
+
performance: { hints: false },
|
|
98
|
+
node: false,
|
|
99
|
+
stats: "errors-warnings",
|
|
100
|
+
module: {
|
|
101
|
+
strictExportPresence: true,
|
|
102
|
+
rules: [
|
|
103
|
+
{
|
|
104
|
+
test: /\.ts$/,
|
|
105
|
+
exclude: /node_modules/,
|
|
106
|
+
loader: "ts-loader",
|
|
107
|
+
options: {
|
|
108
|
+
compilerOptions: this._parsedTsconfig.options,
|
|
109
|
+
errorFormatter: (msg: ErrorInfo) => {
|
|
110
|
+
return SdCliBuildResultUtil.getMessage({
|
|
111
|
+
filePath: msg.file,
|
|
112
|
+
line: msg.line,
|
|
113
|
+
char: msg.character,
|
|
114
|
+
code: "TS" + msg.code.toString(),
|
|
115
|
+
severity: msg.severity,
|
|
116
|
+
message: msg.content
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico|otf|xlsx?|pptx?|docx?|zip|pfx|pkl)$/,
|
|
123
|
+
type: "asset/resource"
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
plugins: [
|
|
128
|
+
new CopyWebpackPlugin({
|
|
129
|
+
patterns: ["assets/"].map((item) => ({
|
|
130
|
+
context: this._rootPath,
|
|
131
|
+
to: item,
|
|
132
|
+
from: `src/${item}`,
|
|
133
|
+
noErrorOnMissing: true,
|
|
134
|
+
force: true,
|
|
135
|
+
globOptions: {
|
|
136
|
+
dot: true,
|
|
137
|
+
followSymbolicLinks: false,
|
|
138
|
+
ignore: [
|
|
139
|
+
".gitkeep",
|
|
140
|
+
"**/.DS_Store",
|
|
141
|
+
"**/Thumbs.db"
|
|
142
|
+
].map((i) => PathUtil.posix(this._rootPath, i))
|
|
143
|
+
},
|
|
144
|
+
priority: 0
|
|
145
|
+
}))
|
|
146
|
+
}),
|
|
147
|
+
new webpack.EnvironmentPlugin({
|
|
148
|
+
SD_VERSION: this._getNpmConfig(this._rootPath)!.version,
|
|
149
|
+
...this._config.env
|
|
150
|
+
}),
|
|
151
|
+
new ESLintWebpackPlugin({
|
|
152
|
+
context: this._rootPath,
|
|
153
|
+
extensions: ["ts", "js", "mjs", "cjs"],
|
|
154
|
+
fix: false,
|
|
155
|
+
threads: false,
|
|
156
|
+
formatter: (results: LintResult[]) => {
|
|
157
|
+
const resultMessages: string[] = [];
|
|
158
|
+
for (const result of results) {
|
|
159
|
+
for (const msg of result.messages) {
|
|
160
|
+
const severity = msg.severity === 1 ? "warning" : msg.severity === 2 ? "error" : undefined;
|
|
161
|
+
if (severity === undefined) continue;
|
|
162
|
+
|
|
163
|
+
resultMessages.push(SdCliBuildResultUtil.getMessage({
|
|
164
|
+
filePath: result.filePath,
|
|
165
|
+
line: msg.line,
|
|
166
|
+
char: msg.column,
|
|
167
|
+
code: msg.ruleId?.toString(),
|
|
168
|
+
severity,
|
|
169
|
+
message: msg.message
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return resultMessages.join(os.EOL);
|
|
174
|
+
}
|
|
175
|
+
}),
|
|
176
|
+
new webpack.ProgressPlugin({
|
|
177
|
+
handler: (per: number, msg: string, ...args: string[]) => {
|
|
178
|
+
const phaseText = msg ? ` - phase: ${msg}` : "";
|
|
179
|
+
const argsText = args.length > 0 ? ` - args: [${args.join(", ")}]` : "";
|
|
180
|
+
this._logger.debug(`Webpack 빌드 수행중...(${Math.round(per * 100)}%)${phaseText}${argsText}`);
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private _getWebpackWatchConfig(extModuleNames: string[]): webpack.Configuration {
|
|
188
|
+
const internalModuleCachePaths = FsUtil.findAllParentChildDirPaths("node_modules/!(@simplysm)", this._rootPath, this._workspaceRootPath);
|
|
189
|
+
|
|
190
|
+
return webpackMerge(this._webpackCommonConfig, {
|
|
191
|
+
mode: "development",
|
|
192
|
+
output: {
|
|
193
|
+
libraryTarget: "umd"
|
|
194
|
+
},
|
|
195
|
+
module: {
|
|
196
|
+
rules: [
|
|
197
|
+
{
|
|
198
|
+
test: /\.m?js$/,
|
|
199
|
+
enforce: "pre",
|
|
200
|
+
loader: "source-map-loader",
|
|
201
|
+
options: {
|
|
202
|
+
filterSourceMappingUrl: (mapUri: string, resourcePath: string) => {
|
|
203
|
+
return !resourcePath.includes("node_modules") || (/@simplysm[\\/]sd/).test(resourcePath);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
cache: { type: "memory", maxGenerations: 1 },
|
|
210
|
+
snapshot: {
|
|
211
|
+
immutablePaths: internalModuleCachePaths,
|
|
212
|
+
managedPaths: internalModuleCachePaths
|
|
213
|
+
},
|
|
214
|
+
optimization: {
|
|
215
|
+
moduleIds: "deterministic",
|
|
216
|
+
chunkIds: "named",
|
|
217
|
+
emitOnErrors: true
|
|
218
|
+
},
|
|
219
|
+
externals: extModuleNames
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private _getWebpackBuildConfig(extModuleNames: string[]): webpack.Configuration {
|
|
224
|
+
return webpackMerge(this._webpackCommonConfig, {
|
|
225
|
+
mode: "production",
|
|
226
|
+
output: {
|
|
227
|
+
libraryTarget: "module"
|
|
228
|
+
},
|
|
229
|
+
cache: false,
|
|
230
|
+
optimization: {
|
|
231
|
+
minimizer: [
|
|
232
|
+
new TerserPlugin({
|
|
233
|
+
terserOptions: {
|
|
234
|
+
ecma: 2020,
|
|
235
|
+
sourceMap: false,
|
|
236
|
+
keep_classnames: true,
|
|
237
|
+
keep_fnames: true,
|
|
238
|
+
ie8: false,
|
|
239
|
+
safari10: false,
|
|
240
|
+
module: true
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
],
|
|
244
|
+
moduleIds: "deterministic",
|
|
245
|
+
chunkIds: "deterministic",
|
|
246
|
+
emitOnErrors: false
|
|
247
|
+
},
|
|
248
|
+
externals: extModuleNames
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private _findExternalModules(all: boolean): { name: string; path: string }[] {
|
|
253
|
+
const loadedModuleNames: string[] = [];
|
|
254
|
+
const externalModules: { name: string; path: string }[] = [];
|
|
255
|
+
|
|
256
|
+
const fn = (currPath: string): void => {
|
|
257
|
+
const npmConfig = this._getNpmConfig(currPath);
|
|
258
|
+
if (!npmConfig) return;
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
for (const moduleName of SdCliNpmConfigUtil.getAllDependencies(npmConfig)) {
|
|
262
|
+
if (loadedModuleNames.includes(moduleName)) continue;
|
|
263
|
+
loadedModuleNames.push(moduleName);
|
|
264
|
+
|
|
265
|
+
const modulePath = FsUtil.findAllParentChildDirPaths("node_modules/" + moduleName, currPath, this._workspaceRootPath).first();
|
|
266
|
+
if (StringUtil.isNullOrEmpty(modulePath)) continue;
|
|
267
|
+
|
|
268
|
+
if (all || FsUtil.exists(path.resolve(modulePath, "binding.gyp"))) {
|
|
269
|
+
externalModules.push({ path: modulePath, name: moduleName });
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
fn(modulePath);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
fn(this._rootPath);
|
|
277
|
+
|
|
278
|
+
return externalModules.distinct();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private _getNpmConfig(pkgPath: string): INpmConfig | undefined {
|
|
282
|
+
if (!this._npmConfigMap.has(pkgPath)) {
|
|
283
|
+
this._npmConfigMap.set(pkgPath, FsUtil.readJson(path.resolve(pkgPath, "package.json")));
|
|
284
|
+
}
|
|
285
|
+
return this._npmConfigMap.get(pkgPath);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -165,7 +165,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
|
|
|
165
165
|
results.push(
|
|
166
166
|
...diagnostics
|
|
167
167
|
.filter((item) => [ts.DiagnosticCategory.Error, ts.DiagnosticCategory.Warning].includes(item.category))
|
|
168
|
-
.map((item) => SdCliBuildResultUtil.
|
|
168
|
+
.map((item) => SdCliBuildResultUtil.convertFromTsDiag(item))
|
|
169
169
|
.filterExists()
|
|
170
170
|
);
|
|
171
171
|
|
package/src/commons.ts
CHANGED
|
@@ -39,17 +39,14 @@ export interface ISdCliConfig {
|
|
|
39
39
|
localUpdates?: Record<string, string>;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export type TSdCliPackageConfig = ISdCliLibPackageConfig |
|
|
42
|
+
export type TSdCliPackageConfig = ISdCliLibPackageConfig | ISdCliServerPackageConfig;
|
|
43
43
|
|
|
44
44
|
export interface ISdCliLibPackageConfig {
|
|
45
45
|
type: "library";
|
|
46
46
|
publish?: "npm";
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export interface ISdCliNgLibPackageConfig {
|
|
50
|
-
type: "angular";
|
|
51
|
-
}
|
|
52
|
-
|
|
53
49
|
export interface ISdCliServerPackageConfig {
|
|
54
50
|
type: "server";
|
|
51
|
+
env?: Record<string, string>;
|
|
55
52
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Logger, SdProcess } from "@simplysm/sd-core-node";
|
|
2
|
+
import { SdCliPrepare } from "./SdCliPrepare";
|
|
3
|
+
|
|
4
|
+
export class SdCliNpm {
|
|
5
|
+
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
6
|
+
|
|
7
|
+
public constructor(private readonly _rootPath: string) {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public async updateAsync(): Promise<void> {
|
|
11
|
+
this._logger.debug("업데이트할 패키지 확인...");
|
|
12
|
+
await SdProcess.execAsync("npm outdated", { cwd: this._rootPath });
|
|
13
|
+
|
|
14
|
+
this._logger.debug("업데이트 시작...");
|
|
15
|
+
await SdProcess.execAsync("npm update", { cwd: this._rootPath });
|
|
16
|
+
|
|
17
|
+
this._logger.debug("sd-cli 준비...");
|
|
18
|
+
await new SdCliPrepare().prepareAsync();
|
|
19
|
+
|
|
20
|
+
this._logger.info("노드 패키지 업데이트 완료");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { FsUtil, Logger } from "@simplysm/sd-core-node";
|
|
2
|
+
|
|
3
|
+
export class SdCliPrepare {
|
|
4
|
+
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
5
|
+
|
|
6
|
+
public async prepareAsync(): Promise<void> {
|
|
7
|
+
// 타입체크 속도 지연 메시지 추가
|
|
8
|
+
const r1 = await this._modifyTypescriptCodeForTypeCheckPerformanceWarning();
|
|
9
|
+
this._logger.log(`[모듈수정] 타입체크 속도 지연 메시지 추가 (${r1 ? "O" : "X"})`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
private async _modifyTypescriptCodeForTypeCheckPerformanceWarning(): Promise<boolean> {
|
|
13
|
+
const fileUrl = await import.meta.resolve!("typescript");
|
|
14
|
+
const filePath = fileUrl.replace(/^file:\/\/\//, "");
|
|
15
|
+
const fileContent = await FsUtil.readFileAsync(filePath);
|
|
16
|
+
const modifiedFileContent = fileContent.replace(`
|
|
17
|
+
function checkSourceElement(node) {
|
|
18
|
+
if (node) {
|
|
19
|
+
var saveCurrentNode = currentNode;
|
|
20
|
+
currentNode = node;
|
|
21
|
+
instantiationCount = 0;
|
|
22
|
+
checkSourceElementWorker(node);
|
|
23
|
+
currentNode = saveCurrentNode;
|
|
24
|
+
}
|
|
25
|
+
}`, `
|
|
26
|
+
function checkSourceElement(node) {
|
|
27
|
+
if (node) {
|
|
28
|
+
const prevUsage = process.cpuUsage();
|
|
29
|
+
|
|
30
|
+
var saveCurrentNode = currentNode;
|
|
31
|
+
currentNode = node;
|
|
32
|
+
instantiationCount = 0;
|
|
33
|
+
checkSourceElementWorker(node);
|
|
34
|
+
currentNode = saveCurrentNode;
|
|
35
|
+
|
|
36
|
+
const usage = process.cpuUsage(prevUsage);
|
|
37
|
+
if (node.hasChildPerformanceWarning) {
|
|
38
|
+
node.parent.hasChildPerformanceWarning = true;
|
|
39
|
+
}
|
|
40
|
+
else if (usage.user + usage.system > 2000 * 1000 && node.kind !== 253) {
|
|
41
|
+
error(node, {
|
|
42
|
+
code: 9000,
|
|
43
|
+
category: ts.DiagnosticCategory.Warning,
|
|
44
|
+
key: "simplysm_check_source_element_performance_slow",
|
|
45
|
+
message: "소스코드 타입분석에 너무 오랜 시간이 소요됩니다. [" + Math.round((usage.user + usage.system) / 1000) + "ms/cpu, KIND: " + node.kind + "]"
|
|
46
|
+
});
|
|
47
|
+
node.parent.hasChildPerformanceWarning = true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}`);
|
|
51
|
+
await FsUtil.writeFileAsync(filePath, modifiedFileContent);
|
|
52
|
+
return fileContent !== modifiedFileContent;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -2,13 +2,13 @@ import { FsUtil, Logger, SdProcess } from "@simplysm/sd-core-node";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { INpmConfig, ISdCliConfig, ISdCliPackageBuildResult } from "../commons";
|
|
4
4
|
import { SdCliPackage } from "../packages/SdCliPackage";
|
|
5
|
-
import { Wait } from "@simplysm/sd-core-common";
|
|
5
|
+
import { Uuid, Wait } from "@simplysm/sd-core-common";
|
|
6
6
|
import os from "os";
|
|
7
7
|
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
|
|
11
|
+
import { SdCliNpm } from "./SdCliNpm";
|
|
12
12
|
|
|
13
13
|
export class SdCliWorkspace {
|
|
14
14
|
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
@@ -40,7 +40,15 @@ export class SdCliWorkspace {
|
|
|
40
40
|
changeCount++;
|
|
41
41
|
this._logger.debug(`[${pkg.name}] 빌드를 시작합니다...`);
|
|
42
42
|
})
|
|
43
|
-
.on("complete", (results) => {
|
|
43
|
+
.on("complete", async (results) => {
|
|
44
|
+
if (pkg.type === "server") {
|
|
45
|
+
if (results.some((item) => item.severity === "error")) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await this._restartServerAsync(pkg);
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
this._logger.debug(`[${pkg.name}] 빌드가 완료되었습니다.`);
|
|
45
53
|
totalResultMap.set(pkg.name, results);
|
|
46
54
|
|
|
@@ -52,40 +60,6 @@ export class SdCliWorkspace {
|
|
|
52
60
|
}
|
|
53
61
|
}, 500);
|
|
54
62
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (pkg.type === "server") {
|
|
58
|
-
pkg.on("complete", async (results) => {
|
|
59
|
-
if (results.some((item) => item.severity === "error")) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const entryFileRelPath = pkg.main;
|
|
64
|
-
if (entryFileRelPath === undefined) {
|
|
65
|
-
this._logger.error(`서버패키지(${pkg.name})의 'package.json'에서 'main'필드를 찾을 수 없습니다.`);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const entryFilePath = path.resolve(pkg.rootPath, entryFileRelPath);
|
|
69
|
-
|
|
70
|
-
this._logger.log(`서버(${pkg.name}) 재시작...`);
|
|
71
|
-
const serverInfo = this._serverInfoMap.getOrCreate(pkg.name, {});
|
|
72
|
-
if (serverInfo.server) {
|
|
73
|
-
await serverInfo.server.closeAsync();
|
|
74
|
-
delete serverInfo.server;
|
|
75
|
-
decache(entryFilePath);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
serverInfo.server = (await import(entryFilePath)) as SdServiceServer | undefined;
|
|
79
|
-
if (serverInfo.server === undefined) {
|
|
80
|
-
this._logger.error(`${entryFilePath}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
await Wait.until(() => serverInfo.server!.isOpen);
|
|
85
|
-
|
|
86
|
-
this._logger.log(`서버(${pkg.name}) 재시작 완료`);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
63
|
}
|
|
90
64
|
|
|
91
65
|
this._logger.debug("빌드를 시작합니다...");
|
|
@@ -98,6 +72,32 @@ export class SdCliWorkspace {
|
|
|
98
72
|
});
|
|
99
73
|
}
|
|
100
74
|
|
|
75
|
+
private async _restartServerAsync(pkg: SdCliPackage): Promise<void> {
|
|
76
|
+
const entryFileRelPath = pkg.main;
|
|
77
|
+
if (entryFileRelPath === undefined) {
|
|
78
|
+
this._logger.error(`서버패키지(${pkg.name})의 'package.json'에서 'main'필드를 찾을 수 없습니다.`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const entryFilePath = path.resolve(pkg.rootPath, entryFileRelPath);
|
|
82
|
+
|
|
83
|
+
this._logger.log(`서버(${pkg.name}) 재시작...`);
|
|
84
|
+
const serverInfo = this._serverInfoMap.getOrCreate(pkg.name, {});
|
|
85
|
+
if (serverInfo.server) {
|
|
86
|
+
await serverInfo.server.closeAsync();
|
|
87
|
+
delete serverInfo.server;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
serverInfo.server = (await import("file:///" + entryFilePath + "?update=" + Uuid.new().toString())).default as SdServiceServer | undefined;
|
|
91
|
+
if (!(serverInfo.server instanceof SdServiceServer)) {
|
|
92
|
+
this._logger.error(`${entryFilePath}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await Wait.until(() => serverInfo.server!.isOpen);
|
|
97
|
+
|
|
98
|
+
this._logger.log(`서버(${pkg.name}) 재시작 완료`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
101
|
public async buildAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
|
|
102
102
|
this._logger.debug("프로젝트 설정 가져오기...");
|
|
103
103
|
const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
|
|
@@ -160,6 +160,9 @@ export class SdCliWorkspace {
|
|
|
160
160
|
this._logger.debug("프로젝트 및 패키지 버전 설정...");
|
|
161
161
|
await this._upgradeVersionAsync(pkgs);
|
|
162
162
|
|
|
163
|
+
this._logger.debug("노드패키지 업데이트...");
|
|
164
|
+
await new SdCliNpm(this._rootPath).updateAsync();
|
|
165
|
+
|
|
163
166
|
// 빌드
|
|
164
167
|
if (!opt.noBuild) {
|
|
165
168
|
this._logger.debug("빌드를 시작합니다...");
|
|
@@ -5,6 +5,8 @@ import { EventEmitter } from "events";
|
|
|
5
5
|
import { ObjectUtil } from "@simplysm/sd-core-common";
|
|
6
6
|
import { SdCliTsLibBuilder } from "../builder/SdCliTsLibBuilder";
|
|
7
7
|
import { SdCliJsLibBuilder } from "../builder/SdCliJsLibBuilder";
|
|
8
|
+
import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
|
|
9
|
+
import { SdCliServerBuilder } from "../builder/SdCliServerBuilder";
|
|
8
10
|
|
|
9
11
|
export class SdCliPackage extends EventEmitter {
|
|
10
12
|
private readonly _npmConfig: INpmConfig;
|
|
@@ -26,12 +28,7 @@ export class SdCliPackage extends EventEmitter {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
public get allDependencies(): string[] {
|
|
29
|
-
return
|
|
30
|
-
...Object.keys(this._npmConfig.dependencies ?? {}),
|
|
31
|
-
...Object.keys(this._npmConfig.optionalDependencies ?? {}),
|
|
32
|
-
...Object.keys(this._npmConfig.devDependencies ?? {}),
|
|
33
|
-
...Object.keys(this._npmConfig.peerDependencies ?? {})
|
|
34
|
-
].distinct();
|
|
31
|
+
return SdCliNpmConfigUtil.getAllDependencies(this._npmConfig);
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
public constructor(private readonly _workspaceRootPath: string,
|
|
@@ -76,8 +73,15 @@ export class SdCliPackage extends EventEmitter {
|
|
|
76
73
|
await this._genBuildTsconfigAsync();
|
|
77
74
|
}
|
|
78
75
|
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
let builder: SdCliJsLibBuilder | SdCliTsLibBuilder | SdCliServerBuilder;
|
|
77
|
+
|
|
78
|
+
if (this._config.type === "library") {
|
|
79
|
+
const isAngular = isTs && this.allDependencies.includes("@angular/core");
|
|
80
|
+
builder = !isTs ? new SdCliJsLibBuilder(this.rootPath) : new SdCliTsLibBuilder(this.rootPath, isAngular);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
builder = new SdCliServerBuilder(this.rootPath, this._config, this._workspaceRootPath);
|
|
84
|
+
}
|
|
81
85
|
|
|
82
86
|
await builder
|
|
83
87
|
.on("change", () => {
|
|
@@ -2,9 +2,10 @@ import ts from "typescript";
|
|
|
2
2
|
import * as os from "os";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { ISdCliPackageBuildResult } from "../commons";
|
|
5
|
+
import webpack from "webpack";
|
|
5
6
|
|
|
6
7
|
export class SdCliBuildResultUtil {
|
|
7
|
-
public static
|
|
8
|
+
public static convertFromTsDiag(diag: ts.Diagnostic): ISdCliPackageBuildResult | undefined {
|
|
8
9
|
const severity = diag.category === ts.DiagnosticCategory.Error ? "error"
|
|
9
10
|
: diag.category === ts.DiagnosticCategory.Warning ? "warning"
|
|
10
11
|
: undefined;
|
|
@@ -29,6 +30,35 @@ export class SdCliBuildResultUtil {
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
public static convertFromWebpackStats(stats: webpack.Stats): ISdCliPackageBuildResult[] {
|
|
34
|
+
const results: ISdCliPackageBuildResult[] = [];
|
|
35
|
+
|
|
36
|
+
for (const statWarn of stats.compilation.warnings) {
|
|
37
|
+
if (stats.compilation.options.ignoreWarnings?.some((ignoreWarning) => ignoreWarning(statWarn, stats.compilation))) continue;
|
|
38
|
+
|
|
39
|
+
results.push(this._convertFromWebpackError("warning", statWarn));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const statErr of stats.compilation.errors) {
|
|
43
|
+
results.push(this._convertFromWebpackError("error", statErr));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private static _convertFromWebpackError(severity: "warning" | "error", err: webpack.WebpackError): ISdCliPackageBuildResult {
|
|
50
|
+
console.log(err);
|
|
51
|
+
return {
|
|
52
|
+
filePath: err.file,
|
|
53
|
+
line: err.loc["start"].line,
|
|
54
|
+
char: err.loc["start"].column,
|
|
55
|
+
code: err.name,
|
|
56
|
+
severity,
|
|
57
|
+
message: err.message
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
32
62
|
public static getMessage(result: ISdCliPackageBuildResult): string {
|
|
33
63
|
let str = "";
|
|
34
64
|
if (result.filePath !== undefined) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { INpmConfig } from "../commons";
|
|
2
|
+
|
|
3
|
+
export class SdCliNpmConfigUtil {
|
|
4
|
+
public static getAllDependencies(npmConfig: INpmConfig): string[] {
|
|
5
|
+
return [
|
|
6
|
+
...Object.keys(npmConfig.dependencies ?? {}),
|
|
7
|
+
...Object.keys(npmConfig.optionalDependencies ?? {}),
|
|
8
|
+
...Object.keys(npmConfig.devDependencies ?? {}),
|
|
9
|
+
...Object.keys(npmConfig.peerDependencies ?? {})
|
|
10
|
+
].distinct();
|
|
11
|
+
}
|
|
12
|
+
}
|