@microup/master

1.0.0-main-1.0.0.20230823203256 • Public • Published

master

master 包主要负责状态数据的存储,权限校验与重定向、顶层路由处理、多语言等工作。所有的 remote 模块都会经过 master 代码控制然后渲染。

目前未添加权限,多语言模块,如有需要可自行在master添加。

全局的事件触发,通用数据也都可以添加到 master 内,并且这些数据共享,可完成不同模块间数据通信。

store

masterStore 是通过 mobx 进行实现的状态数据池,它可以存储一些全局动态的状态数据,并且在所有 remote 模块中都可以访问到这些数据。

源码

masterStore 的核心代码如下,用于注册一个 Store

import React from 'react';
import {observer, useLocalObservable} from 'mobx-react';
import {runInAction} from 'mobx';
import { Provider } from 'mobx-react';

interface IIssue {
  // data
}

const useMainLocalStore = () => {
  const masterStore = useLocalObservable(() => ({
    data: {} as IIssue,
    get(key: string) {
      return masterStore.data[key]
    },
    set(key, value) {
      runInAction(function () {
        masterStore.data[key] = value
      })
    }
  }));
  return masterStore;
};

const MasterStoreProvider: React.FC<any> = observer((props) => {
  const {children} = props;
  const masterStore = useMainLocalStore();
  return <Provider masterStore={masterStore}>{children}</Provider>;
});

export {MasterStoreProvider};

包裹跟节点

import React from 'react';
……
import {MasterStoreProvider} from './store';
……
const InnerIndex = (props) => {
  const {match, AutoRouter} = props
  return (
    <MasterStoreProvider>
      ……
    </MasterStoreProvider>
  )
};

export default withRouter(InnerIndex);

使用

可以实现不同 remote 模块间数据通信,也可以使得一个模块触发另一个模块的视图渲染。

测试案例如下:

开启一个 app1 服务作为 host 模块,它可以以一下两种方式访问 remote 模块,一种访问其中 remote 模块注册的一个组件,第二种访问整个的 remote 模块,详情也可查看 app1 与 app2 包的代码。

app1 作为 host 模块

import React from 'react';
import {ExternalComponent} from '@microup/utils';
import {inject, observer} from 'mobx-react';

export default inject('masterStore')(observer((props) => {
  const {history, masterStore} = props
  return (
  <div>
    <button onClick={() => {
      masterStore.set('app2Test', !masterStore.get('app2Test'))
    }}>点击改变 app2Test 变量
    </button>
    <h5>引入 app2 externalize 组件</h5>
    <ExternalComponent
      system={{
        scope: 'app2', module: 'App2EC',
      }}
    />
    <h5>全量引入 app2 模块</h5>
    <div style={{borderLeft: "2px black solid",paddingLeft:'8px'}}>
      <ExternalComponent
        {...props}
        match={{...props.master, url: '/app1'}}
        system={{
          scope: 'app2', module: './app2',
        }}
      />
    </div>
  </div>
  )
}))

app2 externalize 组件

import React from 'react';
import {observer,inject} from 'mobx-react';

export default inject('masterStore')(observer(({match, masterStore}) => {
return (<div>app2-externalize-components | app2Test: 	{String(!!masterStore.get('app2Test'))}</div>);
}))
/* externalize: App2EC */

app2 根目录

import React from 'react';
import {Route, Switch} from 'react-router-dom';
import {inject} from 'mobx-react';
import {ErrorPage} from '@microup/master';

const Page1 = React.lazy(() => import('./routes/Page1'));
const Page2 = React.lazy(() => import('./routes/Page2'));

function Index({match, masterStore}) {
  return (
    <Switch>
      <Route path={`${match.url}/page1`} component={Page1}/>
      <Route path={`${match.url}/page2`} component={Page2}/>
      <Route path={`${match.url}`} component={Page1}/>
      <Route path="*" component={ErrorPage}/>
    </Switch>
  );
}

export default inject('masterStore')(Index);

app2 page1

import React from 'react';
import {inject, observer} from 'mobx-react';

export default inject('masterStore')(observer((props) => {
  const {match, masterStore} = props
  return (<div>
    app2 page1 | app2Test: {String(!!masterStore.get('app2Test'))}
  </div>)
}));

master router

moaster router 控制这整个项目的跟路由,路由优先判断是否是/error_page或者/undefined进行全局的错误路由拦截,过滤后的路由会转入 AutoRouter,在 AutoRouter 组件中会处理一级路由并分发到对应 remote 模块

master.jsx

const InnerIndex = (props) => {
  const {match, AutoRouter} = props
  return (
    <MasterStoreProvider>
      <Switch>
        <Route exact path={`${match.url}${match.url === '/' ? '' : '/'}error_page`} component={ErrorPage}/>
        <Route exact path={`${match.url}${match.url === '/' ? '' : '/'}undefined`} component={Empty}/>
        <Route path={match.url} component={AutoRouter}/>
      </Switch>
    </MasterStoreProvider>
  )
};

AutoRouter 组件位置在 routes.nunjucks.jsx 编译后在 tmp 目录中的 router.index.js 中,tmp 详情参考 boot 包文档。

一级路由处理

在 AutoRouter 中执行了这样代码,其作用是优先匹配 config.js 中设置的 routes 中的路由,如果匹配成功,则访问本地路由组件。

routes 作用是一级路由与对应组件位置的描述

# 只是本地开发
routes: {
  a1: './src/exampleMaster/App1', # 路由为 http://192.168.20.133:9091/#/a1/
  a2: './src/exampleMaster/App2' # 路由为 http://192.168.20.133:9091/#/a2/
}
const AutoRouter = () => (
  <Suspense fallback={<Loading/>}>
    <CacheSwitch>
      {'{{ routes }}'}
      <CacheRoute path="*">
        <ExternalRoute />
      </CacheRoute>
    </CacheSwitch>
  </Suspense>
);

如果没有匹配成功,则执行 <ExternalRoute /> 组件,匹配对应 remote 模块。

<ExternalRoute /> 组件中,根据.env中配置的STATIC_URL作为基地址,后边拼接 url 地址中的一级路由与/importManifest.js生成一个新的地址,类似http://192.168.20.101:9095/a1/importManifest.js

然后创建一个新的script标签src 填入上边生成的地址。远程拉取 importManifest.js 代码,实现 remote 模块间连接。(实现方案详情参考动态远程容器

通常我们会有很多 remote 模块,在 host 模块访问多个 remote 模块时,我们不想在代码中把所有地址都写出来( 类似 STATIC_URL-a1,STATIC_URL-a2 这样,会比较麻烦)。这时我可以创建一个独立的 nginx 帮我们代理。

例如所有模块都访问 http://192.168.20.101:9095/a1/importManifest.js ,而 192.168.20.133:9095 中设置 nginx 做对应的反向代理

# STATIC_URL 对应的 nginx
location /a1/ { # app1 remote 模块
	proxy_pass http://192.168.20.101:9091/;
}
location /a2/ { # app2 remote 模块
	proxy_pass http://192.168.20.123:9092/;
}

这样我们访问 http://192.168.20.101:9095/a1/importManifest.js 他会根据一级路由 a1 判断访问 http://192.168.20.101:9091/a1/importManifest.js 然后拿到 js 静态文件做对应渲染。

Package Sidebar

Install

npm i @microup/master

Weekly Downloads

0

Version

1.0.0-main-1.0.0.20230823203256

License

MIT

Unpacked Size

14.4 kB

Total Files

9

Last publish

Collaborators

  • wuzhan