@simplysm/sd-cli 7.0.24 → 7.0.38
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.mjs +2 -1
- package/dist/build-tool/SdCliNgCacheCompilerHost.mjs +2 -2
- package/dist/builder/SdCliClientBuilder.d.ts +20 -0
- package/dist/builder/SdCliClientBuilder.mjs +417 -0
- package/dist/builder/SdCliJsLibBuilder.mjs +2 -2
- package/dist/builder/SdCliServerBuilder.d.ts +7 -4
- package/dist/builder/SdCliServerBuilder.mjs +232 -92
- package/dist/builder/SdCliTsLibBuilder.d.ts +5 -3
- package/dist/builder/SdCliTsLibBuilder.mjs +17 -18
- package/dist/commons.d.ts +13 -1
- package/dist/entry-points/SdCliLocalUpdate.mjs +15 -9
- package/dist/entry-points/SdCliNpm.mjs +8 -4
- package/dist/entry-points/SdCliPrepare.mjs +3 -2
- package/dist/entry-points/SdCliWorkspace.d.ts +1 -0
- package/dist/entry-points/SdCliWorkspace.mjs +55 -23
- package/dist/packages/SdCliPackage.d.ts +5 -4
- package/dist/packages/SdCliPackage.mjs +27 -28
- package/dist/utils/SdCliBuildResultUtil.mjs +3 -4
- package/dist/utils/SdCliNpmConfigUtil.d.ts +4 -1
- package/dist/utils/SdCliNpmConfigUtil.mjs +12 -8
- package/package.json +19 -8
- package/src/bin/sd-cli.ts +1 -0
- package/src/build-tool/SdCliNgCacheCompilerHost.ts +1 -1
- package/src/builder/SdCliClientBuilder.ts +451 -0
- package/src/builder/SdCliJsLibBuilder.ts +1 -1
- package/src/builder/SdCliServerBuilder.ts +260 -91
- package/src/builder/SdCliTsLibBuilder.ts +26 -21
- package/src/commons.ts +10 -1
- package/src/entry-points/SdCliLocalUpdate.ts +14 -8
- package/src/entry-points/SdCliNpm.ts +7 -3
- package/src/entry-points/SdCliPrepare.ts +2 -1
- package/src/entry-points/SdCliWorkspace.ts +63 -24
- package/src/packages/SdCliPackage.ts +29 -34
- package/src/utils/SdCliBuildResultUtil.ts +2 -3
- package/src/utils/SdCliNpmConfigUtil.ts +11 -7
|
@@ -8,17 +8,17 @@ import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
|
|
|
8
8
|
import { ErrorInfo } from "ts-loader/dist/interfaces";
|
|
9
9
|
import os from "os";
|
|
10
10
|
import { ESLint } from "eslint";
|
|
11
|
-
import webpackMerge from "webpack-merge";
|
|
12
11
|
import TerserPlugin from "terser-webpack-plugin";
|
|
13
|
-
import { StringUtil } from "@simplysm/sd-core-common";
|
|
14
|
-
import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
|
|
12
|
+
import { ObjectUtil, StringUtil } from "@simplysm/sd-core-common";
|
|
15
13
|
import ESLintWebpackPlugin from "eslint-webpack-plugin";
|
|
16
14
|
import CopyWebpackPlugin from "copy-webpack-plugin";
|
|
15
|
+
import { LicenseWebpackPlugin } from "license-webpack-plugin";
|
|
17
16
|
import LintResult = ESLint.LintResult;
|
|
18
17
|
|
|
19
18
|
export class SdCliServerBuilder extends EventEmitter {
|
|
20
19
|
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
21
20
|
|
|
21
|
+
private readonly _tsconfigFilePath: string;
|
|
22
22
|
private readonly _parsedTsconfig: ts.ParsedCommandLine;
|
|
23
23
|
private readonly _npmConfigMap = new Map<string, INpmConfig>();
|
|
24
24
|
|
|
@@ -28,8 +28,8 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
28
28
|
super();
|
|
29
29
|
|
|
30
30
|
// tsconfig
|
|
31
|
-
|
|
32
|
-
const tsconfig = FsUtil.readJson(
|
|
31
|
+
this._tsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
|
|
32
|
+
const tsconfig = FsUtil.readJson(this._tsconfigFilePath);
|
|
33
33
|
this._parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._rootPath);
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -40,18 +40,46 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
public async watchAsync(): Promise<void> {
|
|
43
|
+
// DIST 비우기
|
|
44
|
+
await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
|
|
45
|
+
|
|
46
|
+
// 빌드 준비
|
|
47
|
+
const extModuleNames = this._getExternalModuleNames();
|
|
48
|
+
const webpackConfig = this._getWebpackConfig(true, extModuleNames);
|
|
49
|
+
const compiler = webpack(webpackConfig);
|
|
50
|
+
await new Promise<void>((resolve, reject) => {
|
|
51
|
+
compiler.hooks.watchRun.tapAsync(this.constructor.name, (args, callback) => {
|
|
52
|
+
this.emit("change");
|
|
53
|
+
this._logger.debug("Webpack 빌드 수행...");
|
|
54
|
+
callback();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
compiler.watch({}, async (err, stats) => {
|
|
58
|
+
if (err != null || stats == null) {
|
|
59
|
+
reject(err);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// .config.json 파일 쓰기
|
|
64
|
+
await this._writeDistConfigFileAsync();
|
|
65
|
+
|
|
66
|
+
// 결과 반환
|
|
67
|
+
this._logger.debug("Webpack 빌드 완료");
|
|
68
|
+
const results = SdCliBuildResultUtil.convertFromWebpackStats(stats);
|
|
69
|
+
this.emit("complete", results);
|
|
70
|
+
resolve();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
43
73
|
}
|
|
44
74
|
|
|
45
75
|
public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
|
|
46
76
|
// DIST 비우기
|
|
47
77
|
await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
|
|
48
78
|
|
|
49
|
-
// 빌드 준비
|
|
50
|
-
const extModuleNames = this._findExternalModules(false).map((item) => item.name);
|
|
51
|
-
|
|
52
79
|
// 빌드
|
|
53
80
|
this._logger.debug("Webpack 빌드 수행...");
|
|
54
|
-
const
|
|
81
|
+
const extModuleNames = this._getExternalModuleNames();
|
|
82
|
+
const webpackConfig = this._getWebpackConfig(false, extModuleNames);
|
|
55
83
|
const compiler = webpack(webpackConfig);
|
|
56
84
|
const buildResults = await new Promise<ISdCliPackageBuildResult[]>((resolve, reject) => {
|
|
57
85
|
compiler.run((err, stats) => {
|
|
@@ -60,18 +88,127 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
60
88
|
return;
|
|
61
89
|
}
|
|
62
90
|
|
|
63
|
-
// 결과
|
|
91
|
+
// 결과 반환
|
|
64
92
|
const results = SdCliBuildResultUtil.convertFromWebpackStats(stats);
|
|
65
93
|
resolve(results);
|
|
66
94
|
});
|
|
67
95
|
});
|
|
68
|
-
this._logger.debug("Webpack 빌드 완료");
|
|
69
96
|
|
|
97
|
+
// .config.json 파일 쓰기
|
|
98
|
+
await this._writeDistConfigFileAsync();
|
|
99
|
+
|
|
100
|
+
// pm2.json 파일 쓰기
|
|
101
|
+
await this._writeDistPm2ConfigFileAsync();
|
|
102
|
+
|
|
103
|
+
// iis 파일 쓰기
|
|
104
|
+
await this._writeDistIisConfigFileAsync();
|
|
105
|
+
|
|
106
|
+
// 배포용 package.json 파일 생성
|
|
107
|
+
await this._writeDistNpmConfigFileAsync(extModuleNames);
|
|
108
|
+
|
|
109
|
+
// 마무리
|
|
110
|
+
this._logger.debug("Webpack 빌드 완료");
|
|
70
111
|
return buildResults;
|
|
71
112
|
}
|
|
72
113
|
|
|
73
|
-
private
|
|
114
|
+
private async _writeDistConfigFileAsync(): Promise<void> {
|
|
115
|
+
const configDistPath = path.resolve(this._parsedTsconfig.options.outDir!, ".config.json");
|
|
116
|
+
await FsUtil.writeFileAsync(configDistPath, JSON.stringify(this._config.configs ?? {}, undefined, 2));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private async _writeDistPm2ConfigFileAsync(): Promise<void> {
|
|
120
|
+
if (this._config.pm2 === undefined || this._config.pm2 === false) return;
|
|
121
|
+
|
|
122
|
+
const npmConfig = this._getNpmConfig(this._rootPath)!;
|
|
123
|
+
const pm2DistPath = path.resolve(this._parsedTsconfig.options.outDir!, "pm2.json");
|
|
124
|
+
await FsUtil.writeFileAsync(
|
|
125
|
+
pm2DistPath,
|
|
126
|
+
JSON.stringify(
|
|
127
|
+
ObjectUtil.merge(
|
|
128
|
+
{
|
|
129
|
+
"name": npmConfig.name.replace(/@/g, "").replace(/\//g, "-"),
|
|
130
|
+
"script": path.basename(path.resolve(this._parsedTsconfig.options.outDir!, "main.mjs")),
|
|
131
|
+
"watch": true,
|
|
132
|
+
"watch_delay": 2000,
|
|
133
|
+
"ignore_watch": [
|
|
134
|
+
"node_modules",
|
|
135
|
+
"www"
|
|
136
|
+
].distinct(),
|
|
137
|
+
"interpreter": "node@" + process.versions.node,
|
|
138
|
+
"env": {
|
|
139
|
+
NODE_ENV: "production",
|
|
140
|
+
SD_VERSION: npmConfig.version,
|
|
141
|
+
TZ: "Asia/Seoul",
|
|
142
|
+
...this._config.env ? this._config.env : {}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
(typeof this._config.pm2 !== "boolean") ? this._config.pm2 : {},
|
|
146
|
+
{
|
|
147
|
+
arrayProcess: "concat"
|
|
148
|
+
}),
|
|
149
|
+
undefined,
|
|
150
|
+
2
|
|
151
|
+
)
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private async _writeDistIisConfigFileAsync(): Promise<void> {
|
|
156
|
+
if (this._config.iis === undefined || this._config.iis === false) return;
|
|
157
|
+
|
|
158
|
+
const iisDistPath = path.resolve(this._parsedTsconfig.options.outDir!, "web.config");
|
|
159
|
+
const serverExeFilePath = (this._config.iis !== true && "serverExeFilePath" in this._config.iis)
|
|
160
|
+
? (this._config.iis.serverExeFilePath ?? "C:\\Program Files\\nodejs\\node.exe")
|
|
161
|
+
: "C:\\Program Files\\nodejs\\node.exe";
|
|
162
|
+
await FsUtil.writeFileAsync(iisDistPath, `
|
|
163
|
+
<configuration>
|
|
164
|
+
<system.webServer>
|
|
165
|
+
<webSocket enabled="false" />
|
|
166
|
+
<handlers>
|
|
167
|
+
<add name="iisnode" path="main.js" verb="*" modules="iisnode" />
|
|
168
|
+
</handlers>
|
|
169
|
+
<iisnode nodeProcessCommandLine="${serverExeFilePath}"
|
|
170
|
+
watchedFiles="web.config;*.js"
|
|
171
|
+
loggingEnabled="true"
|
|
172
|
+
devErrorsEnabled="true" />
|
|
173
|
+
<rewrite>
|
|
174
|
+
<rules>
|
|
175
|
+
<rule name="main">
|
|
176
|
+
<action type="Rewrite" url="main.mjs" />
|
|
177
|
+
</rule>
|
|
178
|
+
</rules>
|
|
179
|
+
</rewrite>
|
|
180
|
+
<httpErrors errorMode="Detailed" />
|
|
181
|
+
</system.webServer>
|
|
182
|
+
</configuration>`.trim());
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private async _writeDistNpmConfigFileAsync(deps: string[]): Promise<void> {
|
|
186
|
+
const distNpmConfig = ObjectUtil.clone(this._getNpmConfig(this._rootPath))!;
|
|
187
|
+
distNpmConfig.dependencies = {};
|
|
188
|
+
for (const dep of deps) {
|
|
189
|
+
distNpmConfig.dependencies[dep] = "*";
|
|
190
|
+
}
|
|
191
|
+
delete distNpmConfig.optionalDependencies;
|
|
192
|
+
delete distNpmConfig.devDependencies;
|
|
193
|
+
delete distNpmConfig.peerDependencies;
|
|
194
|
+
|
|
195
|
+
if (this._config.pm2 !== undefined) {
|
|
196
|
+
distNpmConfig.scripts = { "start": "pm2 start pm2.json" };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
await FsUtil.writeFileAsync(
|
|
200
|
+
path.resolve(this._parsedTsconfig.options.outDir!, "package.json"),
|
|
201
|
+
JSON.stringify(distNpmConfig, undefined, 2)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private _getWebpackConfig(watch: boolean, extModuleNames: string[]): webpack.Configuration {
|
|
206
|
+
const internalModuleCachePaths = watch
|
|
207
|
+
? FsUtil.findAllParentChildDirPaths("node_modules/!(@simplysm)", this._rootPath, this._workspaceRootPath)
|
|
208
|
+
: undefined;
|
|
209
|
+
|
|
74
210
|
return {
|
|
211
|
+
mode: watch ? "development" : "production",
|
|
75
212
|
devtool: false,
|
|
76
213
|
target: ["node", "es2020"],
|
|
77
214
|
profile: false,
|
|
@@ -90,22 +227,82 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
90
227
|
output: {
|
|
91
228
|
clean: true,
|
|
92
229
|
path: this._parsedTsconfig.options.outDir,
|
|
93
|
-
filename: "[name].
|
|
94
|
-
chunkFilename: "[name].
|
|
95
|
-
assetModuleFilename: "
|
|
230
|
+
filename: "[name].mjs",
|
|
231
|
+
chunkFilename: "[name].mjs",
|
|
232
|
+
assetModuleFilename: "res/[name][ext][query]",
|
|
233
|
+
libraryTarget: "module"
|
|
234
|
+
},
|
|
235
|
+
experiments: {
|
|
236
|
+
outputModule: true
|
|
96
237
|
},
|
|
97
238
|
performance: { hints: false },
|
|
98
|
-
node:
|
|
239
|
+
node: {
|
|
240
|
+
__dirname: true
|
|
241
|
+
},
|
|
99
242
|
stats: "errors-warnings",
|
|
243
|
+
externals: extModuleNames,
|
|
244
|
+
...watch ? {
|
|
245
|
+
cache: { type: "memory", maxGenerations: 1 },
|
|
246
|
+
snapshot: {
|
|
247
|
+
immutablePaths: internalModuleCachePaths,
|
|
248
|
+
managedPaths: internalModuleCachePaths
|
|
249
|
+
}
|
|
250
|
+
} : {
|
|
251
|
+
cache: false
|
|
252
|
+
},
|
|
253
|
+
optimization: {
|
|
254
|
+
...watch ? {} : {
|
|
255
|
+
minimize: true,
|
|
256
|
+
minimizer: [
|
|
257
|
+
new TerserPlugin({
|
|
258
|
+
extractComments: false,
|
|
259
|
+
terserOptions: {
|
|
260
|
+
compress: true,
|
|
261
|
+
ecma: 2020,
|
|
262
|
+
sourceMap: false,
|
|
263
|
+
keep_classnames: true,
|
|
264
|
+
keep_fnames: true,
|
|
265
|
+
ie8: false,
|
|
266
|
+
safari10: false,
|
|
267
|
+
module: true,
|
|
268
|
+
format: {
|
|
269
|
+
comments: false
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
]
|
|
274
|
+
},
|
|
275
|
+
moduleIds: "deterministic",
|
|
276
|
+
chunkIds: watch ? "named" : "deterministic",
|
|
277
|
+
emitOnErrors: watch
|
|
278
|
+
},
|
|
100
279
|
module: {
|
|
101
280
|
strictExportPresence: true,
|
|
102
281
|
rules: [
|
|
282
|
+
{
|
|
283
|
+
test: /\.m?js/,
|
|
284
|
+
resolve: {
|
|
285
|
+
fullySpecified: false
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
...watch ? [
|
|
289
|
+
{
|
|
290
|
+
test: /\.m?js$/,
|
|
291
|
+
enforce: "pre" as const,
|
|
292
|
+
loader: "source-map-loader",
|
|
293
|
+
options: {
|
|
294
|
+
filterSourceMappingUrl: (mapUri: string, resourcePath: string) => {
|
|
295
|
+
return !resourcePath.includes("node_modules") || (/@simplysm[\\/]sd/).test(resourcePath);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
] : [],
|
|
103
300
|
{
|
|
104
301
|
test: /\.ts$/,
|
|
105
302
|
exclude: /node_modules/,
|
|
106
303
|
loader: "ts-loader",
|
|
107
304
|
options: {
|
|
108
|
-
|
|
305
|
+
configFile: this._tsconfigFilePath,
|
|
109
306
|
errorFormatter: (msg: ErrorInfo) => {
|
|
110
307
|
return SdCliBuildResultUtil.getMessage({
|
|
111
308
|
filePath: msg.file,
|
|
@@ -125,6 +322,14 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
125
322
|
]
|
|
126
323
|
},
|
|
127
324
|
plugins: [
|
|
325
|
+
...watch ? [] : [
|
|
326
|
+
new LicenseWebpackPlugin({
|
|
327
|
+
stats: { warnings: false, errors: false },
|
|
328
|
+
perChunkOutput: false,
|
|
329
|
+
outputFilename: "3rd_party_licenses.txt",
|
|
330
|
+
skipChildCompilers: true
|
|
331
|
+
}) as any
|
|
332
|
+
],
|
|
128
333
|
new CopyWebpackPlugin({
|
|
129
334
|
patterns: ["assets/"].map((item) => ({
|
|
130
335
|
context: this._rootPath,
|
|
@@ -150,6 +355,8 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
150
355
|
}),
|
|
151
356
|
new ESLintWebpackPlugin({
|
|
152
357
|
context: this._rootPath,
|
|
358
|
+
eslintPath: path.resolve(this._workspaceRootPath, "node_modules", "eslint"),
|
|
359
|
+
exclude: ["node_modules"],
|
|
153
360
|
extensions: ["ts", "js", "mjs", "cjs"],
|
|
154
361
|
fix: false,
|
|
155
362
|
threads: false,
|
|
@@ -172,110 +379,72 @@ export class SdCliServerBuilder extends EventEmitter {
|
|
|
172
379
|
}
|
|
173
380
|
return resultMessages.join(os.EOL);
|
|
174
381
|
}
|
|
175
|
-
})
|
|
382
|
+
})/*,
|
|
176
383
|
new webpack.ProgressPlugin({
|
|
177
384
|
handler: (per: number, msg: string, ...args: string[]) => {
|
|
178
385
|
const phaseText = msg ? ` - phase: ${msg}` : "";
|
|
179
386
|
const argsText = args.length > 0 ? ` - args: [${args.join(", ")}]` : "";
|
|
180
387
|
this._logger.debug(`Webpack 빌드 수행중...(${Math.round(per * 100)}%)${phaseText}${argsText}`);
|
|
181
388
|
}
|
|
182
|
-
})
|
|
389
|
+
})*/
|
|
183
390
|
]
|
|
184
391
|
};
|
|
185
392
|
}
|
|
186
393
|
|
|
187
|
-
private
|
|
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 }[] {
|
|
394
|
+
private _getExternalModuleNames(): string[] {
|
|
253
395
|
const loadedModuleNames: string[] = [];
|
|
254
|
-
const
|
|
396
|
+
const resultSet = new Set<string>();
|
|
255
397
|
|
|
256
398
|
const fn = (currPath: string): void => {
|
|
257
399
|
const npmConfig = this._getNpmConfig(currPath);
|
|
258
400
|
if (!npmConfig) return;
|
|
259
401
|
|
|
402
|
+
const moduleNames = [
|
|
403
|
+
...Object.keys(npmConfig.dependencies ?? {}),
|
|
404
|
+
...Object.keys(npmConfig.peerDependencies ?? {}).filter((item) => !npmConfig.peerDependenciesMeta?.[item].optional)
|
|
405
|
+
];
|
|
406
|
+
const optModuleNames = [
|
|
407
|
+
...Object.keys(npmConfig.optionalDependencies ?? {}),
|
|
408
|
+
...Object.keys(npmConfig.peerDependencies ?? {}).filter((item) => npmConfig.peerDependenciesMeta?.[item].optional)
|
|
409
|
+
].distinct();
|
|
260
410
|
|
|
261
|
-
for (const moduleName of
|
|
411
|
+
for (const moduleName of moduleNames) {
|
|
262
412
|
if (loadedModuleNames.includes(moduleName)) continue;
|
|
263
413
|
loadedModuleNames.push(moduleName);
|
|
264
414
|
|
|
265
415
|
const modulePath = FsUtil.findAllParentChildDirPaths("node_modules/" + moduleName, currPath, this._workspaceRootPath).first();
|
|
266
|
-
if (StringUtil.isNullOrEmpty(modulePath))
|
|
416
|
+
if (StringUtil.isNullOrEmpty(modulePath)) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
267
419
|
|
|
268
|
-
if (
|
|
269
|
-
|
|
420
|
+
if (FsUtil.exists(path.resolve(modulePath, "binding.gyp"))) {
|
|
421
|
+
resultSet.add(moduleName);
|
|
270
422
|
}
|
|
271
423
|
|
|
272
424
|
fn(modulePath);
|
|
273
425
|
}
|
|
426
|
+
|
|
427
|
+
for (const optModuleName of optModuleNames) {
|
|
428
|
+
if (loadedModuleNames.includes(optModuleName)) continue;
|
|
429
|
+
loadedModuleNames.push(optModuleName);
|
|
430
|
+
|
|
431
|
+
const optModulePath = FsUtil.findAllParentChildDirPaths("node_modules/" + optModuleName, currPath, this._workspaceRootPath).first();
|
|
432
|
+
if (StringUtil.isNullOrEmpty(optModulePath)) {
|
|
433
|
+
resultSet.add(optModuleName);
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (FsUtil.exists(path.resolve(optModulePath, "binding.gyp"))) {
|
|
438
|
+
resultSet.add(optModuleName);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
fn(optModulePath);
|
|
442
|
+
}
|
|
274
443
|
};
|
|
275
444
|
|
|
276
445
|
fn(this._rootPath);
|
|
277
446
|
|
|
278
|
-
return
|
|
447
|
+
return Array.from(resultSet.values());
|
|
279
448
|
}
|
|
280
449
|
|
|
281
450
|
private _getNpmConfig(pkgPath: string): INpmConfig | undefined {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ISdCliPackageBuildResult } from "../commons";
|
|
1
|
+
import { INpmConfig, ISdCliPackageBuildResult } from "../commons";
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
import { FsUtil, Logger, PathUtil, SdFsWatcher } from "@simplysm/sd-core-node";
|
|
@@ -11,6 +11,7 @@ import { SdCliPackageLinter } from "../build-tool/SdCliPackageLinter";
|
|
|
11
11
|
import { SdCliCacheCompilerHost } from "../build-tool/SdCliCacheCompilerHost";
|
|
12
12
|
import { SdCliNgCacheCompilerHost } from "../build-tool/SdCliNgCacheCompilerHost";
|
|
13
13
|
import { NgCompiler } from "@angular/compiler-cli/src/ngtsc/core";
|
|
14
|
+
import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
|
|
14
15
|
|
|
15
16
|
export class SdCliTsLibBuilder extends EventEmitter {
|
|
16
17
|
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
@@ -26,10 +27,26 @@ export class SdCliTsLibBuilder extends EventEmitter {
|
|
|
26
27
|
private _ngProgram?: NgtscProgram;
|
|
27
28
|
private _builder?: ts.EmitAndSemanticDiagnosticsBuilderProgram;
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
private readonly _tsconfigFilePath: string;
|
|
31
|
+
private readonly _parsedTsconfig: ts.ParsedCommandLine;
|
|
32
|
+
private readonly _npmConfig: INpmConfig;
|
|
33
|
+
|
|
34
|
+
private readonly _isAngular: boolean;
|
|
35
|
+
|
|
36
|
+
public constructor(private readonly _rootPath) {
|
|
31
37
|
super();
|
|
32
38
|
this._linter = new SdCliPackageLinter(this._rootPath);
|
|
39
|
+
|
|
40
|
+
// tsconfig
|
|
41
|
+
this._tsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
|
|
42
|
+
const tsconfig = FsUtil.readJson(this._tsconfigFilePath);
|
|
43
|
+
this._parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._rootPath);
|
|
44
|
+
|
|
45
|
+
// package.json
|
|
46
|
+
this._npmConfig = FsUtil.readJson(path.resolve(this._rootPath, "package.json"));
|
|
47
|
+
|
|
48
|
+
// else
|
|
49
|
+
this._isAngular = SdCliNpmConfigUtil.getDependencies(this._npmConfig).defaults.includes("@angular/core");
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
public override on(event: "change", listener: () => void): this;
|
|
@@ -41,18 +58,15 @@ export class SdCliTsLibBuilder extends EventEmitter {
|
|
|
41
58
|
public async watchAsync(): Promise<void> {
|
|
42
59
|
this.emit("change");
|
|
43
60
|
|
|
44
|
-
// TSCONFIG 읽기
|
|
45
|
-
const parsedTsconfig = await this._getParsedTsconfigAsync();
|
|
46
|
-
|
|
47
61
|
// DIST 비우기
|
|
48
|
-
await FsUtil.removeAsync(
|
|
62
|
+
await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
|
|
49
63
|
|
|
50
64
|
// 프로그램 리로드
|
|
51
|
-
const buildPack = this._createSdBuildPack(
|
|
65
|
+
const buildPack = this._createSdBuildPack(this._parsedTsconfig);
|
|
52
66
|
|
|
53
67
|
const relatedPaths = await this.getAllRelatedPathsAsync();
|
|
54
68
|
const watcher = SdFsWatcher.watch(relatedPaths);
|
|
55
|
-
watcher.onChange(async (changeInfos) => {
|
|
69
|
+
watcher.onChange({}, async (changeInfos) => {
|
|
56
70
|
const changeFilePaths = changeInfos.filter((item) => ["add", "change", "unlink"].includes(item.event)).map((item) => item.path);
|
|
57
71
|
if (changeFilePaths.length === 0) return;
|
|
58
72
|
|
|
@@ -65,7 +79,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
|
|
|
65
79
|
}
|
|
66
80
|
|
|
67
81
|
// 빌드
|
|
68
|
-
const watchBuildPack = this._createSdBuildPack(
|
|
82
|
+
const watchBuildPack = this._createSdBuildPack(this._parsedTsconfig);
|
|
69
83
|
|
|
70
84
|
// 린트
|
|
71
85
|
const watchBuildResults = await this._runBuilderAsync(watchBuildPack.builder, watchBuildPack.ngCompiler);
|
|
@@ -90,14 +104,11 @@ export class SdCliTsLibBuilder extends EventEmitter {
|
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
|
|
93
|
-
// TSCONFIG 읽기
|
|
94
|
-
const parsedTsconfig = await this._getParsedTsconfigAsync();
|
|
95
|
-
|
|
96
107
|
// DIST 비우기
|
|
97
|
-
await FsUtil.removeAsync(
|
|
108
|
+
await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
|
|
98
109
|
|
|
99
110
|
// 프로그램 리로드
|
|
100
|
-
const buildPack = this._createSdBuildPack(
|
|
111
|
+
const buildPack = this._createSdBuildPack(this._parsedTsconfig);
|
|
101
112
|
|
|
102
113
|
// 빌드
|
|
103
114
|
const buildResults = await this._runBuilderAsync(buildPack.builder, buildPack.ngCompiler);
|
|
@@ -312,12 +323,6 @@ export class SdCliTsLibBuilder extends EventEmitter {
|
|
|
312
323
|
return compilerHost;
|
|
313
324
|
}
|
|
314
325
|
}
|
|
315
|
-
|
|
316
|
-
private async _getParsedTsconfigAsync(): Promise<ts.ParsedCommandLine> {
|
|
317
|
-
const tsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
|
|
318
|
-
const tsconfig = await FsUtil.readJsonAsync(tsconfigFilePath);
|
|
319
|
-
return ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._rootPath);
|
|
320
|
-
}
|
|
321
326
|
}
|
|
322
327
|
|
|
323
328
|
interface IFileCache {
|
package/src/commons.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface INpmConfig {
|
|
|
15
15
|
optionalDependencies?: Record<string, string>;
|
|
16
16
|
devDependencies?: Record<string, string>;
|
|
17
17
|
peerDependencies?: Record<string, string>;
|
|
18
|
+
peerDependenciesMeta?: Record<string, { optional?: boolean }>;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export interface ITsconfig {
|
|
@@ -39,7 +40,7 @@ export interface ISdCliConfig {
|
|
|
39
40
|
localUpdates?: Record<string, string>;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
export type TSdCliPackageConfig = ISdCliLibPackageConfig | ISdCliServerPackageConfig;
|
|
43
|
+
export type TSdCliPackageConfig = ISdCliLibPackageConfig | ISdCliServerPackageConfig | ISdCliClientPackageConfig;
|
|
43
44
|
|
|
44
45
|
export interface ISdCliLibPackageConfig {
|
|
45
46
|
type: "library";
|
|
@@ -49,4 +50,12 @@ export interface ISdCliLibPackageConfig {
|
|
|
49
50
|
export interface ISdCliServerPackageConfig {
|
|
50
51
|
type: "server";
|
|
51
52
|
env?: Record<string, string>;
|
|
53
|
+
configs?: Record<string, any>;
|
|
54
|
+
pm2?: Record<string, any> | boolean;
|
|
55
|
+
iis?: { serverExeFilePath?: string } | boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ISdCliClientPackageConfig {
|
|
59
|
+
type: "client";
|
|
60
|
+
server: string;
|
|
52
61
|
}
|
|
@@ -40,19 +40,25 @@ export class SdCliLocalUpdate {
|
|
|
40
40
|
const watchPaths = (await updatePathInfos.mapManyAsync(async (item) => await this._getWatchPathsAsync(item.source))).distinct();
|
|
41
41
|
|
|
42
42
|
const watcher = SdFsWatcher.watch(watchPaths);
|
|
43
|
-
watcher.onChange(async (changeInfos) => {
|
|
43
|
+
watcher.onChange({ delay: 1000 }, async (changeInfos) => {
|
|
44
44
|
const changeFilePaths = changeInfos.filter((item) => ["add", "change", "unlink"].includes(item.event)).map((item) => item.path);
|
|
45
45
|
if (changeFilePaths.length === 0) return;
|
|
46
46
|
|
|
47
47
|
this._logger.log("로컬 라이브러리 변경감지...");
|
|
48
48
|
for (const changedFilePath of changeFilePaths) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
if (!FsUtil.exists(changedFilePath)) continue;
|
|
50
|
+
|
|
51
|
+
for (const updatePathInfo of updatePathInfos) {
|
|
52
|
+
if (!PathUtil.isChildPath(changedFilePath, updatePathInfo.source)) continue;
|
|
53
|
+
|
|
54
|
+
const sourceRelPath = path.relative(updatePathInfo.source, changedFilePath);
|
|
55
|
+
if (sourceRelPath.includes("node_modules")) continue;
|
|
56
|
+
if (sourceRelPath.includes("package.json")) continue;
|
|
57
|
+
|
|
58
|
+
const targetFilePath = path.resolve(updatePathInfo.target, sourceRelPath);
|
|
59
|
+
|
|
60
|
+
this._logger.debug(`변경파일감지(복사): ${changedFilePath} => ${targetFilePath}`);
|
|
61
|
+
await FsUtil.copyAsync(changedFilePath, targetFilePath);
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
64
|
|
|
@@ -8,11 +8,15 @@ export class SdCliNpm {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
public async updateAsync(): Promise<void> {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
try {
|
|
12
|
+
this._logger.debug("업데이트할 패키지 확인...");
|
|
13
|
+
await SdProcess.spawnAsync("npm outdated", { cwd: this._rootPath });
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
}
|
|
13
17
|
|
|
14
18
|
this._logger.debug("업데이트 시작...");
|
|
15
|
-
await SdProcess.
|
|
19
|
+
await SdProcess.spawnAsync("npm update", { cwd: this._rootPath });
|
|
16
20
|
|
|
17
21
|
this._logger.debug("sd-cli 준비...");
|
|
18
22
|
await new SdCliPrepare().prepareAsync();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FsUtil, Logger } from "@simplysm/sd-core-node";
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
2
3
|
|
|
3
4
|
export class SdCliPrepare {
|
|
4
5
|
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
@@ -11,7 +12,7 @@ export class SdCliPrepare {
|
|
|
11
12
|
|
|
12
13
|
private async _modifyTypescriptCodeForTypeCheckPerformanceWarning(): Promise<boolean> {
|
|
13
14
|
const fileUrl = await import.meta.resolve!("typescript");
|
|
14
|
-
const filePath = fileUrl
|
|
15
|
+
const filePath = fileURLToPath(fileUrl);
|
|
15
16
|
const fileContent = await FsUtil.readFileAsync(filePath);
|
|
16
17
|
const modifiedFileContent = fileContent.replace(`
|
|
17
18
|
function checkSourceElement(node) {
|