引言
前端私有化方案,这篇只讲述了整体的设计,没有涉及到技术细节,特此补充一下。
整个流程
启动阶段
使用的是cra,通过命令行的启动方式
PROJECT=XXX node scripts/start.js
package.json文件
......
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
},
......
补充说明:这里为啥没有把不同的项目写到package.json中,是因为项目增多的时候,这个项目命令会变得非常多,显得不友好,这个时候可以在readme.md中备注一下,项目对应的关系,知道启动哪一个项目即可。
A项目 -> A
B项目 -> B
webpack hook监听
function ProjectConfigPlugin() {
}
ProjectConfigPlugin.prototype.apply = function (compiler) {
compiler.plugin('environment', function () {
outPutPageSchema();
});
};
// 生成每个页面的schema文件
function outPutPageSchema() {
const dirPath = path.join(currentDirPath, 'projectConfig', project);
const dir = fs.readdirSync(dirPath);
dir.forEach(async fileTxt => {
const fileName = fileTxt.replace('.json', '');
const json = await fs.readJson(path.join(dirPath, fileTxt));
componentToDymaic(json);
const tpl = `
import loadable from '@loadable/component'
import { nodeProps } from "@/schema";
const schema: nodeProps = ${JSON.stringify(json, null, 2)}
export default schema
`;
//这里会直接将页面动态的写入到对应的page文件夹下面,方便页面加载
const outPath = path.join(currentDirPath, `src/pages/${fileName}`, `${fileName}.schema.ts`);
fs.outputFileSync(outPath, prettier.format(tpl).replace(/\"\$|\$\"/g, ''));
});
}
// 动态路径替换 这个指的是json文件中每个component的名称
function componentToDymaic(object) {
if (object.component) {
object.component = `$loadable(()=> import('@/components/${object.component}'))$`;
}
if (object.children) {
object.children.map(item => componentToDymaic(item));
}
}
module.exports = ProjectConfigPlugin;
项目json
{
"nodeType": "page", // 节点类型,方遍理解
"children": [ // react children
{
"nodeType": "header",
"component": "block/header", // 对应相应的组件,这个是组件的相对路径,hooks监听的时候会进行替换
"props": { // 这个组件需要的参数
"href": "xxxx,
"img": "xxxx"
}
},
{
"nodeType": "mainbody",
"component": "block/mainBody",
"props": {
"showChildrenIndex": 0
},
"children": [
{
"nodeType": "login",
"component": "block/login",
"props": {
"admin": {
"title": "xxxx",
"links": [
{
"label": "立即注册",
"href": "/login/register"
},
{
"label": "找回密码",
"href": "/login/reset"
}
],
"showProvider": true
},
"nomal": {
"title": "xxxx",
"loginSuccess": "/",
"openMfa": true,
"openIdaas": true,
"showProvider": true
}
}
}
]
}
]
}
注意:每个组件必须是实现react children,不然后续组件无法加载。
页面schema
import loadable from "@loadable/component";
import { nodeProps } from "@/schema";
const schema: nodeProps = {
nodeType: "page",
children: [
{
nodeType: "header",
// 这里及是上文提到的 替换成对应的组件
component: loadable(()=> import('@/components/block/header')),
props: {
href: "xxxx",
img: "xxxx",
},
},
{
nodeType: "mainbody",
component: loadable(()=> import('@/components/block/mainBody')),
props: {
showChildrenIndex: 0,
},
children: [
{
nodeType: "login",
component: loadable(()=> import('@/components/block/login')),
props: {
admin: {
title: "xxxx",
links: [
{
label: "立即注册",
href: "/login/register",
},
{
label: "找回密码",
href: "/login/reset",
},
],
showProvider: true,
},
nomal: {
title: "xxxx",
loginSuccess: "/",
openMfa: true,
openIdaas: true,
showProvider: true,
},
},
},
],
},
],
};
export default schema;
父组件会自动的加载子组件,从而一直加载完整个schema。
页面tsx
import a from 'a.schema.ts';
export default (props: any) => {
return (
<div>
{a.children}
</div>
)
最后
整个项目的配置话就是实现了