時(shí)間:2022-08-12 16:57:02 | 來源:網(wǎng)站運(yùn)營
時(shí)間:2022-08-12 16:57:02 來源:網(wǎng)站運(yùn)營
系統(tǒng)名+Api做前綴
這樣保障了各個(gè)系統(tǒng)之間的請求可以完全隔離。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; }}
我們將用戶的統(tǒng)一登錄和認(rèn)證問題交給了SSO,所有的項(xiàng)目的后端Server都要接入SSO校驗(yàn)登錄狀態(tài),從而保障業(yè)務(wù)系統(tǒng)間用戶安全認(rèn)證的一致性。let Router = <Router fetchMenu = {fetchMenuHandle} routes = {routes} app = {App} history = {history} >ReactDOM.render(Router,document.querySelector("#app"));
Router是在react-router的基礎(chǔ)上做了一層封裝,通過menu和routes最后生成一個(gè)如下所示的路由樹: <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項(xiàng)目”從window.app.routes
獲取路由,“子項(xiàng)目”把自己需要注冊的路由添加到window.app.routes
中,子項(xiàng)目的注冊如下: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')),}]);
路由合并的同時(shí)也把具體的功能做了引用關(guān)聯(lián),再到構(gòu)建時(shí)就可以把所有的功能與路由管理起來。項(xiàng)目的作用域要怎么控制呢?我們要求“子項(xiàng)目”間是彼此隔離,要避免樣式污染,要做獨(dú)立的數(shù)據(jù)流管理,我們用項(xiàng)目作用域的方式來解決這些問題。window.app
,我們也是通過這個(gè)全局App來做項(xiàng)目作用域的控制。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)
,注冊項(xiàng)目作用域和數(shù)據(jù)流的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的處理插件,為每一個(gè)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,期望每個(gè)“子項(xiàng)目”的版本都是統(tǒng)一的。因此我們需要解決JS公共庫版本統(tǒng)一的問題。window.app.require
的方式引用,在編譯“子項(xiàng)目”的時(shí)候,把引用公共庫的代碼從require('react')
全部替換為window.app.require('react')
,這樣就可以將JS公共庫的版本都交給“Portal項(xiàng)目”來控制了。/*** 重新定義包* @param name 引用的包名,例如 react* @param context 資源引用器 實(shí)際上是 webpackContext(是一個(gè)方法,來引用資源文件)* @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 //定義一個(gè)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$/));
“子項(xiàng)目”的構(gòu)建,使用webpack的externals(外部擴(kuò)展)來對引用進(jìn)行替換:/** * 對一些公共包的引用做處理 通過webpack的externals(外部擴(kuò)展)來解決 */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(); }};
這樣項(xiàng)目的注冊就完成了,還有一些需要“子項(xiàng)目”自己改造的地方,例如本地啟動(dòng)需要把“Portal項(xiàng)目”的導(dǎo)航加載進(jìn)來,需要做mock數(shù)據(jù)等等。node index.js
把服務(wù)啟動(dòng)起來。關(guān)鍵詞:端的,方式
客戶&案例
營銷資訊
關(guān)于我們
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。