@simplysm/sd-cli 7.0.25 → 7.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.eslintrc.cjs +2 -2
  2. package/dist/bin/sd-cli.mjs +3 -1
  3. package/dist/build-tool/SdCliNgCacheCompilerHost.mjs +3 -3
  4. package/dist/builder/SdCliClientBuilder.d.ts +20 -0
  5. package/dist/builder/SdCliClientBuilder.mjs +417 -0
  6. package/dist/builder/SdCliJsLibBuilder.mjs +2 -2
  7. package/dist/builder/SdCliServerBuilder.d.ts +6 -4
  8. package/dist/builder/SdCliServerBuilder.mjs +175 -100
  9. package/dist/builder/SdCliTsLibBuilder.d.ts +5 -3
  10. package/dist/builder/SdCliTsLibBuilder.mjs +20 -21
  11. package/dist/commons.d.ts +10 -1
  12. package/dist/entry-points/SdCliLocalUpdate.mjs +15 -9
  13. package/dist/entry-points/SdCliNpm.mjs +8 -4
  14. package/dist/entry-points/SdCliPrepare.mjs +3 -2
  15. package/dist/entry-points/SdCliWorkspace.d.ts +1 -0
  16. package/dist/entry-points/SdCliWorkspace.mjs +57 -24
  17. package/dist/packages/SdCliPackage.d.ts +4 -4
  18. package/dist/packages/SdCliPackage.mjs +17 -17
  19. package/dist/utils/SdCliBuildResultUtil.mjs +4 -5
  20. package/dist/utils/SdCliNpmConfigUtil.d.ts +7 -0
  21. package/dist/utils/SdCliNpmConfigUtil.mjs +15 -0
  22. package/package.json +18 -7
  23. package/src/bin/sd-cli.ts +2 -0
  24. package/src/build-tool/SdCliNgCacheCompilerHost.ts +3 -3
  25. package/src/builder/SdCliClientBuilder.ts +451 -0
  26. package/src/builder/SdCliJsLibBuilder.ts +2 -2
  27. package/src/builder/SdCliServerBuilder.ts +195 -100
  28. package/src/builder/SdCliTsLibBuilder.ts +29 -24
  29. package/src/commons.ts +9 -1
  30. package/src/entry-points/SdCliLocalUpdate.ts +14 -8
  31. package/src/entry-points/SdCliNpm.ts +7 -3
  32. package/src/entry-points/SdCliPrepare.ts +2 -1
  33. package/src/entry-points/SdCliWorkspace.ts +65 -26
  34. package/src/packages/SdCliPackage.ts +18 -18
  35. package/src/utils/SdCliBuildResultUtil.ts +3 -4
  36. package/src/utils/SdCliNpmConfigUtil.ts +16 -0
  37. package/tsconfig.json +1 -1
@@ -8,9 +8,8 @@ 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 * as webpackMerge from "webpack-merge";
12
11
  import TerserPlugin from "terser-webpack-plugin";
13
- import { StringUtil } from "@simplysm/sd-core-common";
12
+ import { ObjectUtil, StringUtil } from "@simplysm/sd-core-common";
14
13
  import ESLintWebpackPlugin from "eslint-webpack-plugin";
15
14
  import CopyWebpackPlugin from "copy-webpack-plugin";
16
15
  import { LicenseWebpackPlugin } from "license-webpack-plugin";
@@ -45,26 +44,29 @@ export class SdCliServerBuilder extends EventEmitter {
45
44
  await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
46
45
 
47
46
  // 빌드 준비
48
- const webpackConfig = this._getWebpackWatchConfig();
47
+ const extModuleNames = this._getExternalModuleNames();
48
+ const webpackConfig = this._getWebpackConfig(true, extModuleNames);
49
49
  const compiler = webpack(webpackConfig);
50
50
  await new Promise<void>((resolve, reject) => {
51
51
  compiler.hooks.watchRun.tapAsync(this.constructor.name, (args, callback) => {
52
52
  this.emit("change");
53
- callback();
54
-
55
53
  this._logger.debug("Webpack 빌드 수행...");
54
+ callback();
56
55
  });
57
56
 
58
- compiler.watch({}, (err, stats) => {
57
+ compiler.watch({}, async (err, stats) => {
59
58
  if (err != null || stats == null) {
60
59
  reject(err);
61
60
  return;
62
61
  }
63
62
 
64
- const results = SdCliBuildResultUtil.convertFromWebpackStats(stats);
65
- this.emit("complete", results);
63
+ // .config.json 파일 쓰기
64
+ await this._writeDistConfigFileAsync();
66
65
 
66
+ // 결과 반환
67
67
  this._logger.debug("Webpack 빌드 완료");
68
+ const results = SdCliBuildResultUtil.convertFromWebpackStats(stats);
69
+ this.emit("complete", results);
68
70
  resolve();
69
71
  });
70
72
  });
@@ -76,7 +78,8 @@ export class SdCliServerBuilder extends EventEmitter {
76
78
 
77
79
  // 빌드
78
80
  this._logger.debug("Webpack 빌드 수행...");
79
- const webpackConfig = this._getWebpackBuildConfig();
81
+ const extModuleNames = this._getExternalModuleNames();
82
+ const webpackConfig = this._getWebpackConfig(false, extModuleNames);
80
83
  const compiler = webpack(webpackConfig);
81
84
  const buildResults = await new Promise<ISdCliPackageBuildResult[]>((resolve, reject) => {
82
85
  compiler.run((err, stats) => {
@@ -85,18 +88,127 @@ export class SdCliServerBuilder extends EventEmitter {
85
88
  return;
86
89
  }
87
90
 
88
- // 결과 리턴
91
+ // 결과 반환
89
92
  const results = SdCliBuildResultUtil.convertFromWebpackStats(stats);
90
93
  resolve(results);
91
94
  });
92
95
  });
93
- this._logger.debug("Webpack 빌드 완료");
94
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 빌드 완료");
95
111
  return buildResults;
96
112
  }
97
113
 
98
- private get _webpackCommonConfig(): webpack.Configuration {
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
+
99
210
  return {
211
+ mode: watch ? "development" : "production",
100
212
  devtool: false,
101
213
  target: ["node", "es2020"],
102
214
  profile: false,
@@ -124,8 +236,46 @@ export class SdCliServerBuilder extends EventEmitter {
124
236
  outputModule: true
125
237
  },
126
238
  performance: { hints: false },
127
- node: false,
239
+ node: {
240
+ __dirname: true
241
+ },
128
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
+ },
129
279
  module: {
130
280
  strictExportPresence: true,
131
281
  rules: [
@@ -135,6 +285,18 @@ export class SdCliServerBuilder extends EventEmitter {
135
285
  fullySpecified: false
136
286
  }
137
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
+ ] : [],
138
300
  {
139
301
  test: /\.ts$/,
140
302
  exclude: /node_modules/,
@@ -160,6 +322,14 @@ export class SdCliServerBuilder extends EventEmitter {
160
322
  ]
161
323
  },
162
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
+ ],
163
333
  new CopyWebpackPlugin({
164
334
  patterns: ["assets/"].map((item) => ({
165
335
  context: this._rootPath,
@@ -185,6 +355,8 @@ export class SdCliServerBuilder extends EventEmitter {
185
355
  }),
186
356
  new ESLintWebpackPlugin({
187
357
  context: this._rootPath,
358
+ eslintPath: path.resolve(this._workspaceRootPath, "node_modules", "eslint"),
359
+ exclude: ["node_modules"],
188
360
  extensions: ["ts", "js", "mjs", "cjs"],
189
361
  fix: false,
190
362
  threads: false,
@@ -207,96 +379,21 @@ export class SdCliServerBuilder extends EventEmitter {
207
379
  }
208
380
  return resultMessages.join(os.EOL);
209
381
  }
210
- }),
382
+ })/*,
211
383
  new webpack.ProgressPlugin({
212
384
  handler: (per: number, msg: string, ...args: string[]) => {
213
385
  const phaseText = msg ? ` - phase: ${msg}` : "";
214
386
  const argsText = args.length > 0 ? ` - args: [${args.join(", ")}]` : "";
215
387
  this._logger.debug(`Webpack 빌드 수행중...(${Math.round(per * 100)}%)${phaseText}${argsText}`);
216
388
  }
217
- })
389
+ })*/
218
390
  ]
219
391
  };
220
392
  }
221
393
 
222
- private _getWebpackWatchConfig(): webpack.Configuration {
223
- const internalModuleCachePaths = FsUtil.findAllParentChildDirPaths("node_modules/!(@simplysm)", this._rootPath, this._workspaceRootPath);
224
-
225
- const extModuleNames = this._findExternalModules(true).map((item) => item.name);
226
- return webpackMerge.merge(this._webpackCommonConfig, {
227
- mode: "development",
228
- module: {
229
- rules: [
230
- {
231
- test: /\.m?js$/,
232
- enforce: "pre",
233
- loader: "source-map-loader",
234
- options: {
235
- filterSourceMappingUrl: (mapUri: string, resourcePath: string) => {
236
- return !resourcePath.includes("node_modules") || (/@simplysm[\\/]sd/).test(resourcePath);
237
- }
238
- }
239
- }
240
- ]
241
- },
242
- cache: { type: "memory", maxGenerations: 1 },
243
- snapshot: {
244
- immutablePaths: internalModuleCachePaths,
245
- managedPaths: internalModuleCachePaths
246
- },
247
- optimization: {
248
- moduleIds: "deterministic",
249
- chunkIds: "named",
250
- emitOnErrors: true
251
- },
252
- externals: extModuleNames
253
- });
254
- }
255
-
256
- private _getWebpackBuildConfig(): webpack.Configuration {
257
- const extModuleNames = this._findExternalModules(false).map((item) => item.name);
258
- return webpackMerge.merge(this._webpackCommonConfig, {
259
- mode: "production",
260
- cache: false,
261
- optimization: {
262
- minimize: true,
263
- minimizer: [
264
- new TerserPlugin({
265
- extractComments: false,
266
- terserOptions: {
267
- compress: true,
268
- ecma: 2020,
269
- sourceMap: false,
270
- keep_classnames: true,
271
- keep_fnames: true,
272
- ie8: false,
273
- safari10: false,
274
- module: true,
275
- format: {
276
- comments: false
277
- }
278
- }
279
- })
280
- ],
281
- moduleIds: "deterministic",
282
- chunkIds: "deterministic",
283
- emitOnErrors: false
284
- },
285
- plugins: [
286
- new LicenseWebpackPlugin({
287
- stats: { warnings: false, errors: false },
288
- perChunkOutput: false,
289
- outputFilename: "3rd_party_licenses.txt",
290
- skipChildCompilers: true
291
- }) as any
292
- ],
293
- externals: extModuleNames
294
- });
295
- }
296
-
297
- private _findExternalModules(all: boolean): { name: string; path?: string }[] {
394
+ private _getExternalModuleNames(): string[] {
298
395
  const loadedModuleNames: string[] = [];
299
- const externalModules: { name: string; path?: string }[] = [];
396
+ const resultSet = new Set<string>();
300
397
 
301
398
  const fn = (currPath: string): void => {
302
399
  const npmConfig = this._getNpmConfig(currPath);
@@ -317,12 +414,11 @@ export class SdCliServerBuilder extends EventEmitter {
317
414
 
318
415
  const modulePath = FsUtil.findAllParentChildDirPaths("node_modules/" + moduleName, currPath, this._workspaceRootPath).first();
319
416
  if (StringUtil.isNullOrEmpty(modulePath)) {
320
- console.log(2, currPath, moduleName);
321
417
  continue;
322
418
  }
323
419
 
324
- if (all || FsUtil.exists(path.resolve(modulePath, "binding.gyp"))) {
325
- externalModules.push({ path: modulePath, name: moduleName });
420
+ if (FsUtil.exists(path.resolve(modulePath, "binding.gyp"))) {
421
+ resultSet.add(moduleName);
326
422
  }
327
423
 
328
424
  fn(modulePath);
@@ -334,13 +430,12 @@ export class SdCliServerBuilder extends EventEmitter {
334
430
 
335
431
  const optModulePath = FsUtil.findAllParentChildDirPaths("node_modules/" + optModuleName, currPath, this._workspaceRootPath).first();
336
432
  if (StringUtil.isNullOrEmpty(optModulePath)) {
337
- console.log(1, currPath, optModuleName);
338
- externalModules.push({ path: optModulePath, name: optModuleName });
433
+ resultSet.add(optModuleName);
339
434
  continue;
340
435
  }
341
436
 
342
- if (all || FsUtil.exists(path.resolve(optModulePath, "binding.gyp"))) {
343
- externalModules.push({ path: optModulePath, name: optModuleName });
437
+ if (FsUtil.exists(path.resolve(optModulePath, "binding.gyp"))) {
438
+ resultSet.add(optModuleName);
344
439
  }
345
440
 
346
441
  fn(optModulePath);
@@ -349,7 +444,7 @@ export class SdCliServerBuilder extends EventEmitter {
349
444
 
350
445
  fn(this._rootPath);
351
446
 
352
- return externalModules.distinct();
447
+ return Array.from(resultSet.values());
353
448
  }
354
449
 
355
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
- public constructor(private readonly _rootPath,
30
- private readonly _isAngular: boolean) {
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: string) {
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(parsedTsconfig.options.outDir!);
62
+ await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
49
63
 
50
64
  // 프로그램 리로드
51
- const buildPack = this._createSdBuildPack(parsedTsconfig);
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(parsedTsconfig);
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(parsedTsconfig.options.outDir!);
108
+ await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
98
109
 
99
110
  // 프로그램 리로드
100
- const buildPack = this._createSdBuildPack(parsedTsconfig);
111
+ const buildPack = this._createSdBuildPack(this._parsedTsconfig);
101
112
 
102
113
  // 빌드
103
114
  const buildResults = await this._runBuilderAsync(buildPack.builder, buildPack.ngCompiler);
@@ -183,7 +194,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
183
194
  }
184
195
  catch (err) {
185
196
  if (err instanceof sass.Exception) {
186
- const matches = err.sassStack.match(/^(.*\.sd\.scss) ([0-9]*):([0-9]*)/)!;
197
+ const matches = (/^(.*\.sd\.scss) ([0-9]*):([0-9]*)/).exec(err.sassStack)!;
187
198
  const filePath = path.resolve(matches[1].replace(/\.sd\.scss/, "").replace(/^\.:/, item => item.toUpperCase()));
188
199
  const scssLine = matches[2];
189
200
  const scssChar = matches[3];
@@ -195,7 +206,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
195
206
  char: undefined,
196
207
  code: undefined,
197
208
  severity: "error",
198
- message: `스타일(${scssLine}:${scssChar}): ${message}`
209
+ message: `스타일(${scssLine}:${scssChar}): ${message}\n${err.message}`
199
210
  }];
200
211
  }
201
212
 
@@ -223,7 +234,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
223
234
  const affectedSourceFileSet: Set<ts.SourceFile> = new Set<ts.SourceFile>();
224
235
  while (true) {
225
236
  const result = this._builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sourceFile) => {
226
- if (ngCompiler && ngCompiler.ignoreForDiagnostics.has(sourceFile) && sourceFile.fileName.endsWith(".ngtypecheck.ts")) {
237
+ if (ngCompiler?.ignoreForDiagnostics.has(sourceFile) && sourceFile.fileName.endsWith(".ngtypecheck.ts")) {
227
238
  const orgFileName = sourceFile.fileName.slice(0, -15) + ".ts";
228
239
  const orgSourceFile = this._builder!.getSourceFile(orgFileName);
229
240
  if (orgSourceFile) {
@@ -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
@@ -40,7 +40,7 @@ export interface ISdCliConfig {
40
40
  localUpdates?: Record<string, string>;
41
41
  }
42
42
 
43
- export type TSdCliPackageConfig = ISdCliLibPackageConfig | ISdCliServerPackageConfig;
43
+ export type TSdCliPackageConfig = ISdCliLibPackageConfig | ISdCliServerPackageConfig | ISdCliClientPackageConfig;
44
44
 
45
45
  export interface ISdCliLibPackageConfig {
46
46
  type: "library";
@@ -50,4 +50,12 @@ export interface ISdCliLibPackageConfig {
50
50
  export interface ISdCliServerPackageConfig {
51
51
  type: "server";
52
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;
53
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
- const currentUpdatePathInfos = updatePathInfos.filter((item) => PathUtil.isChildPath(changedFilePath, item.source));
50
- const targetFilePaths = currentUpdatePathInfos.map((item) => path.resolve(item.target, path.relative(item.source, changedFilePath)));
51
- if (FsUtil.exists(changedFilePath)) {
52
- this._logger.debug(`변경파일감지(복사): ${changedFilePath}`);
53
- for (const targetFilePath of targetFilePaths) {
54
- await FsUtil.copyAsync(changedFilePath, targetFilePath);
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
- this._logger.debug("업데이트할 패키지 확인...");
12
- await SdProcess.execAsync("npm outdated", { cwd: this._rootPath });
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.execAsync("npm update", { cwd: this._rootPath });
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.replace(/^file:\/\/\//, "");
15
+ const filePath = fileURLToPath(fileUrl);
15
16
  const fileContent = await FsUtil.readFileAsync(filePath);
16
17
  const modifiedFileContent = fileContent.replace(`
17
18
  function checkSourceElement(node) {