时间:2022-08-12 16:57:02 | 来源:网站运营
时间:2022-08-12 16:57:02 来源:网站运营
系统名+Api做前缀
这样保障了各个系统之间的请求可以完全隔离。server { listen 80; server_name xxx.xx.com; location /project/api/ { set $upstream_name "server.project"; proxy_pass http://$upstream_name; } ... location / { set $upstream_name "web.portal"; proxy_pass http://$upstream_name; }}
我们将用户的统一登录和认证问题交给了SSO,所有的项目的后端Server都要接入SSO校验登录状态,从而保障业务系统间用户安全认证的一致性。let Router = <Router fetchMenu = {fetchMenuHandle} routes = {routes} app = {App} history = {history} >ReactDOM.render(Router,document.querySelector("#app"));
Router是在react-router的基础上做了一层封装,通过menu和routes最后生成一个如下所示的路由树: <Router> <Route path="/" component={App}> <Route path="/namespace/xx" component={About} /> <Route path="inbox" component={Inbox}> <Route path="messages/:id" component={Message} /> </Route> </Route> </Router>
具体注册使用了全局的window.app.routes
,“Portal项目”从window.app.routes
获取路由,“子项目”把自己需要注册的路由添加到window.app.routes
中,子项目的注册如下:let app = window.app = window.app || {}; app.routes = (app.routes || []).concat([{ code:'attendance-record', path: '/attendance-record', component: wrapper(() => async(require('./nodes/attendance-record'), 'kaoqin')),}]);
路由合并的同时也把具体的功能做了引用关联,再到构建时就可以把所有的功能与路由管理起来。项目的作用域要怎么控制呢?我们要求“子项目”间是彼此隔离,要避免样式污染,要做独立的数据流管理,我们用项目作用域的方式来解决这些问题。window.app
,我们也是通过这个全局App来做项目作用域的控制。window.app
包含了如下几部分:let app = window.app || {};app = { require:function(request){...}, define:function(name,context,index){...}, routes:[...], init:function(namespace,reducers){...} };
window.app主要功能:import reducers from './redux/kaoqin-reducer';let app = window.app = window.app || {}; app.routes = (app.routes || []).concat([{ code:'attendance-record', path: '/attendance-record', component: wrapper(() => async(require('./nodes/attendance-record'), 'kaoqin')), // ... 其他路由}]);function wrapper(loadComponent) { let React = null; let Component = null; let Wrapped = props => ( <div className="namespace-kaoqin"> <Component {...props} /> </div> ); return async () => { await window.app.init('namespace-kaoqin',reducers); React = require('react'); Component = await loadComponent(); return Wrapped; };}
其中做了这几件事情:window.app.init(namespace,reducers)
,注册项目作用域和数据流的reducersComponent
挂载在className
为namespace-kaoqin
的div
下面//webpack打包部分,在postcss插件中 添加namespace的控制config.postcss.push(postcss.plugin('namespace', () => css => css.walkRules(rule => { if (rule.parent && rule.parent.type === 'atrule' && rule.parent.name !== 'media') return; rule.selectors = rule.selectors.map(s => `.namespace-kaoqin ${s === 'body' ? '' : s}`); })));
CSS处理用到postcss-loader,postcss-loader用到postcss,我们添加postcss的处理插件,为每一个CSS选择器都添加名为.namespace-kaoqin
的根选择器,最后打包出来的CSS,如下所示:.namespace-kaoqin .attendance-record { height: 100%; position: relative}.namespace-kaoqin .attendance-record .attendance-record-content { font-size: 14px; height: 100%; overflow: auto; padding: 0 20px}...
CSS样式问题解决之后,接下来看一下,Portal提供的init做了哪些工作。let inited = false;let ModalContainer = null;app.init = async function (namespace,reducers) { if (!inited) { inited = true; let block = await new Promise(resolve => { require.ensure([], function (require) { app.define('block', require.context('block', true, /^/.//(?!dev)([^//]|//(?!demo))+/.jsx?$/)); resolve(require('block')); }, 'common'); }); ModalContainer = document.createElement('div'); document.body.appendChild(mtfv3ModalContainer); let { Modal} = block; Modal.getContainer = () => ModalContainer; } ModalContainer.setAttribute('class', `${namespace}`); mountReducers(namepace,reducers)};
init方法主要做了两件事情:app.define
的用法,它主要是用来处理JS公共库的控制,例如我们用到的组件库Block,期望每个“子项目”的版本都是统一的。因此我们需要解决JS公共库版本统一的问题。window.app.require
的方式引用,在编译“子项目”的时候,把引用公共库的代码从require('react')
全部替换为window.app.require('react')
,这样就可以将JS公共库的版本都交给“Portal项目”来控制了。/*** 重新定义包* @param name 引用的包名,例如 react* @param context 资源引用器 实际上是 webpackContext(是一个方法,来引用资源文件)* @param index 定义的包的入口文件*/app.define = function (name, context, index) { let keys = context.keys(); for (let key of keys) { let parts = (name + key.slice(1)).split('/'); let dir = this.modules; for (let i = 0; i < parts.length - 1; i++) { let part = parts[i]; if (!dir.hasOwnProperty(part)) { dir[part] = {}; } dir = dir[part]; } dir[parts[parts.length - 1]] = context.bind(context, key); } if (index != null) { this.modules[name]['index.js'] = this.modules[name][index]; }};//定义app的react //定义一个react资源库:把原来react根目录和lib目录下的.js全部获取到,绑定到新定义的react中,并指定react.js作为入口文件app.define('react', require.context('react', true, /^.//(lib//)?[^//]+/.js$/), 'react.js');app.define('react-dom', require.context('react-dom', true, /^.//index/.js$/));
“子项目”的构建,使用webpack的externals(外部扩展)来对引用进行替换:/** * 对一些公共包的引用做处理 通过webpack的externals(外部扩展)来解决 */const libs = ['react', 'react-dom', "block"];module.exports = function (context, request, callback) { if (libs.indexOf(request.split('/', 1)[0]) !== -1) { //如果文件的require路径中包含libs中的 替换为 window.app.require('${request}'); //var在这儿是声明的意思 callback(null, `var window.app.require('${request}')`); } else { callback(); }};
这样项目的注册就完成了,还有一些需要“子项目”自己改造的地方,例如本地启动需要把“Portal项目”的导航加载进来,需要做mock数据等等。node index.js
把服务启动起来。关键词:端的,方式