module-federation-exposes-webpack-plugin
Version:
Create module federation exposes config
139 lines (138 loc) • 6.78 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateExposes = exports.getExportContent = void 0;
const ts_morph_1 = require("ts-morph");
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
/** 根据语法类型过滤节点,返回数组 */
function filterNodeBySyntaxKind(nodes, kind) {
return nodes
.filter((node) => node.getKind() === kind)
.map((node) => node.getText());
}
/** 根据语法类型过滤节点,返回对象 */
function findNodeBySyntaxKind(nodes, kind) {
var _a;
return (_a = filterNodeBySyntaxKind(nodes, kind)) === null || _a === void 0 ? void 0 : _a[0];
}
/** 根据导出index文件获取导出内容 */
const getExportContent = (path, transform) => {
const project = new ts_morph_1.Project();
// 添加源代码
const source = project.addSourceFileAtPath(path);
const content = [];
source.forEachChild((item) => {
var _a;
const text = item.getText();
// 不处理非导出类型语法
if (item.getKind() !== ts_morph_1.SyntaxKind.ExportDeclaration) {
return;
}
// 不处理导出类型
if (text.startsWith("export type")) {
return;
}
const nodes = item.forEachDescendantAsArray();
// 参考 https://github.com/estree/estree/blob/master/es2015.md#exports
// export { get } from 'module' => ['get']
// export { get as myGet } from 'module' => ['get as myGet']
// export { get, pick as myPick } from 'module' => ['get', 'pick as myPick']
// export { default as Module, get } from 'module' => ['default as Module', 'get']
// export * as module from 'module' => undefined
const exportSpecifier = filterNodeBySyntaxKind(nodes, ts_morph_1.SyntaxKind.ExportSpecifier);
// export { get as myGet } from 'module' => ['get', 'myGet']
// export { get, pick } from 'module' => ['get', 'pick']
// export { get, pick as myPick } from 'module' => ['get', 'pick', 'myPick']
// export { default as Module, get } from 'module' => ['default', 'Module', 'get']
// export * as module from 'module' => []
const identifiers = filterNodeBySyntaxKind(nodes, ts_morph_1.SyntaxKind.Identifier);
// 如果是*号导出时有值,此时identifiers返回为空数组
// export * as module from 'module' => '* as module'
// export { get } from 'module' => undefined
const namespaceExport = findNodeBySyntaxKind(nodes, ts_morph_1.SyntaxKind.NamespaceExport);
// export { get } from 'module' => 'module'
const stringLiteral = findNodeBySyntaxKind(nodes, ts_morph_1.SyntaxKind.StringLiteral);
const libraryName = (transform === null || transform === void 0 ? void 0 : transform(stringLiteral)) || stringLiteral;
// 跳过此次循环的下标
let breakIndex = -1;
for (let i = 0; i < identifiers.length; i++) {
if (breakIndex === i) {
continue;
}
const identifier = identifiers[i];
const reNamedIdentifier = identifier === "default" ? "default" : `${identifier} as default`;
// 是否有重命名导出,如get as myGet, default as Utils
const isRenamedExport = (_a = exportSpecifier === null || exportSpecifier === void 0 ? void 0 : exportSpecifier[i]) === null || _a === void 0 ? void 0 : _a.includes(" as ");
// 如果有默认导出, 则跳过下一次循环
if (isRenamedExport) {
breakIndex = i + 1;
content.push({
name: identifiers[i + 1],
content: `export { ${reNamedIdentifier} } from ${libraryName};`,
});
continue;
}
// 如果包含*号导出
if (namespaceExport === null || namespaceExport === void 0 ? void 0 : namespaceExport.includes("* as")) {
content.push({
name: identifier,
content: `export * as default from ${libraryName};`,
});
continue;
}
content.push({
name: identifier,
content: `export { ${reNamedIdentifier} } from ${libraryName};`,
});
}
});
return content;
};
exports.getExportContent = getExportContent;
/** 生成导出文件 */
function generateExposesFile(dir, content, filetype) {
return __awaiter(this, void 0, void 0, function* () {
// 生成目录时先删除旧目录数据
yield fs_extra_1.default.remove(dir);
// 删除后重新创建目录
yield fs_extra_1.default.mkdir(dir);
for (const item of content) {
const filepath = path_1.default.resolve(dir, `${item.name}.${filetype}`);
yield fs_extra_1.default.writeFile(filepath, item.content);
}
});
}
/** 生成模块联邦exposes JSON配置 */
function generateExposesJson(dir, content) {
return __awaiter(this, void 0, void 0, function* () {
const filename = path_1.default.resolve(dir, "index.json");
// 目录名称
const dirName = path_1.default.basename(dir);
const map = {};
content.forEach((item) => {
map[`./${item.name}`] = `./${dirName}/${item.name}`;
});
yield fs_extra_1.default.writeFile(filename, JSON.stringify(map, null, 2));
});
}
function generateExposes(options) {
return __awaiter(this, void 0, void 0, function* () {
const { exportFile, generateDir, filetype = "ts", transform } = options;
const content = (0, exports.getExportContent)(exportFile, transform);
yield generateExposesFile(generateDir, content, filetype);
yield generateExposesJson(generateDir, content);
});
}
exports.generateExposes = generateExposes;