@mainset/cli 0.2.1-rc.2 → 0.3.0-rc.1

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.
@@ -1,5 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+ import { initDotenv } from '../dotenv-config.mjs';
3
4
  import { resolveHostPackageBinForCLICommandPath, runtimePathById, } from '../runtime/index.mjs';
4
5
  import { consoleColorize, execImmediateCommand, initProcessCatchErrorLogger, runStreamingCommand, runStreamingInSync, } from '../utils/index.mjs';
5
6
  import { execImmediatePurgeDist } from './process-runner-chunks/index.mjs';
@@ -16,6 +17,9 @@ function registerWebAppCommand(program) {
16
17
  .option('-c, --config <path>', 'Path to config file')
17
18
  .option('--serveMode <mode>', 'Serve mode: ssr or csr (default: ssr)', 'ssr')
18
19
  .action((options) => {
20
+ // !IMPORTANT: Load environment variables from .env file ONLY when we are compiling Web Applications
21
+ // as it logs {missing .env file} console error during {course-code} / {node-package} compilation
22
+ initDotenv();
19
23
  // Step 0: determinate command params
20
24
  const customWebpackConfigPath = path.resolve(runtimePathById.root, options.config || './config/webpack.config.mjs');
21
25
  // SSR server path
@@ -44,7 +48,7 @@ function registerWebAppCommand(program) {
44
48
  execImmediatePurgeDist();
45
49
  // Step 2: build:ssr-webapp source code
46
50
  console.log('\nšŸ“¦ Compiling SSR WebApp with Webpack ...');
47
- execImmediateCommand(`${webpackCLICommandPath} --config ${webpackSSRConfigPath}`);
51
+ execImmediateCommand(`MS_CLI__WEBPACK_SERVE_MODE=ssr ${webpackCLICommandPath} --config ${webpackSSRConfigPath}`);
48
52
  /*
49
53
  // Step 3: build:ssr-server source code
50
54
  console.log('\nšŸ“¦ Compiling SSR Server with Rslib ...');
@@ -61,7 +65,7 @@ function registerWebAppCommand(program) {
61
65
  execImmediatePurgeDist();
62
66
  // Step 2: build:csr-webapp source code
63
67
  console.log('\nšŸ“¦ Compiling CSR WebApp with Webpack ...');
64
- execImmediateCommand(`${webpackCLICommandPath} --config ${webpackCSRConfigPath}`);
68
+ execImmediateCommand(`MS_CLI__WEBPACK_SERVE_MODE=csr ${webpackCLICommandPath} --config ${webpackCSRConfigPath}`);
65
69
  console.log('\nāœ… CSR Build completed successfully\n');
66
70
  }
67
71
  }
@@ -88,11 +92,9 @@ function registerWebAppCommand(program) {
88
92
  runStreamingInSync([
89
93
  // Step 2: watch:ssr-webapp source code of web app
90
94
  {
91
- runCommand: () => runStreamingCommand(webpackCLICommandPath, [
92
- '--config',
93
- webpackSSRConfigPath,
94
- '--watch',
95
- ]),
95
+ runCommand: () => runStreamingCommand(webpackCLICommandPath, ['--config', webpackSSRConfigPath, '--watch'], {
96
+ env: Object.assign(Object.assign({}, process.env), { MS_CLI__WEBPACK_SERVE_MODE: 'ssr' }),
97
+ }),
96
98
  waitForOutput: 'compiled successfully',
97
99
  },
98
100
  // Step 3: start:ssr-server which is compiled web app and ssr-server code
@@ -112,12 +114,9 @@ function registerWebAppCommand(program) {
112
114
  ? customWebpackConfigPath
113
115
  : path.resolve(runtimePathById.root, 'node_modules', '@mainset/bundler-webpack/dist/esm/webpack-config/dev-server.csr.config.mjs');
114
116
  // Step 1: watch:csr-server / start:csr-server source code
115
- runStreamingCommand(webpackCLICommandPath, [
116
- 'serve',
117
- '--config',
118
- webpackDevServerConfigPath,
119
- '--open',
120
- ]);
117
+ runStreamingCommand(webpackCLICommandPath, ['serve', '--config', webpackDevServerConfigPath, '--open'], {
118
+ env: Object.assign(Object.assign({}, process.env), { MS_CLI__WEBPACK_SERVE_MODE: 'csr' }),
119
+ });
121
120
  }
122
121
  }
123
122
  catch (error) {
@@ -142,10 +141,13 @@ function registerWebAppCommand(program) {
142
141
  // ========== [Serve Static] CSR mode ==========
143
142
  // Step 1: determinate command params
144
143
  const serverEntryPath = path.resolve(runtimePathById.msCLISrc, '../services/serve-static/serve-static.mjs');
145
- const customServeStaticConfigPath = path.resolve(runtimePathById.root, options.config || './config/serve-static.config.json');
146
- const serveStaticConfigPath = fs.existsSync(customServeStaticConfigPath)
147
- ? customServeStaticConfigPath
148
- : path.resolve(runtimePathById.msCLISrc, '../services/express-base-app/express-base-app.config.json');
144
+ const customServeStaticMjsConfigPath = path.resolve(runtimePathById.root, options.config || './config/serve-static.config.mjs');
145
+ const customServeStaticJsonConfigPath = path.resolve(runtimePathById.root, './config/serve-static.config.json');
146
+ const serveStaticConfigPath = (fs.existsSync(customServeStaticMjsConfigPath) &&
147
+ customServeStaticMjsConfigPath) ||
148
+ (fs.existsSync(customServeStaticJsonConfigPath) &&
149
+ customServeStaticJsonConfigPath) ||
150
+ path.resolve(runtimePathById.msCLISrc, '../services/express-base-app/express-base-app.config.json');
149
151
  // Step 2: serve static compiled files
150
152
  runStreamingCommand('node', [
151
153
  serverEntryPath,
@@ -0,0 +1,9 @@
1
+ import dotenv from '@dotenvx/dotenvx';
2
+ function initDotenv() {
3
+ // Load environment-specific .env file
4
+ return dotenv.config();
5
+ }
6
+ // REVIEW: investigate if {.env} file need's to be loaded during {course-code} / {node-package} compilation
7
+ // Auto-execute configuration
8
+ // initDotenv();
9
+ export { initDotenv };
@@ -1,3 +1,4 @@
1
1
  export { NODE_ENV } from './constants.mjs';
2
+ export { parseCliOptions } from './parse-cli-options.mjs';
2
3
  export { runtimePathById } from './path.mjs';
3
4
  export { resolveHostPackageBinForCLICommandPath, resolveHostPackageNodeModulesPath, } from './resolve-host-package.mjs';
@@ -0,0 +1,13 @@
1
+ import { Command } from 'commander';
2
+ function parseCliOptions(options) {
3
+ const program = new Command();
4
+ options.forEach(({ commanderFlags, description }) => {
5
+ program.option(commanderFlags, description);
6
+ });
7
+ return program
8
+ .allowUnknownOption() // Bypass {error: unknown option '--config'}
9
+ .allowExcessArguments() // Bypass {error: too many arguments. Expected 0 arguments but got 2.}
10
+ .parse(process.argv)
11
+ .opts();
12
+ }
13
+ export { parseCliOptions };
@@ -1,17 +1,20 @@
1
1
  import express from 'express';
2
+ import { createProxyMiddleware } from 'http-proxy-middleware';
2
3
  import path from 'path';
3
- // Import type { Options } from 'http-proxy-middleware';
4
4
  import { runtimePathById } from '../../runtime/index.mjs';
5
5
  import defaultExpressConfig from './express-base-app.config.json' with { type: 'json' };
6
6
  class ExpressBaseApp {
7
7
  // ========== Constructor ==========
8
8
  constructor(customExpressConfig = {}) {
9
- const { listenPort = defaultExpressConfig.listenPort, serveStatics } = customExpressConfig;
9
+ const { listenPort = defaultExpressConfig.listenPort, serveStatics = defaultExpressConfig.serveStatics, proxyConfigByPath, } = customExpressConfig;
10
10
  this.listenPort = listenPort;
11
11
  this.app = express();
12
12
  this.appUseStatic({
13
13
  serveStatics,
14
14
  });
15
+ this.appUseProxyMiddleware({
16
+ proxyConfigByPath,
17
+ });
15
18
  this.startListening = this.startListening.bind(this);
16
19
  }
17
20
  // ========== Private ==========
@@ -21,11 +24,12 @@ class ExpressBaseApp {
21
24
  this.app.use(serveStaticConfig.publicPath, express.static(serveStaticConfig.rootPath));
22
25
  });
23
26
  }
24
- // Private appUseProxy() {
25
- // app.use('/api', createProxyMiddleware(proxyConfig['/api/']));
26
- // app.use('/api-local', createProxyMiddleware(proxyConfig['/api-local/']));
27
- // app.use('/api-boilerplate', createProxyMiddleware(proxyConfig['/api-boilerplate/']));
28
- // }
27
+ appUseProxyMiddleware({ proxyConfigByPath = {}, }) {
28
+ var _a;
29
+ (_a = Object.keys(proxyConfigByPath)) === null || _a === void 0 ? void 0 : _a.forEach((proxyPath) => {
30
+ this.app.use(proxyPath, createProxyMiddleware(proxyConfigByPath[proxyPath]));
31
+ });
32
+ }
29
33
  // ========== Public ==========
30
34
  startListening() {
31
35
  this.app.listen(this.listenPort, async () => {
@@ -1,14 +1,17 @@
1
- import { Command } from 'commander';
2
1
  import fs from 'fs';
2
+ import { parseCliOptions } from '../../runtime/index.mjs';
3
3
  // Step-1: parse CLI arguments
4
- const options = new Command()
5
- .option('--serveStaticConfig <path>', 'Path to ./config/serve-static.config.json config file')
6
- .allowUnknownOption() // Bypass {error: unknown option '--config'}
7
- .allowExcessArguments() // Bypass {error: too many arguments. Expected 0 arguments but got 2.}
8
- .parse(process.argv)
9
- .opts();
4
+ const options = parseCliOptions([
5
+ {
6
+ commanderFlags: '--serveStaticConfig <path>',
7
+ description: 'Path to ./config/serve-static.config.{mjs,json} config file',
8
+ },
9
+ ]);
10
10
  // Step-2: load Serve Static config from JSON file
11
- const serveStaticConfig = options.serveStaticConfig
12
- ? JSON.parse(fs.readFileSync(options.serveStaticConfig, 'utf-8'))
13
- : {};
11
+ const isConfigFileJsonWithoutProcessEnvUsage = /\.json$/.test(options.serveStaticConfig);
12
+ const serveStaticConfig = isConfigFileJsonWithoutProcessEnvUsage
13
+ ? JSON.parse(fs.readFileSync(options.serveStaticConfig, 'utf-8') ||
14
+ // NOTE: dot not crash in case if {.json} file is empty
15
+ '{}')
16
+ : (await import(options.serveStaticConfig)).default;
14
17
  export { serveStaticConfig };
@@ -1,11 +1,11 @@
1
- import { Command } from 'commander';
1
+ import { parseCliOptions } from '../../runtime/index.mjs';
2
2
  // Step-1: parse CLI arguments
3
- const options = new Command()
4
- .option('--ssrServerConfig <path>', 'Path to ./config/ssr-server.config.mts config file')
5
- .allowUnknownOption() // Bypass {error: unknown option '--config'}
6
- .allowExcessArguments() // Bypass {error: too many arguments. Expected 0 arguments but got 2.}
7
- .parse(process.argv)
8
- .opts();
3
+ const options = parseCliOptions([
4
+ {
5
+ commanderFlags: '--ssrServerConfig <path>',
6
+ description: 'Path to ./config/ssr-server.config.mts config file',
7
+ },
8
+ ]);
9
9
  // Step-2: load SSR server config from JSON file
10
10
  const ssrServerConfig = (await import(options.ssrServerConfig))
11
11
  .default;
@@ -36,12 +36,9 @@ function execImmediateCommand(fullCommandString) {
36
36
  *
37
37
  * Example: runStreamingCommand('rspack', ['serve', '--config', './config/rspack.config.ts']);
38
38
  */
39
- function runStreamingCommand(command, args) {
39
+ function runStreamingCommand(command, args, options = {}) {
40
40
  try {
41
- const child = spawn(command, args, {
42
- stdio: 'inherit',
43
- shell: true,
44
- });
41
+ const child = spawn(command, args, Object.assign({ stdio: 'inherit', shell: true }, options));
45
42
  // Track the process using ProcessManager as it could live in the background after crashing
46
43
  // Examples: server stacks when files removed while server is running
47
44
  // 1. rm -rf ./dist
@@ -0,0 +1,3 @@
1
+ import dotenv from '@dotenvx/dotenvx';
2
+ declare function initDotenv(): dotenv.DotenvConfigOutput;
3
+ export { initDotenv };
@@ -1,4 +1,5 @@
1
1
  export { NODE_ENV } from './constants.mjs';
2
2
  export type { NodeEnv } from './constants.mjs';
3
+ export { parseCliOptions } from './parse-cli-options.mjs';
3
4
  export { runtimePathById } from './path.mjs';
4
5
  export { resolveHostPackageBinForCLICommandPath, resolveHostPackageNodeModulesPath, } from './resolve-host-package.mjs';
@@ -0,0 +1,6 @@
1
+ type ParseCliOptionDescriptor = {
2
+ commanderFlags: string;
3
+ description?: string;
4
+ };
5
+ declare function parseCliOptions(options: ParseCliOptionDescriptor[]): import("commander").OptionValues;
6
+ export { parseCliOptions };
@@ -1,4 +1,5 @@
1
1
  import { Express } from 'express';
2
+ import type { Options } from 'http-proxy-middleware';
2
3
  interface ServeStaticConfig {
3
4
  rootPath?: string;
4
5
  publicPath?: string;
@@ -6,12 +7,14 @@ interface ServeStaticConfig {
6
7
  interface ExpressBaseAppConfig {
7
8
  listenPort?: number;
8
9
  serveStatics?: ServeStaticConfig[];
10
+ proxyConfigByPath?: Record<string, Options>;
9
11
  }
10
12
  declare class ExpressBaseApp {
11
13
  private readonly listenPort;
12
14
  readonly app: Express;
13
15
  constructor(customExpressConfig?: Partial<ExpressBaseAppConfig>);
14
16
  private appUseStatic;
17
+ private appUseProxyMiddleware;
15
18
  startListening(): void;
16
19
  }
17
20
  export { ExpressBaseApp };
@@ -1,3 +1,4 @@
1
+ import type { SpawnOptions } from 'child_process';
1
2
  declare function initProcessCatchErrorLogger(commandName: string, error: Error | unknown, commandParam?: string): void;
2
3
  /**
3
4
  * Executes a short-lived command synchronously.
@@ -12,7 +13,7 @@ declare function execImmediateCommand(fullCommandString: string): void;
12
13
  *
13
14
  * Example: runStreamingCommand('rspack', ['serve', '--config', './config/rspack.config.ts']);
14
15
  */
15
- declare function runStreamingCommand(command: string, args: string[]): import("child_process").ChildProcess | undefined;
16
+ declare function runStreamingCommand(command: string, args: string[], options?: SpawnOptions): import("child_process").ChildProcess | undefined;
16
17
  /**
17
18
  * Runs a streaming command in sync mode.
18
19
  * This is a placeholder function and does not execute any command.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mainset/cli",
3
- "version": "0.2.1-rc.2",
3
+ "version": "0.3.0-rc.1",
4
4
  "description": "A unified CLI tool for accelerating development, based on mainset vision of front-end infrastructure",
5
5
  "homepage": "https://github.com/mainset/dev-stack-fe/tree/main/packages/cli",
6
6
  "bugs": {
@@ -31,6 +31,7 @@
31
31
  "ms-cli": "./dist/esm/mainset-cli.mjs"
32
32
  },
33
33
  "dependencies": {
34
+ "@dotenvx/dotenvx": "^1.47.2",
34
35
  "@types/node": "^24.0.3",
35
36
  "commander": "^14.0.0",
36
37
  "cors": "^2.8.5",
@@ -42,10 +43,10 @@
42
43
  "@types/cors": "^2.8.19",
43
44
  "@types/express": "^5.0.3",
44
45
  "@types/node": "^24.0.3",
45
- "@mainset/dev-stack-fe": "^0.1.1"
46
+ "@mainset/dev-stack-fe": "^0.2.0-rc.1"
46
47
  },
47
48
  "peerDependencies": {
48
- "@mainset/dev-stack-fe": "^0.1.1"
49
+ "@mainset/dev-stack-fe": "^0.2.0"
49
50
  },
50
51
  "scripts": {
51
52
  "build:source": "node ./node_modules/@mainset/dev-stack-fe/node_modules/typescript/bin/tsc --project ./tsconfig.json",