mfer 2.0.0 → 2.1.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
@@ -2,7 +2,6 @@
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![npm version](https://img.shields.io/npm/v/mfer.svg)](https://www.npmjs.com/package/mfer)
4
4
 
5
-
6
5
  A powerful CLI tool designed to simplify the management and execution of multiple micro frontend applications. mfer helps developers run, update, and organize their micro frontend projects with minimal configuration and maximum efficiency.
7
6
 
8
7
  ## 📋 Table of Contents
@@ -99,6 +98,7 @@ mfer pull frontend
99
98
  - [`mfer pull`](#mfer-pull-group_name) - Pull latest changes from git repositories
100
99
  - [`mfer install`](#mfer-install-group_name) - Install dependencies for micro frontends
101
100
  - [`mfer clone`](#mfer-clone-group_name) - Clone repositories that don't exist locally
101
+ - [`mfer lib`](#mfer-lib) - Manage internal npm packages
102
102
  - [`mfer config`](#mfer-config) - Manage configuration settings
103
103
  - [`mfer help`](#mfer-help) - Display help information
104
104
 
@@ -215,6 +215,87 @@ mfer help run # Show help for run command
215
215
  mfer help config # Show help for config command
216
216
  ```
217
217
 
218
+ ### `mfer lib`
219
+
220
+ Manage internal npm packages and their distribution to micro frontends.
221
+
222
+ **Subcommands:**
223
+
224
+ - [`mfer lib build`](#mfer-lib-build-lib-name) - Build internal npm packages
225
+ - [`mfer lib deploy`](#mfer-lib-deploy-lib-name) - Copy built libraries to micro frontends
226
+ - [`mfer lib publish`](#mfer-lib-publish-lib-name) - Build and deploy libraries to micro frontends
227
+ - [`mfer lib list`](#mfer-lib-list) - List configured libraries and their status
228
+
229
+ ### `mfer lib build [lib-name]`
230
+
231
+ Build internal npm packages.
232
+
233
+ **Arguments:**
234
+
235
+ - `lib-name`: Name of the library to build (builds all if not specified)
236
+
237
+ **Options:**
238
+
239
+ - `-s, --select`: Prompt to select which libraries to build
240
+
241
+ **Examples:**
242
+
243
+ ```bash
244
+ mfer lib build # Build all libraries
245
+ mfer lib build my-shared-utils # Build specific library
246
+ mfer lib build --select # Select libraries to build interactively
247
+ ```
248
+
249
+ ### `mfer lib deploy [lib-name]`
250
+
251
+ Copy built libraries to micro frontends.
252
+
253
+ **Arguments:**
254
+
255
+ - `lib-name`: Name of the library to deploy (deploys all if not specified)
256
+
257
+ **Options:**
258
+
259
+ - `-s, --select`: Prompt to select which libraries to deploy
260
+
261
+ **Examples:**
262
+
263
+ ```bash
264
+ mfer lib deploy # Deploy all libraries
265
+ mfer lib deploy my-shared-utils # Deploy specific library
266
+ mfer lib deploy --select # Select libraries to deploy interactively
267
+ ```
268
+
269
+ ### `mfer lib publish [lib-name]`
270
+
271
+ Build and deploy libraries to micro frontends.
272
+
273
+ **Arguments:**
274
+
275
+ - `lib-name`: Name of the library to publish (publishes all if not specified)
276
+
277
+ **Options:**
278
+
279
+ - `-s, --select`: Prompt to select which libraries to publish
280
+
281
+ **Examples:**
282
+
283
+ ```bash
284
+ mfer lib publish # Publish all libraries
285
+ mfer lib publish my-shared-utils # Publish specific library
286
+ mfer lib publish --select # Select libraries to publish interactively
287
+ ```
288
+
289
+ ### `mfer lib list`
290
+
291
+ List configured libraries and their status.
292
+
293
+ **Example:**
294
+
295
+ ```bash
296
+ mfer lib list # Show all configured libraries and their build status
297
+ ```
298
+
218
299
  ## ⚙️ Configuration
219
300
 
220
301
  mfer uses a YAML configuration file located at `~/.mfer/config.yaml`. Here's an example structure:
@@ -222,6 +303,11 @@ mfer uses a YAML configuration file located at `~/.mfer/config.yaml`. Here's an
222
303
  ```yaml
223
304
  base_github_url: "https://github.com/your-username"
224
305
  mfe_directory: "/path/to/your/micro-frontends"
306
+ lib_directory: "/path/to/your/internal-libs"
307
+ libs:
308
+ - my-shared-utils
309
+ - my-design-system
310
+ - my-common-components
225
311
  groups:
226
312
  all:
227
313
  - my-main-app
@@ -239,6 +325,8 @@ groups:
239
325
 
240
326
  - **`base_github_url`**: Your GitHub base URL for repository operations
241
327
  - **`mfe_directory`**: Path to the directory containing all your micro frontend projects
328
+ - **`lib_directory`**: Path to the directory containing your internal npm packages (optional)
329
+ - **`libs`**: List of internal npm package names to manage (optional)
242
330
  - **`groups`**: Named collections of micro frontend projects
243
331
  - **`all`**: Default group containing all projects (required)
244
332
  - **Custom groups**: Any additional groups you want to create
@@ -37,7 +37,7 @@ function createAndSaveConfig(githubUsername, mfeDirectory, allGroup = [], libDir
37
37
  console.log(chalk.yellow("Please replace 'my_mfe_1' and 'my_mfe_2' with your actual repository names."));
38
38
  }
39
39
  if (libDirectory && libs.length > 0) {
40
- console.log(chalk.green(`\nLibrary configuration added: ${libs.length} librar${libs.length === 1 ? 'y' : 'ies'} configured.`));
40
+ console.log(chalk.green(`\nLibrary configuration added: ${libs.length} librar${libs.length === 1 ? "y" : "ies"} configured.`));
41
41
  console.log(chalk.yellow("You can now use 'mfer lib build', 'mfer lib deploy', and 'mfer lib publish' commands."));
42
42
  }
43
43
  }
@@ -136,7 +136,7 @@ function promptForLibSelection(libs) {
136
136
  return yield checkbox({
137
137
  message: "Select which libraries to include in the configuration:",
138
138
  choices: libs.map((lib) => ({ name: lib, value: lib })),
139
- validate: (arr) => (arr.length > 0 ? true : "Select at least one library"),
139
+ validate: (arr) => arr.length > 0 ? true : "Select at least one library",
140
140
  });
141
141
  }
142
142
  catch (error) {
@@ -12,11 +12,14 @@ import chalk from "chalk";
12
12
  import { spawn } from "child_process";
13
13
  import * as fs from "fs";
14
14
  import * as path from "path";
15
+ import { checkbox } from "@inquirer/prompts";
15
16
  import { currentConfig, configExists, warnOfMissingConfig, } from "../../utils/config-utils.js";
16
17
  const buildCommand = new Command("build")
17
18
  .description("Build internal npm packages")
18
19
  .argument("[lib-name]", "Name of the library to build (builds all if not specified)")
19
- .action((libName) => __awaiter(void 0, void 0, void 0, function* () {
20
+ .option("-s, --select", "prompt to select which libraries to build")
21
+ .action((libName, options) => __awaiter(void 0, void 0, void 0, function* () {
22
+ var _a, _b;
20
23
  if (!configExists) {
21
24
  warnOfMissingConfig();
22
25
  return;
@@ -26,19 +29,47 @@ const buildCommand = new Command("build")
26
29
  console.log(chalk.yellow("Please run 'mfer init' to configure library settings."));
27
30
  return;
28
31
  }
29
- const libsToBuild = libName
30
- ? [libName].filter(lib => currentConfig.libs.includes(lib))
31
- : currentConfig.libs;
32
- if (libName && !currentConfig.libs.includes(libName)) {
33
- console.log(chalk.red(`Error: Library '${libName}' not found in configuration.`));
34
- console.log(chalk.yellow(`Available libraries: ${currentConfig.libs.join(", ")}`));
35
- return;
32
+ let libsToBuild;
33
+ if (options === null || options === void 0 ? void 0 : options.select) {
34
+ try {
35
+ console.log(chalk.blue(`Select libraries to build:`));
36
+ const selectedLibs = yield checkbox({
37
+ message: "Choose which libraries to build:",
38
+ choices: currentConfig.libs.map((lib) => ({ name: lib, value: lib })),
39
+ validate: (arr) => arr.length > 0 ? true : "Select at least one library",
40
+ });
41
+ libsToBuild = selectedLibs;
42
+ }
43
+ catch (error) {
44
+ if (error instanceof Error &&
45
+ (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("SIGINT")) ||
46
+ ((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes("User force closed")))) {
47
+ console.log(chalk.yellow("\nReceived SIGINT. Stopping..."));
48
+ process.exit(130);
49
+ }
50
+ throw error;
51
+ }
52
+ }
53
+ else {
54
+ libsToBuild = libName
55
+ ? [libName].filter((lib) => currentConfig.libs.includes(lib))
56
+ : currentConfig.libs;
57
+ if (libName && !currentConfig.libs.includes(libName)) {
58
+ console.log(chalk.red(`Error: Library '${libName}' not found in configuration.`));
59
+ console.log(chalk.yellow(`Available libraries: ${currentConfig.libs.join(", ")}`));
60
+ return;
61
+ }
36
62
  }
37
63
  if (libsToBuild.length === 0) {
38
64
  console.log(chalk.yellow("No libraries to build."));
39
65
  return;
40
66
  }
41
- console.log(chalk.blue(`Building ${libsToBuild.length} librar${libsToBuild.length === 1 ? 'y' : 'ies'}...`));
67
+ const libsText = (options === null || options === void 0 ? void 0 : options.select)
68
+ ? `selected libraries (${libsToBuild.length})`
69
+ : libName
70
+ ? `library '${libName}'`
71
+ : `all libraries (${libsToBuild.length})`;
72
+ console.log(chalk.blue(`Building ${libsText}...`));
42
73
  for (const lib of libsToBuild) {
43
74
  const libPath = path.join(currentConfig.lib_directory, lib);
44
75
  if (!fs.existsSync(libPath)) {
@@ -56,7 +87,7 @@ const buildCommand = new Command("build")
56
87
  }
57
88
  console.log(chalk.green("\nBuild process completed!"));
58
89
  }));
59
- function buildLibrary(libPath, libName) {
90
+ function buildLibrary(libPath, _libName) {
60
91
  return __awaiter(this, void 0, void 0, function* () {
61
92
  return new Promise((resolve, reject) => {
62
93
  const buildProcess = spawn("npm", ["run", "build"], {
@@ -11,11 +11,14 @@ import { Command } from "commander";
11
11
  import chalk from "chalk";
12
12
  import * as fs from "fs";
13
13
  import * as path from "path";
14
+ import { checkbox } from "@inquirer/prompts";
14
15
  import { currentConfig, configExists, warnOfMissingConfig, } from "../../utils/config-utils.js";
15
16
  const deployCommand = new Command("deploy")
16
17
  .description("Copy built libraries to micro frontends")
17
18
  .argument("[lib-name]", "Name of the library to deploy (deploys all if not specified)")
18
- .action((libName) => __awaiter(void 0, void 0, void 0, function* () {
19
+ .option("-s, --select", "prompt to select which libraries to deploy")
20
+ .action((libName, options) => __awaiter(void 0, void 0, void 0, function* () {
21
+ var _a, _b;
19
22
  if (!configExists) {
20
23
  warnOfMissingConfig();
21
24
  return;
@@ -25,20 +28,48 @@ const deployCommand = new Command("deploy")
25
28
  console.log(chalk.yellow("Please run 'mfer init' to configure library settings."));
26
29
  return;
27
30
  }
28
- const libsToDeploy = libName
29
- ? [libName].filter(lib => currentConfig.libs.includes(lib))
30
- : currentConfig.libs;
31
- if (libName && !currentConfig.libs.includes(libName)) {
32
- console.log(chalk.red(`Error: Library '${libName}' not found in configuration.`));
33
- console.log(chalk.yellow(`Available libraries: ${currentConfig.libs.join(", ")}`));
34
- return;
31
+ let libsToDeploy;
32
+ if (options === null || options === void 0 ? void 0 : options.select) {
33
+ try {
34
+ console.log(chalk.blue(`Select libraries to deploy:`));
35
+ const selectedLibs = yield checkbox({
36
+ message: "Choose which libraries to deploy:",
37
+ choices: currentConfig.libs.map((lib) => ({ name: lib, value: lib })),
38
+ validate: (arr) => arr.length > 0 ? true : "Select at least one library",
39
+ });
40
+ libsToDeploy = selectedLibs;
41
+ }
42
+ catch (error) {
43
+ if (error instanceof Error &&
44
+ (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("SIGINT")) ||
45
+ ((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes("User force closed")))) {
46
+ console.log(chalk.yellow("\nReceived SIGINT. Stopping..."));
47
+ process.exit(130);
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ else {
53
+ libsToDeploy = libName
54
+ ? [libName].filter((lib) => currentConfig.libs.includes(lib))
55
+ : currentConfig.libs;
56
+ if (libName && !currentConfig.libs.includes(libName)) {
57
+ console.log(chalk.red(`Error: Library '${libName}' not found in configuration.`));
58
+ console.log(chalk.yellow(`Available libraries: ${currentConfig.libs.join(", ")}`));
59
+ return;
60
+ }
35
61
  }
36
62
  if (libsToDeploy.length === 0) {
37
63
  console.log(chalk.yellow("No libraries to deploy."));
38
64
  return;
39
65
  }
40
- console.log(chalk.blue(`Deploying ${libsToDeploy.length} librar${libsToDeploy.length === 1 ? 'y' : 'ies'}...`));
41
- const mfeDirectories = currentConfig.groups.all.map(mfe => path.join(currentConfig.mfe_directory, mfe));
66
+ const libsText = (options === null || options === void 0 ? void 0 : options.select)
67
+ ? `selected libraries (${libsToDeploy.length})`
68
+ : libName
69
+ ? `library '${libName}'`
70
+ : `all libraries (${libsToDeploy.length})`;
71
+ console.log(chalk.blue(`Deploying ${libsText}...`));
72
+ const mfeDirectories = currentConfig.groups.all.map((mfe) => path.join(currentConfig.mfe_directory, mfe));
42
73
  for (const lib of libsToDeploy) {
43
74
  const libDistPath = path.join(currentConfig.lib_directory, lib, "dist");
44
75
  if (!fs.existsSync(libDistPath)) {
@@ -69,7 +100,7 @@ const deployCommand = new Command("deploy")
69
100
  }
70
101
  }
71
102
  if (deployedCount > 0) {
72
- console.log(chalk.green(`✓ ${lib} deployed to ${deployedCount} MFE${deployedCount === 1 ? '' : 's'}`));
103
+ console.log(chalk.green(`✓ ${lib} deployed to ${deployedCount} MFE${deployedCount === 1 ? "" : "s"}`));
73
104
  }
74
105
  else {
75
106
  console.log(chalk.yellow(`⚠ ${lib} not deployed (not found in any MFE's node_modules)`));
@@ -77,9 +108,9 @@ const deployCommand = new Command("deploy")
77
108
  }
78
109
  console.log(chalk.green("\nDeploy process completed!"));
79
110
  }));
80
- function copyLibraryToMfe(sourcePath, targetPath, libName) {
111
+ function copyLibraryToMfe(sourcePath, targetPath, _libName) {
81
112
  return __awaiter(this, void 0, void 0, function* () {
82
- return new Promise((resolve, reject) => {
113
+ return new Promise((resolve, _reject) => {
83
114
  if (fs.existsSync(targetPath)) {
84
115
  fs.rmSync(targetPath, { recursive: true, force: true });
85
116
  }
@@ -12,11 +12,14 @@ import chalk from "chalk";
12
12
  import { spawn } from "child_process";
13
13
  import * as fs from "fs";
14
14
  import * as path from "path";
15
+ import { checkbox } from "@inquirer/prompts";
15
16
  import { currentConfig, configExists, warnOfMissingConfig, } from "../../utils/config-utils.js";
16
17
  const publishCommand = new Command("publish")
17
18
  .description("Build and deploy libraries to micro frontends")
18
19
  .argument("[lib-name]", "Name of the library to publish (publishes all if not specified)")
19
- .action((libName) => __awaiter(void 0, void 0, void 0, function* () {
20
+ .option("-s, --select", "prompt to select which libraries to publish")
21
+ .action((libName, options) => __awaiter(void 0, void 0, void 0, function* () {
22
+ var _a, _b;
20
23
  if (!configExists) {
21
24
  warnOfMissingConfig();
22
25
  return;
@@ -26,20 +29,48 @@ const publishCommand = new Command("publish")
26
29
  console.log(chalk.yellow("Please run 'mfer init' to configure library settings."));
27
30
  return;
28
31
  }
29
- const libsToPublish = libName
30
- ? [libName].filter(lib => currentConfig.libs.includes(lib))
31
- : currentConfig.libs;
32
- if (libName && !currentConfig.libs.includes(libName)) {
33
- console.log(chalk.red(`Error: Library '${libName}' not found in configuration.`));
34
- console.log(chalk.yellow(`Available libraries: ${currentConfig.libs.join(", ")}`));
35
- return;
32
+ let libsToPublish;
33
+ if (options === null || options === void 0 ? void 0 : options.select) {
34
+ try {
35
+ console.log(chalk.blue(`Select libraries to publish:`));
36
+ const selectedLibs = yield checkbox({
37
+ message: "Choose which libraries to publish:",
38
+ choices: currentConfig.libs.map((lib) => ({ name: lib, value: lib })),
39
+ validate: (arr) => arr.length > 0 ? true : "Select at least one library",
40
+ });
41
+ libsToPublish = selectedLibs;
42
+ }
43
+ catch (error) {
44
+ if (error instanceof Error &&
45
+ (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("SIGINT")) ||
46
+ ((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes("User force closed")))) {
47
+ console.log(chalk.yellow("\nReceived SIGINT. Stopping..."));
48
+ process.exit(130);
49
+ }
50
+ throw error;
51
+ }
52
+ }
53
+ else {
54
+ libsToPublish = libName
55
+ ? [libName].filter((lib) => currentConfig.libs.includes(lib))
56
+ : currentConfig.libs;
57
+ if (libName && !currentConfig.libs.includes(libName)) {
58
+ console.log(chalk.red(`Error: Library '${libName}' not found in configuration.`));
59
+ console.log(chalk.yellow(`Available libraries: ${currentConfig.libs.join(", ")}`));
60
+ return;
61
+ }
36
62
  }
37
63
  if (libsToPublish.length === 0) {
38
64
  console.log(chalk.yellow("No libraries to publish."));
39
65
  return;
40
66
  }
41
- console.log(chalk.blue(`Publishing ${libsToPublish.length} librar${libsToPublish.length === 1 ? 'y' : 'ies'}...`));
42
- const mfeDirectories = currentConfig.groups.all.map(mfe => path.join(currentConfig.mfe_directory, mfe));
67
+ const libsText = (options === null || options === void 0 ? void 0 : options.select)
68
+ ? `selected libraries (${libsToPublish.length})`
69
+ : libName
70
+ ? `library '${libName}'`
71
+ : `all libraries (${libsToPublish.length})`;
72
+ console.log(chalk.blue(`Publishing ${libsText}...`));
73
+ const mfeDirectories = currentConfig.groups.all.map((mfe) => path.join(currentConfig.mfe_directory, mfe));
43
74
  for (const lib of libsToPublish) {
44
75
  const libPath = path.join(currentConfig.lib_directory, lib);
45
76
  if (!fs.existsSync(libPath)) {
@@ -80,7 +111,7 @@ const publishCommand = new Command("publish")
80
111
  }
81
112
  }
82
113
  if (deployedCount > 0) {
83
- console.log(chalk.green(` ✓ ${lib} published to ${deployedCount} MFE${deployedCount === 1 ? '' : 's'}`));
114
+ console.log(chalk.green(` ✓ ${lib} published to ${deployedCount} MFE${deployedCount === 1 ? "" : "s"}`));
84
115
  }
85
116
  else {
86
117
  console.log(chalk.yellow(` ⚠ ${lib} not deployed (not found in any MFE's node_modules)`));
@@ -88,7 +119,7 @@ const publishCommand = new Command("publish")
88
119
  }
89
120
  console.log(chalk.green("\nPublish process completed!"));
90
121
  }));
91
- function buildLibrary(libPath, libName) {
122
+ function buildLibrary(libPath, _libName) {
92
123
  return __awaiter(this, void 0, void 0, function* () {
93
124
  return new Promise((resolve, reject) => {
94
125
  const buildProcess = spawn("npm", ["run", "build"], {
@@ -110,9 +141,9 @@ function buildLibrary(libPath, libName) {
110
141
  });
111
142
  });
112
143
  }
113
- function copyLibraryToMfe(sourcePath, targetPath, libName) {
144
+ function copyLibraryToMfe(sourcePath, targetPath, _libName) {
114
145
  return __awaiter(this, void 0, void 0, function* () {
115
- return new Promise((resolve, reject) => {
146
+ return new Promise((resolve, _reject) => {
116
147
  if (fs.existsSync(targetPath)) {
117
148
  fs.rmSync(targetPath, { recursive: true, force: true });
118
149
  }
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { loadConfig } from "./utils/config-utils.js";
11
11
  program
12
12
  .name("mfer")
13
13
  .description("Micro Frontend Runner (mfer) - A CLI for running your project's micro frontends.")
14
- .version("2.0.0", "-v, --version", "mfer CLI version")
14
+ .version("2.1.0", "-v, --version", "mfer CLI version")
15
15
  .hook("preAction", () => {
16
16
  console.log();
17
17
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mfer",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "CLI tool designed to sensibly run micro-frontends from the terminal.",
5
5
  "bin": {
6
6
  "mfer": "dist/index.js"