mfer 1.4.2 → 1.5.0

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/README.md CHANGED
@@ -123,11 +123,22 @@ Run micro frontend applications concurrently.
123
123
 
124
124
  - `group_name`: Name of the group to run (defaults to "all")
125
125
 
126
- **Example:**
126
+ **Options:**
127
+
128
+ - `-c, --command <command>`: Custom command to run (default: npm start)
129
+ - `-a, --async`: Run custom command concurrently instead of sequentially
130
+ - `-s, --select`: Prompt to select which micro frontends to run
131
+
132
+ **Examples:**
127
133
 
128
134
  ```bash
129
- mfer run # Run all micro frontends
130
- mfer run frontend # Run only frontend group
135
+ mfer run # Run all micro frontends with default command (npm start)
136
+ mfer run frontend # Run only frontend group with default command
137
+ mfer run --command "npm ci" home # Run custom command sequentially on home group
138
+ mfer run -c "yarn install" shared # Run yarn install sequentially on shared group
139
+ mfer run --command "npm ci" --async home # Run custom command concurrently on home group
140
+ mfer run -c "yarn install" -a shared # Run yarn install concurrently on shared group
141
+ mfer run --command "npm run build" --select # Select MFEs and run build command sequentially
131
142
  ```
132
143
 
133
144
  ### `mfer pull [group_name]`
@@ -13,17 +13,32 @@ import concurrently from "concurrently";
13
13
  import chalk from "chalk";
14
14
  import path from "path";
15
15
  import { checkbox } from "@inquirer/prompts";
16
- const RUN_COMMAND = "npm start";
16
+ import { spawn } from "child_process";
17
+ const DEFAULT_RUN_COMMAND = "npm start";
17
18
  const runCommand = new Command("run")
18
19
  .description("run micro-frontend applications")
19
20
  .argument("[group_name]", "name of the group as specified in the configuration", "all")
20
21
  .option("-s, --select", "prompt to select which micro frontends to run")
22
+ .option("-c, --command <command>", "custom command to run (default: npm start)")
23
+ .option("-a, --async", "run custom command concurrently instead of sequentially")
21
24
  .action((groupName, options) => __awaiter(void 0, void 0, void 0, function* () {
22
25
  var _a, _b;
23
26
  if (!configExists) {
24
27
  warnOfMissingConfig();
25
28
  return;
26
29
  }
30
+ if (options.command &&
31
+ typeof options.command === "string" &&
32
+ options.command.trim() === "") {
33
+ const messagePrefix = chalk.red("Error");
34
+ console.log(`${messagePrefix}: custom command cannot be empty`);
35
+ return;
36
+ }
37
+ if (options.async && !options.command) {
38
+ const messagePrefix = chalk.red("Error");
39
+ console.log(`${messagePrefix}: --async can only be used with --command option`);
40
+ return;
41
+ }
27
42
  const group = currentConfig.groups[groupName];
28
43
  if (!group) {
29
44
  const messagePrefix = chalk.red("Error");
@@ -57,45 +72,91 @@ const runCommand = new Command("run")
57
72
  }
58
73
  }
59
74
  const mfeDir = currentConfig.mfe_directory;
60
- const commands = selectedMFEs.map((mfe) => ({
61
- command: RUN_COMMAND,
62
- name: mfe,
63
- cwd: path.join(mfeDir, mfe),
64
- prefixColor: "blue",
65
- }));
75
+ const commandToRun = options.command || DEFAULT_RUN_COMMAND;
76
+ const isAsync = options.async && options.command;
66
77
  const groupText = options.select
67
78
  ? `selected MFEs from group '${groupName}'`
68
79
  : `group '${groupName}'`;
69
- console.log(chalk.green(`Running micro frontends in ${groupText}...`));
70
- const concurrentlyResult = concurrently(commands, {
71
- prefix: "{name} |",
72
- killOthersOn: ["failure", "success"],
73
- restartTries: 0,
74
- });
75
- const handleSigint = () => {
76
- console.log(chalk.yellow("\nReceived SIGINT. Stopping all micro frontends..."));
77
- concurrentlyResult.commands.forEach((cmd) => {
78
- if (cmd && typeof cmd.kill === "function") {
79
- cmd.kill();
80
+ const commandText = options.command
81
+ ? `custom command '${commandToRun}'`
82
+ : "default command";
83
+ const executionMode = isAsync ? "concurrently" : "sequentially";
84
+ console.log(chalk.green(`Running ${commandText} on micro frontends in ${groupText} ${executionMode}...`));
85
+ if (isAsync || !options.command) {
86
+ yield runConcurrently(selectedMFEs, commandToRun, mfeDir);
87
+ }
88
+ else {
89
+ yield runSequentially(selectedMFEs, commandToRun, mfeDir);
90
+ }
91
+ }));
92
+ function runSequentially(mfes, command, mfeDir) {
93
+ return __awaiter(this, void 0, void 0, function* () {
94
+ for (const mfe of mfes) {
95
+ const cwd = path.join(mfeDir, mfe);
96
+ console.log(chalk.blue(`\n[${mfe}] Running: ${command}`));
97
+ try {
98
+ const result = yield new Promise((resolve) => {
99
+ const child = spawn(command, [], {
100
+ stdio: "inherit",
101
+ cwd,
102
+ shell: true,
103
+ });
104
+ child.on("close", (exitCode) => {
105
+ resolve({ exitCode });
106
+ });
107
+ child.on("error", (error) => {
108
+ console.error(chalk.red(`[${mfe}] Error: ${error.message}`));
109
+ resolve({ exitCode: 1 });
110
+ });
111
+ });
112
+ if (result.exitCode !== 0) {
113
+ console.error(chalk.red(`[${mfe}] Command failed with exit code ${result.exitCode}`));
114
+ }
80
115
  }
116
+ catch (error) {
117
+ console.error(chalk.red(`[${mfe}] Unexpected error: ${error}`));
118
+ }
119
+ }
120
+ });
121
+ }
122
+ function runConcurrently(mfes, command, mfeDir) {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ const commands = mfes.map((mfe) => ({
125
+ command,
126
+ name: mfe,
127
+ cwd: path.join(mfeDir, mfe),
128
+ prefixColor: "blue",
129
+ }));
130
+ const concurrentlyResult = concurrently(commands, {
131
+ prefix: "{name} |",
132
+ killOthersOn: ["failure", "success"],
133
+ restartTries: 0,
81
134
  });
82
- process.exit(0);
83
- };
84
- process.once("SIGINT", handleSigint);
85
- concurrentlyResult.result.then(() => { }, (err) => {
86
- console.error(chalk.red("One or more micro frontends failed to start."));
87
- if (Array.isArray(err)) {
88
- err.forEach((fail) => {
89
- var _a, _b;
90
- const name = ((_a = fail.command) === null || _a === void 0 ? void 0 : _a.name) || "unknown";
91
- const exitCode = fail.exitCode;
92
- const cwd = ((_b = fail.command) === null || _b === void 0 ? void 0 : _b.cwd) || "unknown";
93
- console.error(chalk.yellow(` MFE ${name} failed to start (cwd: ${cwd}) with exit code ${exitCode}`));
135
+ const handleSigint = () => {
136
+ console.log(chalk.yellow("\nReceived SIGINT. Stopping all micro frontends..."));
137
+ concurrentlyResult.commands.forEach((cmd) => {
138
+ if (cmd && typeof cmd.kill === "function") {
139
+ cmd.kill();
140
+ }
94
141
  });
95
- }
96
- else if (err && typeof err === "object" && "message" in err) {
97
- console.error(err.message);
98
- }
142
+ process.exit(0);
143
+ };
144
+ process.once("SIGINT", handleSigint);
145
+ concurrentlyResult.result.then(() => { }, (err) => {
146
+ console.error(chalk.red("One or more micro frontends failed to start."));
147
+ if (Array.isArray(err)) {
148
+ err.forEach((fail) => {
149
+ var _a, _b;
150
+ const name = ((_a = fail.command) === null || _a === void 0 ? void 0 : _a.name) || "unknown";
151
+ const exitCode = fail.exitCode;
152
+ const cwd = ((_b = fail.command) === null || _b === void 0 ? void 0 : _b.cwd) || "unknown";
153
+ console.error(chalk.yellow(` MFE ${name} failed to start (cwd: ${cwd}) with exit code ${exitCode}`));
154
+ });
155
+ }
156
+ else if (err && typeof err === "object" && "message" in err) {
157
+ console.error(err.message);
158
+ }
159
+ });
99
160
  });
100
- }));
161
+ }
101
162
  export default runCommand;
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { loadConfig } from "./utils/config-utils.js";
10
10
  program
11
11
  .name("mfer")
12
12
  .description("Micro Frontend Runner (mfer) - A CLI for running your project's micro frontends.")
13
- .version("1.4.2", "-v, --version", "mfer CLI version")
13
+ .version("1.5.0", "-v, --version", "mfer CLI version")
14
14
  .hook("preAction", () => {
15
15
  console.log();
16
16
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mfer",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "CLI tool designed to sensibly run micro-frontends from the terminal.",
5
5
  "bin": {
6
6
  "mfer": "dist/index.js"