zephyr-xpack-internal
Version:
Xpack internals for Zephyr
174 lines (173 loc) • 8.87 kB
JavaScript
import __rslib_shim_module__ from "node:module";
const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/ (()=>import.meta.url)());
import { dirname, resolve, sep } from "node:path";
import { ZeErrors } from "zephyr-agent";
import { extractFederatedConfig, isModuleFederationPlugin, parseRemotesAsEntries } from "../../../xpack-extract/index.mjs";
import { convertToGraph } from "../convert-to-graph/convert-to-graph.mjs";
import { AddRuntimeRequirementToPromiseExternal } from "./add-runtime-requirement-to-promise-external.mjs";
import { computeVersionStrategy, gitSha } from "./compute-version-strategy.mjs";
import { buildVersionedDependencyMap, findPackageJson, resolveInstalledPackageVersion } from "./find-package-json.mjs";
import { __webpack_require__ } from "../../../rslib-runtime~0.mjs";
import { createRequire as __rspack_createRequire } from "node:module";
const __rspack_createRequire_require = __rspack_createRequire(import.meta.url);
__webpack_require__.add({
"node:module" (module) {
module.exports = __rspack_createRequire_require("node:module");
}
});
const { createRequire: createProjectRequire } = __webpack_require__("node:module");
function resolveFederationGraphConfiguration(mfConfig, fallback, applicationName) {
const plugins = mfConfig ? Array.isArray(mfConfig) ? mfConfig : [
mfConfig
] : [];
const configurations = plugins.flatMap((plugin)=>{
const config = extractFederatedConfig(plugin);
return config ? [
config
] : [];
});
const resolvedConfigurations = configurations.length > 0 ? configurations : Object.keys(fallback).length > 0 ? [
fallback
] : [];
const remoteNames = [
...new Set(resolvedConfigurations.flatMap((config)=>parseRemotesAsEntries(config.remotes).map(([remoteName])=>remoteName)))
];
return {
configurations: resolvedConfigurations,
graphConfiguration: 1 === resolvedConfigurations.length ? resolvedConfigurations[0] : {
name: applicationName
},
remoteNames
};
}
class FederationDashboardPlugin {
_options;
_dashData;
allArgumentsUsed = [];
FederationPluginOptions = {};
constructor(options){
this._options = Object.assign({
debug: false,
useAST: false
}, options);
}
apply(compiler) {
compiler.options.output.uniqueName = `v${Date.now()}`;
new AddRuntimeRequirementToPromiseExternal().apply(compiler);
const FederationPlugin = compiler.options.plugins.find(isModuleFederationPlugin);
this._options.standalone = void 0 === FederationPlugin;
if (FederationPlugin) this.FederationPluginOptions = Object.assign({}, extractFederatedConfig(FederationPlugin), this._options.standalone || {});
else if (this._options.standalone) this.FederationPluginOptions = {};
else throw new Error('Dashboard plugin is missing Module Federation or standalone option');
}
processWebpackGraph({ stats, stats_json, pluginOptions }) {
const { configurations, graphConfiguration, remoteNames } = resolveFederationGraphConfiguration(pluginOptions.mfConfig, this.FederationPluginOptions, this._options.app?.name);
this.FederationPluginOptions = graphConfiguration;
const remoteEntryChunk = 1 === configurations.length ? this.getRemoteEntryChunk(stats_json, graphConfiguration) : void 0;
const validChunkArray = Array.from(new Set(configurations.flatMap((configuration)=>this.buildValidChunkArray(stats, configuration))));
const chunkDependencies = this.getChunkDependencies(validChunkArray);
const vendorFederation = this.buildVendorFederationMap(stats);
const getPlatformFromStats = stats.compilation.name;
const rawData = {
name: graphConfiguration.name,
filename: graphConfiguration.filename || '',
remotes: remoteNames,
metadata: Object.assign({}, this._options.metadata, this.attach_remote_bundle_name_to_metadata(configurations)) || {},
topLevelPackage: vendorFederation || {},
publicPath: stats_json.publicPath,
federationRemoteEntry: remoteEntryChunk,
buildHash: stats_json.hash,
environment: this._options.environment || 'development',
version: computeVersionStrategy(stats_json, this._options.versionStrategy),
posted: this._options.posted || new Date(),
group: this._options.group || 'default',
sha: gitSha,
modules: stats_json.modules,
chunkDependencies,
functionRemotes: this.allArgumentsUsed,
target: pluginOptions.target ?? pluginOptions.zephyr_engine.env.target ?? getPlatformFromStats
};
let graphData;
try {
graphData = convertToGraph(rawData);
} catch (err) {
console.warn('Error during dashboard data processing');
console.warn(err);
}
if (!graphData) return;
return graphData;
}
getRemoteEntryChunk(stats, FederationPluginOptions) {
if (!stats.chunks) return;
return stats.chunks.find((chunk)=>chunk.names?.find((name)=>name === FederationPluginOptions.name));
}
getChunkDependencies(validChunkArray) {
return validChunkArray.reduce((acc, chunk)=>{
const subset = chunk.getAllReferencedChunks();
const stringifiableChunk = Array.from(subset).map((sub)=>{
const cleanSet = Object.getOwnPropertyNames(sub).reduce((acc, key)=>{
if ('_groups' === key) return acc;
return Object.assign(acc, {
[key]: sub[key]
});
}, {});
return this.mapToObjectRec(cleanSet);
});
return Object.assign(acc, {
[`${chunk.id}`]: stringifiableChunk
});
}, {});
}
buildVendorFederationMap(liveStats) {
const vendorFederation = {};
let packageJson;
if (this._options.packageJsonPath) try {
packageJson = require(this._options.packageJsonPath);
} catch (error) {
console.warn(`Unable to read package JSON at ${this._options.packageJsonPath}: ${String(error)}`);
}
else {
const initialPath = liveStats.compilation.options.context?.split(sep);
packageJson = findPackageJson(initialPath);
}
if (packageJson) {
const resolveFrom = this._options.packageJsonPath ? dirname(this._options.packageJsonPath) : liveStats.compilation.options.context ?? process.cwd();
const projectRequire = createProjectRequire(resolve(resolveFrom, 'package.json'));
const resolveVersion = (packageName)=>resolveInstalledPackageVersion(packageName, projectRequire);
vendorFederation.dependencies = buildVersionedDependencyMap(packageJson, 'dependencies', resolveVersion);
vendorFederation.devDependencies = buildVersionedDependencyMap(packageJson, 'devDependencies', resolveVersion);
vendorFederation.optionalDependencies = buildVersionedDependencyMap(packageJson, 'optionalDependencies', resolveVersion);
}
return vendorFederation;
}
mapToObjectRec(m) {
const lo = {};
for (const [key, value] of Object.entries(m))if (value instanceof Map && value.size > 0) lo[key] = this.mapToObjectRec(value);
else if (value instanceof Set && value.size > 0) lo[key] = this.mapToObjectRec(Array.from(value));
else lo[key] = value;
return lo;
}
buildValidChunkArray(liveStats, FederationPluginOptions) {
if (!FederationPluginOptions.name) return [];
const namedChunkRefs = liveStats.compilation.namedChunks.get(FederationPluginOptions.name);
if (!namedChunkRefs) return [];
const AllReferencedChunksByRemote = namedChunkRefs.getAllReferencedChunks();
const validChunkArray = [];
for (const chunk of AllReferencedChunksByRemote)if (chunk.id !== FederationPluginOptions.name) validChunkArray.push(chunk);
return validChunkArray;
}
attach_remote_bundle_name_to_metadata(configurations = [
this.FederationPluginOptions
]) {
if (1 !== configurations.length) return;
const [configuration] = configurations;
if (!configuration?.exposes) return;
if (!configuration.bundle_name) return void console.warn(ZeErrors.ERR_MF_CONFIG_MISSING_FILENAME);
return {
remote_bundle_name: configuration.bundle_name
};
}
async postDashboardData() {}
}
export { FederationDashboardPlugin, resolveFederationGraphConfiguration };
//# sourceMappingURL=FederationDashboardPlugin.mjs.map