@simplysm/sd-cli 7.0.246 → 7.0.249

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.
@@ -110,6 +110,9 @@ export class SdCliServerBuilder extends EventEmitter {
110
110
  // pm2.json 파일 쓰기
111
111
  await this._writeDistPm2ConfigFileAsync();
112
112
 
113
+ // iis web.config 파일 쓰기
114
+ await this._writeDistIisConfigFileAsync();
115
+
113
116
  // 배포용 package.json 파일 생성
114
117
  await this._writeDistNpmConfigFileAsync(extModules.filter((item) => item.exists).map((item) => item.name));
115
118
 
@@ -134,8 +137,9 @@ export class SdCliServerBuilder extends EventEmitter {
134
137
  ObjectUtil.merge(
135
138
  {
136
139
  "name": npmConfig.name.replace(/@/g, "").replace(/\//g, "-"),
137
- "script": path.basename(path.resolve(this._parsedTsconfig.options.outDir!, "main.mjs")),
138
- "node_args": "--experimental-specifier-resolution=node --experimental-import-meta-resolve",
140
+ "script": path.basename(path.resolve(this._parsedTsconfig.options.outDir!, "main.js")),
141
+ // "script": path.basename(path.resolve(this._parsedTsconfig.options.outDir!, "main.mjs")),
142
+ // "node_args": "--experimental-specifier-resolution=node --experimental-import-meta-resolve",
139
143
  "watch": true,
140
144
  "watch_delay": 2000,
141
145
  "ignore_watch": [
@@ -152,7 +156,8 @@ export class SdCliServerBuilder extends EventEmitter {
152
156
  },
153
157
  (typeof this._config.pm2 !== "boolean") ? this._config.pm2 : {},
154
158
  {
155
- arrayProcess: "concat"
159
+ arrayProcess: "concat",
160
+ useDelTargetNull: true
156
161
  }),
157
162
  undefined,
158
163
  2
@@ -160,6 +165,37 @@ export class SdCliServerBuilder extends EventEmitter {
160
165
  );
161
166
  }
162
167
 
168
+ private async _writeDistIisConfigFileAsync(): Promise<void> {
169
+ if (this._config.iis === undefined || this._config.iis === false) return;
170
+
171
+ const iisDistPath = path.resolve(this._parsedTsconfig.options.outDir!, "web.config");
172
+ const serverExeFilePath = (this._config.iis !== true && "serverExeFilePath" in this._config.iis)
173
+ ? (this._config.iis.serverExeFilePath ?? "C:\\Program Files\\nodejs\\node.exe")
174
+ : "C:\\Program Files\\nodejs\\node.exe";
175
+ await FsUtil.writeFileAsync(iisDistPath, `
176
+ <configuration>
177
+ <system.webServer>
178
+ <handlers>
179
+ <add name="iisnode" path="main.js" verb="*" modules="iisnode" />
180
+ </handlers>
181
+ <iisnode nodeProcessCommandLine="${serverExeFilePath}"
182
+ watchedFiles="web.config;*.js"
183
+ loggingEnabled="true"
184
+ devErrorsEnabled="true" />
185
+ <rewrite>
186
+ <rules>
187
+ <rule name="main">
188
+ <action type="Rewrite" url="main.js" />
189
+ </rule>
190
+ </rules>
191
+ </rewrite>
192
+ <httpErrors errorMode="Detailed" />
193
+ </system.webServer>
194
+ </configuration>
195
+
196
+ `.trim());
197
+ }
198
+
163
199
  private async _writeDistNpmConfigFileAsync(deps: string[]): Promise<void> {
164
200
  const distNpmConfig = ObjectUtil.clone(this._getNpmConfig(this._rootPath))!;
165
201
  distNpmConfig.dependencies = {};
@@ -207,6 +243,7 @@ export class SdCliServerBuilder extends EventEmitter {
207
243
  mode: watch ? "development" : "production",
208
244
  devtool: false,
209
245
  target: ["node", "es2020"],
246
+ // target: ["node", "es2020"],
210
247
  profile: false,
211
248
  resolve: {
212
249
  roots: [this._rootPath],
@@ -230,23 +267,27 @@ export class SdCliServerBuilder extends EventEmitter {
230
267
  hashFunction: "xxhash64",
231
268
  clean: true,
232
269
  path: this._parsedTsconfig.options.outDir,
233
- filename: "[name].mjs",
234
- chunkFilename: "[name].mjs",
270
+ filename: "[name].js",
271
+ chunkFilename: "[name].js",
272
+ // filename: "[name].mjs",
273
+ // chunkFilename: "[name].mjs",
235
274
  assetModuleFilename: "res/[name][ext][query]",
236
- library: {
237
- type: "module"
238
- },
239
- module: true
275
+ libraryTarget: "commonjs2"
276
+ // library: {
277
+ // type: "module"
278
+ // },
279
+ // module: true
240
280
  },
241
- experiments: {
281
+ /*experiments: {
242
282
  outputModule: true
243
- },
283
+ },*/
244
284
  watch: false,
245
285
  watchOptions: { poll: undefined, ignored: undefined },
246
286
  performance: { hints: false },
247
287
  infrastructureLogging: { level: "error" },
248
288
  stats: "errors-warnings",
249
- externals: extModules.toObject((item) => item.name, (item) => "node-commonjs " + item.name),
289
+ externals: extModules.toObject((item) => item.name, (item) => "commonjs2 " + item.name),
290
+ // externals: extModules.toObject((item) => item.name, (item) => "node-commonjs " + item.name),
250
291
  cache: {
251
292
  type: "filesystem",
252
293
  profile: watch ? undefined : false,
@@ -259,13 +300,10 @@ export class SdCliServerBuilder extends EventEmitter {
259
300
  .update(watch.toString())
260
301
  .digest("hex")
261
302
  },
262
- // cache: { type: "memory", maxGenerations: 1 },
263
- ...watch ? {
264
- snapshot: {
265
- immutablePaths: internalModuleCachePaths,
266
- managedPaths: internalModuleCachePaths
267
- }
268
- } : {},
303
+ snapshot: {
304
+ immutablePaths: internalModuleCachePaths,
305
+ managedPaths: internalModuleCachePaths
306
+ },
269
307
  node: false,
270
308
  optimization: {
271
309
  minimizer: watch ? [] : [
@@ -279,7 +317,7 @@ export class SdCliServerBuilder extends EventEmitter {
279
317
  keep_fnames: true,
280
318
  ie8: false,
281
319
  safari10: false,
282
- module: true,
320
+ // module: true,
283
321
  format: {
284
322
  comments: false
285
323
  }
package/src/commons.ts CHANGED
@@ -65,6 +65,7 @@ export interface ISdCliServerPackageConfig {
65
65
  env?: Record<string, string>;
66
66
  configs?: Record<string, any>;
67
67
  pm2?: Record<string, any> | boolean;
68
+ iis?: boolean | { serverExeFilePath?: string };
68
69
  externalNodeModules?: string[];
69
70
  publish?: TSdCliPublishConfig;
70
71
  }
@@ -1,17 +1,15 @@
1
- import { FsUtil, Logger, PathUtil, SdProcess } from "@simplysm/sd-core-node";
1
+ 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 { Uuid, Wait } from "@simplysm/sd-core-common";
5
+ import { JsonConvert, 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
- import { SdServiceServer } from "@simplysm/sd-service-server";
11
10
  import { SdCliLocalUpdate } from "./SdCliLocalUpdate";
12
- import url from "url";
13
- import mime from "mime";
14
- import { NextHandleFunction } from "connect";
11
+ import { fileURLToPath } from "url";
12
+ import cp from "child_process";
15
13
 
16
14
  export class SdCliWorkspace {
17
15
  private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
@@ -69,11 +67,15 @@ export class SdCliWorkspace {
69
67
  if (changePkg.config.type === "client") {
70
68
  if (typeof changePkg.config.server === "string") {
71
69
  const serverInfo = this._serverInfoMap.get(changePkg.config.server);
72
- serverInfo?.server?.broadcastReload();
70
+ if (serverInfo) {
71
+ await this._sendServerWorkerBroadcastReloadAsync(serverInfo);
72
+ }
73
73
  }
74
74
  else {
75
75
  const serverInfo = this._serverInfoMap.get("PORT:" + changePkg.config.server.port);
76
- serverInfo?.server?.broadcastReload();
76
+ if (serverInfo) {
77
+ await this._sendServerWorkerBroadcastReloadAsync(serverInfo);
78
+ }
77
79
  }
78
80
  }
79
81
  }
@@ -100,7 +102,7 @@ export class SdCliWorkspace {
100
102
  if (pkg.config.type === "client") {
101
103
  await pkg.watchAsync();
102
104
 
103
- const pkgMiddleware: NextHandleFunction = (req, res, next) => {
105
+ /*const pkgMiddleware: NextHandleFunction = (req, res, next) => {
104
106
  if (req.method === "GET") {
105
107
  const urlObj = url.parse(req.url!, true, false);
106
108
  const urlPathChain = decodeURI(urlObj.pathname!.slice(1)).split("/");
@@ -124,11 +126,17 @@ export class SdCliWorkspace {
124
126
  }
125
127
 
126
128
  next();
127
- };
129
+ };*/
128
130
 
129
131
  if (typeof pkg.config.server === "string") {
130
- const serverInfo = this._serverInfoMap.getOrCreate(pkg.config.server, { middlewares: [], clientInfos: [] });
131
- serverInfo.middlewares.push(pkgMiddleware);
132
+ const serverInfo = this._serverInfoMap.getOrCreate(pkg.config.server, { pathProxy: [], clientInfos: [] });
133
+
134
+ serverInfo.pathProxy.push({
135
+ from: pkg.name.split("/").last()!,
136
+ to: path.resolve(pkg.rootPath, "dist")
137
+ });
138
+ await this._reloadServerWorkerPathProxyAsync(serverInfo);
139
+
132
140
  serverInfo.clientInfos.push({
133
141
  pkgKey: pkg.name.split("/").last()!,
134
142
  platforms: pkg.config.builder ? Object.keys(pkg.config.builder) : ["web"],
@@ -137,11 +145,27 @@ export class SdCliWorkspace {
137
145
  }
138
146
  else { // DEV SERVER
139
147
  const serverInfo = this._serverInfoMap.getOrCreate("PORT:" + pkg.config.server.port, {
140
- middlewares: [],
148
+ pathProxy: [],
141
149
  clientInfos: []
142
150
  });
143
- if (serverInfo.server === undefined) {
144
- const server = new SdServiceServer({
151
+ if (serverInfo.worker === undefined) {
152
+ const serverWorkerInfo = await this._runServerWorkerAsync(pkg.config.server);
153
+ serverInfo.worker = serverWorkerInfo.worker;
154
+ serverInfo.url = serverWorkerInfo.url;
155
+
156
+ serverInfo.pathProxy.push({
157
+ from: pkg.name.split("/").last()!,
158
+ to: path.resolve(pkg.rootPath, "dist")
159
+ });
160
+ await this._reloadServerWorkerPathProxyAsync(serverInfo);
161
+
162
+ serverInfo.clientInfos.push({
163
+ pkgKey: pkg.name.split("/").last()!,
164
+ platforms: pkg.config.builder ? Object.keys(pkg.config.builder) : ["web"],
165
+ cordovaTargets: pkg.config.builder?.cordova?.target ? Object.keys(pkg.config.builder.cordova.target) : ["browser"]
166
+ });
167
+
168
+ /*const server = new SdServiceServer({
145
169
  rootPath: process.cwd(),
146
170
  services: [],
147
171
  port: pkg.config.server.port
@@ -153,7 +177,7 @@ export class SdCliWorkspace {
153
177
  pkgKey: pkg.name.split("/").last()!,
154
178
  platforms: pkg.config.builder ? Object.keys(pkg.config.builder) : ["web"],
155
179
  cordovaTargets: pkg.config.builder?.cordova?.target ? Object.keys(pkg.config.builder.cordova.target) : ["browser"]
156
- });
180
+ });*/
157
181
  }
158
182
  }
159
183
  }
@@ -177,6 +201,57 @@ export class SdCliWorkspace {
177
201
  }
178
202
  }
179
203
 
204
+ private async _runServerWorkerAsync(filePathOrOpt: string | { port: number }): Promise<{ worker: cp.ChildProcess; url: string }> {
205
+ const workerPath = fileURLToPath(await import.meta.resolve!("../worker/server-worker"));
206
+ return await new Promise<{ worker: cp.ChildProcess; url: string }>((resolve, reject) => {
207
+ const worker = cp.fork(workerPath, [
208
+ JsonConvert.stringify(filePathOrOpt)
209
+ ], {
210
+ stdio: ["pipe", "pipe", "pipe", "ipc"],
211
+ env: process.env
212
+ });
213
+
214
+ worker.on("error", (err) => {
215
+ reject(err);
216
+ });
217
+
218
+ worker.stdout!.pipe(process.stdout);
219
+ worker.stderr!.pipe(process.stderr);
220
+
221
+ worker.on("message", (url: string) => {
222
+ resolve({ worker, url });
223
+ });
224
+ });
225
+ }
226
+
227
+ private async _reloadServerWorkerPathProxyAsync(serverInfo: IServerInfo): Promise<void> {
228
+ if (!serverInfo.worker) return;
229
+
230
+ await new Promise<void>((resolve, reject) => {
231
+ serverInfo.worker!.send(JsonConvert.stringify(serverInfo.pathProxy), (err) => {
232
+ if (err) {
233
+ reject(err);
234
+ return;
235
+ }
236
+ resolve();
237
+ });
238
+ });
239
+ }
240
+
241
+ private async _sendServerWorkerBroadcastReloadAsync(serverInfo: IServerInfo): Promise<void> {
242
+ if (!serverInfo.worker) return;
243
+
244
+ await new Promise<void>((resolve, reject) => {
245
+ serverInfo.worker!.send("broadcastReload", (err) => {
246
+ if (err) {
247
+ reject(err);
248
+ return;
249
+ }
250
+ resolve();
251
+ });
252
+ });
253
+ }
254
+
180
255
  private _isServerRestarting = false;
181
256
 
182
257
  private async _restartServerAsync(pkg: SdCliPackage): Promise<void> {
@@ -193,18 +268,24 @@ export class SdCliWorkspace {
193
268
 
194
269
  try {
195
270
  const serverInfo = this._serverInfoMap.getOrCreate(path.basename(pkg.rootPath), {
196
- middlewares: [],
271
+ pathProxy: [],
197
272
  clientInfos: []
198
273
  });
199
- if (serverInfo.server) {
274
+ if (serverInfo.worker) {
200
275
  this._logger.log(`[${pkg.name}] 기존 서버 중지...`);
201
- await serverInfo.server.closeAsync();
202
- delete serverInfo.server;
276
+ cp.exec(`taskkill /pid ${serverInfo.worker.pid} /F /T`);
277
+ delete serverInfo.worker;
278
+ delete serverInfo.url;
203
279
  }
204
280
 
205
281
  this._logger.log(`[${pkg.name}] 서버 시작중...`);
206
282
 
207
- const serverMainPath = "file:///" + PathUtil.posix(entryFilePath) + "?update=" + Uuid.new().toString().replace(/-/g, "");
283
+ const serverWorkerInfo = await this._runServerWorkerAsync(entryFilePath);
284
+ serverInfo.worker = serverWorkerInfo.worker;
285
+ serverInfo.url = serverWorkerInfo.url;
286
+ await this._reloadServerWorkerPathProxyAsync(serverInfo);
287
+
288
+ /*const serverMainPath = "file:///" + PathUtil.posix(entryFilePath) + "?update=" + Uuid.new().toString().replace(/-/g, "");
208
289
  const serverModule = await import(serverMainPath);
209
290
  serverInfo.server = serverModule.default as SdServiceServer | undefined;
210
291
  if (!serverInfo.server) {
@@ -213,7 +294,7 @@ export class SdCliWorkspace {
213
294
  return;
214
295
  }
215
296
  serverInfo.server.devMiddlewares = serverInfo.middlewares;
216
- await Wait.until(() => serverInfo.server!.isOpen);
297
+ await Wait.until(() => serverInfo.server!.isOpen);*/
217
298
 
218
299
  this._logger.log(`[${pkg.name}] 서버가 시작되었습니다.`);
219
300
  }
@@ -416,26 +497,26 @@ export class SdCliWorkspace {
416
497
 
417
498
  const serverInfos = Array.from(this._serverInfoMap.values());
418
499
  for (const serverInfo of serverInfos) {
419
- if (!serverInfo.server) continue;
500
+ if (!serverInfo.worker) continue;
420
501
 
421
- const protocolStr = serverInfo.server.options.ssl ? "https" : "http";
422
- const portStr = serverInfo.server.options.port.toString();
502
+ /*const protocolStr = serverInfo.server.options.ssl ? "https" : "http";
503
+ const portStr = serverInfo.server.options.port.toString();*/
423
504
 
424
505
  for (const clientInfo of serverInfo.clientInfos) {
425
506
  for (const platform of clientInfo.platforms) {
426
507
  if (platform === "web") {
427
- clientHrefs.push(`${protocolStr}://localhost:${portStr}/${clientInfo.pkgKey}/`);
508
+ clientHrefs.push(`${serverInfo.url}/${clientInfo.pkgKey}/`);
428
509
  }
429
510
  else if (platform === "electron") {
430
- clientHrefs.push(`sd-cli run-electron ${clientInfo.pkgKey} http://localhost:${portStr}`);
511
+ clientHrefs.push(`sd-cli run-electron ${clientInfo.pkgKey} ${serverInfo.url}`);
431
512
  }
432
513
  else if (platform === "cordova") {
433
514
  for (const target of clientInfo.cordovaTargets) {
434
515
  if (target === "browser") {
435
- clientHrefs.push(`${protocolStr}://localhost:${portStr}/${clientInfo.pkgKey}/${platform}/`);
516
+ clientHrefs.push(`${serverInfo.url}/${clientInfo.pkgKey}/${platform}/`);
436
517
  }
437
518
  else {
438
- clientHrefs.push(`sd-cli run-cordova ${target} ${clientInfo.pkgKey} http://[IP]:${portStr}`);
519
+ clientHrefs.push(`sd-cli run-cordova ${target} ${clientInfo.pkgKey} ${serverInfo.url}`);
439
520
  }
440
521
  }
441
522
  }
@@ -449,7 +530,8 @@ export class SdCliWorkspace {
449
530
  }
450
531
 
451
532
  interface IServerInfo {
452
- server?: SdServiceServer;
453
- middlewares: NextHandleFunction[];
533
+ worker?: cp.ChildProcess;
534
+ url?: string;
535
+ pathProxy: { from: string; to: string }[];
454
536
  clientInfos: { pkgKey: string; platforms: string[]; cordovaTargets: string[] }[];
455
537
  }
@@ -0,0 +1,72 @@
1
+ import { Logger, LoggerSeverity } from "@simplysm/sd-core-node";
2
+ import { JsonConvert } from "@simplysm/sd-core-common";
3
+ import { SdServiceServer } from "@simplysm/sd-service-server";
4
+
5
+ if (process.env["SD_CLI_LOGGER_SEVERITY"] === "DEBUG") {
6
+ Logger.setConfig({
7
+ console: {
8
+ level: LoggerSeverity.debug
9
+ }
10
+ });
11
+ }
12
+ else {
13
+ Logger.setConfig({
14
+ dot: true
15
+ });
16
+ }
17
+
18
+ const filePathOrOpt = JsonConvert.parse(process.argv[2]) as (string | { port: number });
19
+
20
+ let runningServer: SdServiceServer | undefined;
21
+
22
+ if (typeof filePathOrOpt === "string") {
23
+ import(`file:///${filePathOrOpt}`)
24
+ .then((serverModule) => {
25
+ const server = serverModule.default as SdServiceServer | undefined;
26
+ if (server === undefined) {
27
+ // eslint-disable-next-line no-console
28
+ console.error(`${filePathOrOpt}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
29
+ process.exit(1);
30
+ return;
31
+ }
32
+ const protocolStr = server.options.ssl ? "https" : "http";
33
+ const portStr = server.options.port.toString();
34
+
35
+ runningServer = server;
36
+ process.send!(`${protocolStr}://localhost:${portStr}`);
37
+ })
38
+ .catch((err) => {
39
+ // eslint-disable-next-line no-console
40
+ console.error(err);
41
+ process.exit(1);
42
+ });
43
+ }
44
+ // DEV SERVER
45
+ else {
46
+ const server = new SdServiceServer({
47
+ rootPath: process.cwd(),
48
+ services: [],
49
+ port: filePathOrOpt.port
50
+ });
51
+ server.listenAsync()
52
+ .then(() => {
53
+ runningServer = server;
54
+ process.send!(`http://localhost:${filePathOrOpt.port}`);
55
+ })
56
+ .catch((err) => {
57
+ // eslint-disable-next-line no-console
58
+ console.error(err);
59
+ process.exit(1);
60
+ });
61
+ }
62
+
63
+ process.on("message", (msg: string) => {
64
+ if (!runningServer) return;
65
+
66
+ if (msg === "broadcastReload") {
67
+ runningServer.broadcastReload();
68
+ }
69
+ else {
70
+ runningServer.pathProxy = JsonConvert.parse(msg);
71
+ }
72
+ });
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "src/bin/sd-cli.ts",
12
12
  "src/index.ts",
13
- "src/worker/build-worker.ts"
13
+ "src/worker/build-worker.ts",
14
+ "src/worker/server-worker.ts"
14
15
  ]
15
16
  }
package/tsconfig.json CHANGED
@@ -33,6 +33,7 @@
33
33
  "files": [
34
34
  "src/bin/sd-cli.ts",
35
35
  "src/index.ts",
36
- "src/worker/build-worker.ts"
36
+ "src/worker/build-worker.ts",
37
+ "src/worker/server-worker.ts"
37
38
  ]
38
39
  }