Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iframe sandbox #576

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions dev/children/react16/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion dev/children/react16/src/pages/inline/inline.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function Vue2 () {
{
showLoading && <Spin />
}
<micro-app-sub
<micro-app
name='inline'
url={`${config.vue2}micro-app/vue2/`}
data={data}
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
14 changes: 14 additions & 0 deletions src/create_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, AppInterface>()
Expand All @@ -32,6 +33,7 @@ export interface CreateAppParam {
name: string
url: string
ssrUrl?: string
sandboxType?: string
scopecss: boolean
useSandbox: boolean
inline?: boolean
Expand All @@ -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
Expand All @@ -69,6 +72,7 @@ export default class CreateApp implements AppInterface {
inline,
scopecss,
useSandbox,
sandboxType,
baseroute,
}: CreateAppParam) {
this.container = container ?? null
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/iframe/create.ts
Original file line number Diff line number Diff line change
@@ -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
}
11 changes: 11 additions & 0 deletions src/iframe/run.ts
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions src/micro_app_element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
})

Expand Down
14 changes: 5 additions & 9 deletions src/sandbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -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 () {
Expand Down
39 changes: 35 additions & 4 deletions src/source/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}

Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions typings/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down