@ali-i18n-fe/dada-component
Version:
259 lines (227 loc) • 7.72 kB
JavaScript
const {
getProgram,
} = require("@ali-i18n-fe/react-docgen-typescript-loader-add-tag/dist/loader");
const {
withDefaultConfig,
} = require("@ali-i18n-fe/react-docgen-typescript-loader-add-tag/dist/docgen-typescript");
const requireFromString = require("require-from-string");
const { buildVisionFromTypes } = require("@ali-i18n-fe/json-2-vision").default;
const path = require("path");
const fs = require("fs");
const throttle = require("lodash/throttle");
const set = require("lodash/set");
const {
getStoryPathByFilePath,
getPreviewPathByFilePath,
} = require("../utils");
const { wrapJsDom } = require("../../utils/wrapWindow");
const localVisionPaths = [];
const pluginName = "VisionConfigPlugin";
// const Module = require("module");
// get the instance and original require
// let firstInstance;
// const originalRequire = Module.prototype.require;
// Module.prototype.require = function() {
// if (!firstInstance) {
// firstInstance = this;
// }
// return {};
// };
// require("");
// Module.prototype.require = originalRequire;
class VisionConfigPlugin {
constructor(options = {}) {
this.name = pluginName;
this.options = Object.assign(
{},
{
// 是否排除没有在 src/index.ts 中导出的组件类型
isFilterExport: false,
},
options
);
}
apply(compiler) {
// 循环寻找dependency性能影响太大,暂不开启
// const requireNormalModule = normalModule => {
// const { dependencies } = normalModule;
//
// // rewrite require to load modules
// const originalRequireChild = Module.prototype.require;
// Module.prototype.require = function(moduleName) {
// if (/core-js|babel-runtime/.test(moduleName)) {
// return {};
// }
// if (/@ali|moment|lodash/.test(moduleName)) {
// return {};
// }
//
// const dependency = dependencies.find(
// ({ request }) => request === moduleName
// );
// const { module: moduleFound } = dependency || {};
//
// if (/^\./.test(moduleName)) {
// if (moduleFound && moduleFound._source) {
// try {
// return requireNormalModule(moduleFound);
// } catch (e) {
// debugger;
// }
// }
// }
//
// try {
// return originalRequire.apply(this, arguments);
// } catch (e) {
// debugger;
// }
// };
// Module.prototype.require.originalRequireChild = originalRequireChild;
//
// const source = normalModule._source._value;
// const exportModules = requireFromString(source);
//
// Module.prototype.require = originalRequireChild;
//
// return exportModules;
// };
//
// const indexModule = compilation.modules.find(module =>
// new RegExp(path.resolve(context.rootPath, "/src/index.ts") + "x?$").test(
// module.resource
// )
// );
let parser, program;
compiler.hooks.emit.tap(pluginName, (compilation) => {
// Add file dependencies
const getSource = throttle(() => {
let moduleNames;
const targetMap = {};
try {
// const { default: exportModules } = wrapJsDom(requireNormalModule)(
// indexModule
// );
// dev 环境下收到webpack-dev-server的影响,暂不开启Map过滤
if (
compiler.options.mode === "production" &&
!!compilation.assets["index.js"]
) {
const exportModules = wrapJsDom(requireFromString)(
compilation.assets["index.js"].source()
);
if (
(typeof exportModules === "function" ||
(typeof exportModules === "object" &&
typeof exportModules.$$typeof === "symbol" &&
typeof exportModules.render === "function")) &&
"displayName" in exportModules
) {
// single component
moduleNames = new Set([exportModules.displayName]);
} else {
moduleNames = new Set(Object.keys(exportModules));
}
}
} catch (e) {
// console.log(e);
}
const filePaths = program
.getRootFileNames()
.filter((fileName) => !/docs\.tsx?$/.test(fileName))
.filter((fileName) => !/\.d\.ts$/.test(fileName));
filePaths.forEach((filePath) => {
const componentDocs = parser.parseWithProgramProvider(
filePath,
() => program
);
componentDocs.forEach((compDocs) => {
const { displayName, tags } = compDocs;
const annotationConfig = Object.entries(tags).reduce(
(previousValue, [key, value]) => {
if (/^vision\./.test(key)) {
const { vision } = set({}, key, value);
return Object.assign(previousValue, vision);
}
return Object.assign(previousValue, {
[key]: value,
});
},
{}
);
// 过滤未暴露的组件
if (!moduleNames || moduleNames.has(displayName)) {
const previewFile = path.resolve(filePath, "..", "docs.tsx");
const isExistPreview = fs.existsSync(previewFile);
const typeVisionConfig = buildVisionFromTypes(compDocs, {
defaultConfig: Object.assign(
{},
{
__previewPath:
isExistPreview &&
getPreviewPathByFilePath(
{
_compiler: compiler,
},
filePath
),
__storyPath:
isExistPreview &&
getStoryPathByFilePath(
{
_compiler: compiler,
},
filePath
),
},
annotationConfig,
getVisionDefault(filePath)
),
});
targetMap[typeVisionConfig.componentName] = typeVisionConfig;
}
});
});
return targetMap;
}, 10000);
parser = withDefaultConfig({});
program = getProgram(path.resolve(process.cwd(), "src"));
const targetPath = "vision.config.json";
compilation.assets[targetPath] = {
size() {
return JSON.stringify(getSource()).length;
},
source() {
return JSON.stringify(getSource());
},
};
});
compiler.hooks.afterEmit.tap(pluginName, (compilation) => {
// Add file dependencies
compilation.fileDependencies.add("vision.config.json");
// console.log("#################", localVisionPaths);
localVisionPaths.forEach((filePath) => {
compilation.fileDependencies.add(filePath);
});
});
}
}
function getVisionPath(filePath) {
return path.resolve(filePath, "..", "vision.config.json");
}
function getVisionDefault(filePath) {
const visionPath = getVisionPath(filePath);
try {
if (!fs.existsSync(visionPath)) {
return null;
}
const visionResult = JSON.parse(fs.readFileSync(visionPath, "utf8"));
if (!localVisionPaths.includes(visionPath)) {
localVisionPaths.push(visionPath);
}
return visionResult;
} catch (e) {
return null;
}
}
module.exports = VisionConfigPlugin;