前端私有化方案-编译

413 阅读2分钟

引言

前端私有化方案,这篇只讲述了整体的设计,没有涉及到技术细节,特此补充一下。

整个流程

image.png

启动阶段

使用的是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> 
  )

最后

整个项目的配置话就是实现了

关联文章

前端私有化方案

前端登录页saas化