@vercel/microfrontends
Version:
Defines configuration and utilities for microfrontends development
235 lines (228 loc) • 8.29 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/config/microfrontends/utils/index.ts
var utils_exports = {};
__export(utils_exports, {
findConfig: () => findConfig,
inferMicrofrontendsLocation: () => inferMicrofrontendsLocation
});
module.exports = __toCommonJS(utils_exports);
// src/config/microfrontends/utils/find-config.ts
var import_node_fs = __toESM(require("fs"), 1);
var import_node_path = require("path");
// src/config/constants.ts
var CONFIGURATION_FILENAMES = [
"microfrontends.jsonc",
"microfrontends.json"
];
// src/config/microfrontends/utils/find-config.ts
function findConfig({ dir }) {
for (const filename of CONFIGURATION_FILENAMES) {
const maybeConfig = (0, import_node_path.join)(dir, filename);
if (import_node_fs.default.existsSync(maybeConfig)) {
return maybeConfig;
}
}
return null;
}
// src/config/microfrontends/utils/infer-microfrontends-location.ts
var import_node_path2 = require("path");
var import_node_fs2 = require("fs");
var import_jsonc_parser = require("jsonc-parser");
var import_fast_glob = __toESM(require("fast-glob"), 1);
// src/config/errors.ts
var MicrofrontendError = class extends Error {
constructor(message, opts) {
super(message, { cause: opts?.cause });
this.name = "MicrofrontendsError";
this.source = opts?.source ?? "@vercel/microfrontends";
this.type = opts?.type ?? "unknown";
this.subtype = opts?.subtype;
Error.captureStackTrace(this, MicrofrontendError);
}
isKnown() {
return this.type !== "unknown";
}
isUnknown() {
return !this.isKnown();
}
/**
* Converts an error to a MicrofrontendsError.
* @param original - The original error to convert.
* @returns The converted MicrofrontendsError.
*/
static convert(original, opts) {
if (opts?.fileName) {
const err = MicrofrontendError.convertFSError(original, opts.fileName);
if (err) {
return err;
}
}
if (original.message.includes(
"Code generation from strings disallowed for this context"
)) {
return new MicrofrontendError(original.message, {
type: "config",
subtype: "unsupported_validation_env",
source: "ajv"
});
}
return new MicrofrontendError(original.message);
}
static convertFSError(original, fileName) {
if (original instanceof Error && "code" in original) {
if (original.code === "ENOENT") {
return new MicrofrontendError(`Could not find "${fileName}"`, {
type: "config",
subtype: "unable_to_read_file",
source: "fs"
});
}
if (original.code === "EACCES") {
return new MicrofrontendError(
`Permission denied while accessing "${fileName}"`,
{
type: "config",
subtype: "invalid_permissions",
source: "fs"
}
);
}
}
if (original instanceof SyntaxError) {
return new MicrofrontendError(
`Failed to parse "${fileName}": Invalid JSON format.`,
{
type: "config",
subtype: "invalid_syntax",
source: "fs"
}
);
}
return null;
}
/**
* Handles an unknown error and returns a MicrofrontendsError instance.
* @param err - The error to handle.
* @returns A MicrofrontendsError instance.
*/
static handle(err, opts) {
if (err instanceof MicrofrontendError) {
return err;
}
if (err instanceof Error) {
return MicrofrontendError.convert(err, opts);
}
if (typeof err === "object" && err !== null) {
if ("message" in err && typeof err.message === "string") {
return MicrofrontendError.convert(new Error(err.message), opts);
}
}
return new MicrofrontendError("An unknown error occurred");
}
};
// src/config/microfrontends/utils/infer-microfrontends-location.ts
var configCache = {};
function findPackageWithMicrofrontendsConfig({
repositoryRoot,
applicationName
}) {
try {
const microfrontendsJsonPaths = import_fast_glob.default.globSync(
`**/{${CONFIGURATION_FILENAMES.join(",")}}`,
{
cwd: repositoryRoot,
absolute: true,
onlyFiles: true,
followSymbolicLinks: false,
ignore: ["**/node_modules/**", "**/.git/**"]
}
);
const matchingPaths = [];
for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
try {
const microfrontendsJsonContent = (0, import_node_fs2.readFileSync)(
microfrontendsJsonPath,
"utf-8"
);
const microfrontendsJson = (0, import_jsonc_parser.parse)(microfrontendsJsonContent);
if (microfrontendsJson.applications[applicationName]) {
matchingPaths.push(microfrontendsJsonPath);
} else {
for (const [_, app] of Object.entries(
microfrontendsJson.applications
)) {
if (app.packageName === applicationName) {
matchingPaths.push(microfrontendsJsonPath);
}
}
}
} catch (error) {
}
}
if (matchingPaths.length > 1) {
throw new MicrofrontendError(
`Found multiple \`microfrontends.json\` files in the repository referencing the application "${applicationName}", but only one is allowed.
${matchingPaths.join("\n \u2022 ")}`,
{ type: "config", subtype: "inference_failed" }
);
}
if (matchingPaths.length === 0) {
throw new MicrofrontendError(
`Could not find a \`microfrontends.json\` file in the repository that contains "applications.${applicationName}". If your Vercel Microfrontends configuration is not in this repository, you can use the Vercel CLI to pull the Vercel Microfrontends configuration using the "vercel microfrontends pull" command, or you can specify the path manually using the VC_MICROFRONTENDS_CONFIG environment variable. If you suspect this is thrown in error, please reach out to the Vercel team.`,
{ type: "config", subtype: "inference_failed" }
);
}
const [packageJsonPath] = matchingPaths;
return (0, import_node_path2.dirname)(packageJsonPath);
} catch (error) {
return null;
}
}
function inferMicrofrontendsLocation(opts) {
const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;
if (configCache[cacheKey]) {
return configCache[cacheKey];
}
const result = findPackageWithMicrofrontendsConfig(opts);
if (!result) {
throw new MicrofrontendError(
`Could not infer the location of the \`microfrontends.json\` file for application "${opts.applicationName}" starting in directory "${opts.repositoryRoot}".`,
{ type: "config", subtype: "inference_failed" }
);
}
configCache[cacheKey] = result;
return result;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
findConfig,
inferMicrofrontendsLocation
});
//# sourceMappingURL=utils.cjs.map