From 56181556a9dc495cd0b04ecc7b06886df08f258b Mon Sep 17 00:00:00 2001 From: LinFeng1997 Date: Fri, 2 Sep 2022 15:39:28 +0800 Subject: [PATCH 1/2] chore: init --- src/constants.ts | 2 +- src/create_app.ts | 14 ++++++++++++++ src/iframe/create.ts | 8 ++++++++ src/iframe/run.ts | 11 +++++++++++ src/micro_app_element.ts | 1 + src/sandbox/index.ts | 14 +++++--------- src/source/scripts.ts | 39 +++++++++++++++++++++++++++++++++++---- typings/global.d.ts | 1 + 8 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 src/iframe/create.ts create mode 100644 src/iframe/run.ts diff --git a/src/constants.ts b/src/constants.ts index 2eb4ee36d..53b2e22e0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -33,4 +33,4 @@ export enum keepAliveStates { KEEP_ALIVE_HIDDEN = 'KEEP_ALIVE_HIDDEN', } -export const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,Math,Number,Symbol,Date,Promise,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,Document,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,location,navigator,undefined' +export const globalKeyToBeCached = 'Array,Object,String,Boolean,Math,Number,Symbol,Date,Promise,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,Document,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,location,history,navigator,undefined' diff --git a/src/create_app.ts b/src/create_app.ts index 470d4d93c..11d73ec2b 100644 --- a/src/create_app.ts +++ b/src/create_app.ts @@ -23,6 +23,7 @@ import dispatchLifecyclesEvent, { dispatchCustomEventToMicroApp } from './intera import globalEnv from './libs/global_env' import { releasePatchSetAttribute } from './source/patch' import { getActiveApps } from './micro_app' +import { createIframe } from './iframe/create' // micro app instances export const appInstanceMap = new Map() @@ -32,6 +33,7 @@ export interface CreateAppParam { name: string url: string ssrUrl?: string + sandboxType?: string scopecss: boolean useSandbox: boolean inline?: boolean @@ -53,6 +55,7 @@ export default class CreateApp implements AppInterface { name: string url: string ssrUrl: string + sandboxType: string container: HTMLElement | ShadowRoot | null = null inline: boolean scopecss: boolean @@ -69,6 +72,7 @@ export default class CreateApp implements AppInterface { inline, scopecss, useSandbox, + sandboxType, baseroute, }: CreateAppParam) { this.container = container ?? null @@ -86,6 +90,7 @@ export default class CreateApp implements AppInterface { } this.loadSourceCode() this.useSandbox && (this.sandBox = new SandBox(name, url)) + this.sandboxType = sandboxType ?? 'default' } // Load resources @@ -161,6 +166,15 @@ export default class CreateApp implements AppInterface { cloneContainer(this.source.html as Element, this.container as Element, !this.umdMode) + // 初始化 iframe + if (this.sandboxType === 'iframe') { + const iframeId = `micro-app-iframe-${this.name}` + const iframe = createIframe(`micro-app-iframe-${this.name}`) + // @ts-ignore + window[iframeId] = iframe + this.container?.querySelector('micro-app-body')?.appendChild(iframe) + } + this.sandBox?.start(this.baseroute) let umdHookMountResult: any // result of mount function diff --git a/src/iframe/create.ts b/src/iframe/create.ts new file mode 100644 index 000000000..86a54edb1 --- /dev/null +++ b/src/iframe/create.ts @@ -0,0 +1,8 @@ +export const createIframe = (iframeId: string) => { + const iframe = document.createElement('iframe') + iframe.src = 'about:blank' + iframe.id = iframeId + iframe.style.display = 'none' + + return iframe +} diff --git a/src/iframe/run.ts b/src/iframe/run.ts new file mode 100644 index 000000000..ca9689c35 --- /dev/null +++ b/src/iframe/run.ts @@ -0,0 +1,11 @@ +import { pureCreateElement } from '../libs/utils' + +export const runCodeToIframe = (iframe: HTMLIFrameElement, proxyWindow:Window | undefined, code:string) => { + const iframeDoc = iframe.contentWindow?.document + + iframe.contentWindow && ((iframe.contentWindow as any).window.__MICRO_APP_PROXY_WINDOW__ = proxyWindow) + + const script = pureCreateElement('script') + script.textContent = code + iframeDoc?.body.appendChild(script) +} diff --git a/src/micro_app_element.ts b/src/micro_app_element.ts index bcc4c0e3f..6a958fe8a 100644 --- a/src/micro_app_element.ts +++ b/src/micro_app_element.ts @@ -309,6 +309,7 @@ export function defineElement (tagName: string): void { inline: this.getDisposeResult('inline'), scopecss: !(this.getDisposeResult('disableScopecss') || this.getDisposeResult('shadowDOM')), useSandbox: !this.getDisposeResult('disableSandbox'), + sandboxType: this.getAttribute('sandboxType') || 'default', baseroute: this.getBaseRouteCompatible(), }) diff --git a/src/sandbox/index.ts b/src/sandbox/index.ts index 40e229401..ac2f2a9d9 100644 --- a/src/sandbox/index.ts +++ b/src/sandbox/index.ts @@ -349,7 +349,7 @@ export default class SandBox implements SandBoxInterface { // set hijack Properties to microAppWindow private setHijackProperties (microAppWindow: microAppWindowType, appName: string): void { - let modifiedEval: unknown, modifiedImage: unknown + let modifiedImage: unknown rawDefineProperties(microAppWindow, { document: { get () { @@ -359,16 +359,12 @@ export default class SandBox implements SandBoxInterface { configurable: false, enumerable: true, }, - eval: { + location: { get () { - throttleDeferForSetAppName(appName) - return modifiedEval || eval - }, - set: (value) => { - modifiedEval = value + return globalEnv.rawWindow.location }, - configurable: true, - enumerable: false, + configurable: false, + enumerable: true, }, Image: { get () { diff --git a/src/source/scripts.ts b/src/source/scripts.ts index fea3cdfd6..0f542dc7b 100644 --- a/src/source/scripts.ts +++ b/src/source/scripts.ts @@ -25,6 +25,7 @@ import { import microApp from '../micro_app' import globalEnv from '../libs/global_env' import { globalKeyToBeCached } from '../constants' +import { runCodeToIframe } from '../iframe/run' type moduleCallBack = Func & { moduleCount?: number, errorCount?: number } @@ -287,7 +288,7 @@ export function runScript ( // TEST IGNORE app.container?.querySelector('micro-app-body')!.appendChild(scriptElement) } else { - runCode2Function(code, info) + runCode2Function(code, info, app) if (isDynamic) return document.createComment('dynamic script extract by micro-app') } } catch (e) { @@ -341,7 +342,7 @@ export function runDynamicRemoteScript ( if (app.inline || info.module) { runCode2InlineScript(url, code, info.module, replaceElement as HTMLScriptElement, dispatchScriptOnLoadEvent) } else { - runCode2Function(code, info) + runCode2Function(code, info, app) } } catch (e) { console.error(`[micro-app from runDynamicScript] app ${app.name}: `, e, url) @@ -389,10 +390,22 @@ function runCode2InlineScript ( } // init & run code2Function -function runCode2Function (code: string, info: sourceScriptInfo) { +function runCode2Function ( + code: string, + info: sourceScriptInfo, + app: AppInterface +) { + if (app.sandboxType === 'iframe') { + const iframeId = `micro-app-iframe-${app.name}` + const iframe = document.getElementById(iframeId) as HTMLIFrameElement + runCodeToIframe(iframe, app?.sandBox?.proxyWindow, code) + return + } + if (!info.code2Function) { info.code2Function = new Function(code) } + info.code2Function.call(window) } @@ -415,12 +428,30 @@ function bindScope ( if (app.sandBox && !info.module) { globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow - return `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);` + return app.sandboxType === 'iframe' + ? createIfameSandboxJSCode(code) + : `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);` } return code } +const createWithStatement = (code: string) => `with(window.__MICRO_APP_WINDOW__){${code}}` + +export const createIfameSandboxJSCode = (code: string): string => { + return `(function(window, self, global,globalThis,${globalKeyToBeCached}) { + // Angular 特殊处理 + var Zone = window.Zone; + ${createWithStatement(code)} +}).bind(window.__MICRO_APP_PROXY_WINDOW__)( + window.__MICRO_APP_PROXY_WINDOW__, + window.__MICRO_APP_PROXY_WINDOW__, + window.__MICRO_APP_PROXY_WINDOW__, + window.__MICRO_APP_PROXY_WINDOW__, + ${globalKeyToBeCached} +);` +} + /** * Call the plugin to process the file * @param url script address diff --git a/typings/global.d.ts b/typings/global.d.ts index 2873e6b13..71c7c393d 100644 --- a/typings/global.d.ts +++ b/typings/global.d.ts @@ -53,6 +53,7 @@ declare module '@micro-app/types' { baseroute: string // route prefix, default is '' source: sourceType // sources of css, js, html sandBox: SandBoxInterface | null // sandbox + sandboxType: string; umdMode: boolean // is umd mode // Load resources From 701b174c225a8440e5b1db4f868c4ff08f6a51d4 Mon Sep 17 00:00:00 2001 From: LinFeng1997 Date: Fri, 2 Sep 2022 15:48:22 +0800 Subject: [PATCH 2/2] chore: demo not support web component custom --- dev/children/react16/src/index.js | 6 +++--- dev/children/react16/src/pages/inline/inline.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/children/react16/src/index.js b/dev/children/react16/src/index.js index c754c8e8b..7d9ca3d21 100644 --- a/dev/children/react16/src/index.js +++ b/dev/children/react16/src/index.js @@ -10,9 +10,9 @@ import { Modal, notification } from 'antd'; import subMicroApp from '@micro-zoe/micro-app' // 循环内嵌 -subMicroApp.start({ - tagName: 'micro-app-sub' -}) +// subMicroApp.start({ +// tagName: 'micro-app-sub' +// }) // 数据监听 window.microApp?.addDataListener((data) => { diff --git a/dev/children/react16/src/pages/inline/inline.js b/dev/children/react16/src/pages/inline/inline.js index b66a3000f..d443cfb42 100644 --- a/dev/children/react16/src/pages/inline/inline.js +++ b/dev/children/react16/src/pages/inline/inline.js @@ -25,7 +25,7 @@ function Vue2 () { { showLoading && } -