UNPKG

micro-iframe

Version:

a communication library for iframe-based micro-frontend integration

2 lines (1 loc) 10.6 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("mitt")):"function"==typeof define&&define.amd?define(["exports","mitt"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).MicroIframe={},e.mitt)}(this,(function(e,t){"use strict";class I{fromApp;targetApp;type;data;static MESSAGE_TYPE_PREFIX="MICRO_IFRAME_";constructor({fromApp:e,targetApp:t,type:I,data:i}){this.fromApp=e,this.targetApp=t,this.type=I,this.data=i}static isValid(e){return e&&"object"==typeof e&&"string"==typeof e.fromApp&&"string"==typeof e.targetApp&&"string"==typeof e.type&&"data"in e&&e.type&&e.type.startsWith(I.MESSAGE_TYPE_PREFIX)}static getRealMessage(e){return e.type=e.type.replace(I.MESSAGE_TYPE_PREFIX,""),e}static getRealMessageType(e){return e.replace(I.MESSAGE_TYPE_PREFIX,"")}}const i=t();function _(e){const t=[];try{return function e(I,i){const{name:_,iframeId:M,origin:R}=I,s=[...i,_];t.push({name:_,iframeId:M,origin:R,keyPath:s,children:I?.children?.map((e=>e.name))||[]}),I.children&&I.children.length>0&&I.children.forEach((t=>e(t,s)))}(e,[]),t}catch(e){throw console.error("[micro-iframe] flattenTreeWithKeyPath error:",e),new Error("[micro-iframe] 路由表数据结构不正确,解析失败,请检查!!!")}}class M{MICRO_IFRAME_ORIGIN_ROUTES={};MICRO_IFRAME_ROUTES=[];MICRO_IFRAME_CUR_ROUTE={};MICRO_IFRAME_NAME="";MICRO_IFRAME_OPTIONS={log:!1};static MICRO_IFRAME_EVENT={INIT_RESPONSE_CONFIG:`${I.MESSAGE_TYPE_PREFIX}INIT_RESPONSE_CONFIG`,INIT_REQUEST_CONFIG:`${I.MESSAGE_TYPE_PREFIX}INIT_REQUEST_CONFIG`};constructor(e,t,I){this.MICRO_IFRAME_NAME=e,this.MICRO_IFRAME_OPTIONS=Object.assign({},this.MICRO_IFRAME_OPTIONS,I);const i=_(t),M=i.find((t=>t.name===e));if(!M)throw new Error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: ${e} 在路由表中未找到匹配项, 请检查注册应用名称和路由表是否匹配`);this.MICRO_IFRAME_ORIGIN_ROUTES=t,this.MICRO_IFRAME_ROUTES=i,this.MICRO_IFRAME_CUR_ROUTE=M,console.log(`[micro-iframe] 主应用: ${this.MICRO_IFRAME_NAME}注册成功`),this.__init()}__handleIframeInitRequestConfigMessage(e){const t=document.getElementById(e.iframeId)?.contentWindow;if(t){const i=new I({fromApp:this.MICRO_IFRAME_NAME,targetApp:e.name,type:M.MICRO_IFRAME_EVENT.INIT_RESPONSE_CONFIG,data:this.MICRO_IFRAME_ORIGIN_ROUTES});t.postMessage(i,e.origin)}}__handleIframeForwardMessage(e){const t=this.MICRO_IFRAME_ROUTES.find((t=>t.name===e.targetApp));if(!t)return void(this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 转发消息, 消息目标应用${e.targetApp}未在路由表中注册,发送失败`));const I=t.keyPath.findIndex((e=>e===this.MICRO_IFRAME_NAME));if(-1===I||I+1>=t.keyPath.length)return void(this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 转发消息, 消息中间应用节点未找到,发送失败`));const i=t.keyPath[I+1],_=this.MICRO_IFRAME_ROUTES.find((e=>e.name===i));if(!_)return void(this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 转发消息, 消息中间应用${i}未在路由表中注册,发送失败`));const M=document.getElementById(_.iframeId||"")?.contentWindow;M?M.postMessage(e,_.origin):this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 转发消息, 消息中间应用目标窗口: ${_.iframeId}未找到, 发送失败`)}__checkMessageIsValid(e){if(!I.isValid(e?.data||{}))return void(this.MICRO_IFRAME_OPTIONS.log&&console.warn(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 接收到消息不符合micro-iframe规则, 该消息被丢弃`,e));return!!this.MICRO_IFRAME_ROUTES.find((t=>t.name===e.data.fromApp))||(this.MICRO_IFRAME_OPTIONS.log&&console.warn(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 接收到未在路由表注册消息,该消息被丢弃`,e),!1)}__init(){window.addEventListener("message",(e=>{if(this.MICRO_IFRAME_OPTIONS.log&&console.log(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用接收到消息:`,e),!this.__checkMessageIsValid(e))return;const t=new I(e?.data||{});if(t.type!==M.MICRO_IFRAME_EVENT.INIT_REQUEST_CONFIG)t.targetApp===this.MICRO_IFRAME_NAME?i.emit(I.getRealMessageType(t.type),I.getRealMessage(t)):this.__handleIframeForwardMessage(t);else{const t=this.MICRO_IFRAME_ROUTES.find((t=>t.name===e.data.fromApp));this.__handleIframeInitRequestConfigMessage(t)}}))}$on(e,t){i.on(e,t)}$emit(e,t,i){const _=this.MICRO_IFRAME_ROUTES.find((t=>t.name===e));if(_)if(this.MICRO_IFRAME_CUR_ROUTE.children.includes(e)){const M=new I({fromApp:this.MICRO_IFRAME_NAME,targetApp:e,type:`${I.MESSAGE_TYPE_PREFIX}${t}`,data:i}),R=document.getElementById(_.iframeId)?.contentWindow;R?R.postMessage(M,_.origin):this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 发送消息, 目标应用${e}的窗口${_.iframeId}未找到, 发送失败`)}else this.__handleIframeForwardMessage(new I({fromApp:this.MICRO_IFRAME_NAME,targetApp:e,type:`${I.MESSAGE_TYPE_PREFIX}${t}`,data:i}));else this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 发送消息, 目应用${e}在路由表中未注册, 发送失败`)}}class R{MICRO_IFRAME_ORIGIN_ROUTES={};MICRO_IFRAME_ROUTES=[];MICRO_IFRAME_CUR_ROUTE={};MICRO_IFRAME_IS_HANDSHAKE=!1;MICRO_IFRAME_NAME="";POWERED_BY_MICRO_IFRAME=!1;MICRO_IFRAME_OPTIONS={log:!1};static MICRO_IFRAME_EVENT={INIT_RESPONSE_CONFIG:`${I.MESSAGE_TYPE_PREFIX}INIT_RESPONSE_CONFIG`,INIT_REQUEST_CONFIG:`${I.MESSAGE_TYPE_PREFIX}INIT_REQUEST_CONFIG`};constructor(e,t){this.__init(e,t)}__handleIframeInitResponseConfigMessage(e){if(this.MICRO_IFRAME_IS_HANDSHAKE)return;const t=_(e.data),I=t.find((e=>e.name===this.MICRO_IFRAME_NAME));I?(this.MICRO_IFRAME_ORIGIN_ROUTES=e.data,this.MICRO_IFRAME_ROUTES=t,this.MICRO_IFRAME_CUR_ROUTE=I,this.POWERED_BY_MICRO_IFRAME=!0,this.MICRO_IFRAME_IS_HANDSHAKE=!0,console.log(`[micro-iframe] 子应用: ${this.MICRO_IFRAME_NAME}注册成功`),i.emit("iframe-ready",e)):this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: ${this.MICRO_IFRAME_NAME} 在路由表中未找到匹配项, 请检查注册应用名称和路由表是否匹配`)}__handleIframeInitRequestConfigMessage(e){const t=document.getElementById(e.iframeId)?.contentWindow;if(t){const i=new I({fromApp:this.MICRO_IFRAME_NAME,targetApp:e.name,type:R.MICRO_IFRAME_EVENT.INIT_RESPONSE_CONFIG,data:this.MICRO_IFRAME_ORIGIN_ROUTES});t.postMessage(i,e.origin)}}__handleIframeForwardMessage(e){const t=this.MICRO_IFRAME_ROUTES.find((t=>t.name===e.targetApp));if(t)if(t.keyPath.includes(this.MICRO_IFRAME_NAME)){const I=t.keyPath.findIndex((e=>e===this.MICRO_IFRAME_NAME));if(-1===I||I+1>=t.keyPath.length)return void(this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 转发消息, 消息中间应用节点未找到,发送失败`));const i=t.keyPath[I+1],_=this.MICRO_IFRAME_ROUTES.find((e=>e.name===i));if(!_)return void(this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 发送消息, 消息中间应用${i}未在路由表中注册, 发送失败`));const M=document.getElementById(_.iframeId)?.contentWindow;M?M.postMessage(e,_.origin):this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 发送消息, 目标应用${i}的窗口${t.iframeId}未找到, 发送失败`)}else{const I=this.__getTargetWindowFromKeyPath(t);I?.window?I?.window?.postMessage(e,I.hitMainApp?this.MICRO_IFRAME_ORIGIN_ROUTES.origin:t.origin):this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 发送消息, 目标应用${t}的窗口${t.iframeId}未找到, 发送失败`)}else this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 转发消息, 消息目标应用${e.targetApp}未在路由表中注册,发送失败`)}__getTargetWindowFromKeyPath(e){let t=null,I=!1;const i=Object.assign(this.MICRO_IFRAME_CUR_ROUTE.keyPath);for(let _=i.length-1;_>=0;_--)if(i[_]!==this.MICRO_IFRAME_NAME){if(i[_]===this.MICRO_IFRAME_ORIGIN_ROUTES.name){t=t?.parent,I=!0;break}if(i[_]===e.name){t=t?.parent;break}t=t?.parent}else t=window;return{window:t,hitMainApp:I}}__checkMessageIsValid(e){if(!I.isValid(e?.data||{}))return void(this.MICRO_IFRAME_OPTIONS.log&&console.warn(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 接收到消息不符合micro-iframe规则, 该消息被丢弃`,e));return!!this.MICRO_IFRAME_ROUTES.find((t=>t.name===e.data.fromApp))||(this.MICRO_IFRAME_OPTIONS.log&&console.warn(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 接收到未在路由表注册消息,该消息被丢弃`,e),!1)}__init(e,t){this.MICRO_IFRAME_NAME=e,this.MICRO_IFRAME_OPTIONS=Object.assign({},this.MICRO_IFRAME_OPTIONS,t);const _=new I({fromApp:this.MICRO_IFRAME_NAME,targetApp:"",type:R.MICRO_IFRAME_EVENT.INIT_REQUEST_CONFIG,data:void 0});window?.parent.postMessage(_,"*"),window.addEventListener("message",(e=>{if(this.MICRO_IFRAME_OPTIONS.log&&console.log(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用接收到消息:`,e),e?.data?.type===R.MICRO_IFRAME_EVENT.INIT_RESPONSE_CONFIG)return void this.__handleIframeInitResponseConfigMessage(e?.data||{});if(!this.__checkMessageIsValid(e))return;const t=new I(e?.data||{});if(t.type!==R.MICRO_IFRAME_EVENT.INIT_REQUEST_CONFIG)t.targetApp===this.MICRO_IFRAME_NAME?i.emit(I.getRealMessageType(t.type),I.getRealMessage(t)):this.__handleIframeForwardMessage(t);else{const t=this.MICRO_IFRAME_ROUTES.find((t=>t.name===e.data.fromApp));this.__handleIframeInitRequestConfigMessage(t)}}))}$on(e,t){i.on(e,t)}$emit(e,t,i){const _=this.MICRO_IFRAME_ROUTES.find((t=>t.name===e));if(_)if(this.MICRO_IFRAME_CUR_ROUTE.children.includes(e)){const M=new I({fromApp:this.MICRO_IFRAME_NAME,targetApp:e,type:`${I.MESSAGE_TYPE_PREFIX}${t}`,data:i}),R=document.getElementById(_.iframeId)?.contentWindow;R?R.postMessage(M,_.origin):this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 发送消息, 目标应用${e}的窗口${_.iframeId}未找到, 发送失败`)}else this.__handleIframeForwardMessage(new I({fromApp:this.MICRO_IFRAME_NAME,targetApp:e,type:`${I.MESSAGE_TYPE_PREFIX}${t}`,data:i}));else this.MICRO_IFRAME_OPTIONS.log&&console.error(`[micro-iframe]-[${this.MICRO_IFRAME_NAME}]应用: 发送消息, 目应用${e}在路由表中未注册, 发送失败`)}}e.MicroChildApp=R,e.MicroMainApp=M}));