Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

[jsfm] Enhance the multi-instance isolation (sandbox) #960

Closed
wants to merge 5 commits into from
Closed
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
119 changes: 85 additions & 34 deletions html5/runtime/api/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { registerComponents } from './component'
import { services, register, unregister } from './service'
import { track } from '../bridge/debug'
import WeexInstance from './WeexInstance'
import { getDoc } from '../vdom/operation'

let frameworks
let runtimeConfig
Expand Down Expand Up @@ -71,12 +72,42 @@ function createServices (id, env, config) {
return serviceMap
}

const instanceMap = {}

const instanceTypeMap = {}
function getFrameworkType (id) {
if (instanceMap[id]) {
return instanceMap[id].framework
return instanceTypeMap[id]
}

function createInstanceContext (id, options = {}, data) {
const weex = new WeexInstance(id, options)
Object.freeze(weex)

const bundleType = options.bundleType || 'Vue'
instanceTypeMap[id] = bundleType
const framework = runtimeConfig.frameworks[bundleType]
if (!framework) {
return new Error(`[JS Framework] Invalid bundle type "${bundleType}".`)
}
track(id, 'bundleType', bundleType)

// prepare js service
const services = createServices(id, { weex, bundleType }, runtimeConfig)
Object.freeze(services)

// prepare runtime context
const runtimeContext = Object.create(null)
Object.assign(runtimeContext, services, {
weex,
services // Temporary compatible with some legacy APIs in Rax
})
Object.freeze(runtimeContext)

// prepare instance context
const instanceContext = Object.create(runtimeContext)
if (typeof framework.createInstanceContext === 'function') {
Object.assign(instanceContext, framework.createInstanceContext(id, runtimeContext, data))
}
Object.freeze(instanceContext)
return instanceContext
}

/**
Expand All @@ -88,35 +119,22 @@ function getFrameworkType (id) {
* @param {object} data
*/
function createInstance (id, code, config, data) {
if (instanceMap[id]) {
return new Error(`invalid instance id "${id}"`)
if (instanceTypeMap[id]) {
return new Error(`The instance id "${id}" has already been used!`)
}

// Init instance info.
const bundleType = getBundleType(code)
instanceTypeMap[id] = bundleType

// Init instance config.
config = JSON.parse(JSON.stringify(config || {}))
config.env = JSON.parse(JSON.stringify(global.WXEnvironment || {}))

const weex = new WeexInstance(id, config)
Object.freeze(weex)

const runtimeEnv = {
weex,
config, // TODO: deprecated
created: Date.now(),
framework: bundleType
}
runtimeEnv.services = createServices(id, runtimeEnv, runtimeConfig)
instanceMap[id] = runtimeEnv

const runtimeContext = Object.create(null)
Object.assign(runtimeContext, runtimeEnv.services, { weex })
config.bundleType = bundleType

const framework = runtimeConfig.frameworks[bundleType]
if (!framework) {
return new Error(`invalid bundle type "${bundleType}".`)
return new Error(`[JS Framework] Invalid bundle type "${bundleType}".`)
}
if (bundleType === 'Weex') {
console.error(`[JS Framework] COMPATIBILITY WARNING: `
Expand All @@ -126,14 +144,22 @@ function createInstance (id, code, config, data) {
+ `Please upgrade it to Vue.js or Rax.`)
}

track(id, 'bundleType', bundleType)

// run create instance
if (typeof framework.prepareInstanceContext === 'function') {
const instanceContext = framework.prepareInstanceContext(runtimeContext)
return runInContext(code, instanceContext)
const instanceContext = createInstanceContext(id, config, data)
if (typeof framework.createInstance === 'function') {
// Temporary compatible with some legacy APIs in Rax,
// some Rax page is using the legacy ".we" framework.
if (bundleType === 'Rax' || bundleType === 'Weex') {
const raxInstanceContext = Object.assign({
config,
created: Date.now(),
framework: bundleType
}, instanceContext)
return framework.createInstance(id, code, config, data, raxInstanceContext)
}
return framework.createInstance(id, code, config, data, instanceContext)
}
return framework.createInstance(id, code, config, data, runtimeEnv)
// console.error(`[JS Framework] Can't find available "createInstance" method in ${bundleType}!`)
runInContext(code, instanceContext)
}

/**
Expand All @@ -151,16 +177,35 @@ function runInContext (code, context) {

const bundle = `
(function (global) {
"use strict";
${code}
})(Object.create(this))
`

return (new Function(...keys, bundle))(...args)
}

/**
* Get the JSON object of the root element.
* @param {string} instanceId
*/
function getRoot (instanceId) {
const document = getDoc(instanceId)
try {
if (document && document.body) {
return document.body.toJSON()
}
}
catch (e) {
console.error(`[JS Framework] Failed to get the virtual dom tree.`)
return
}
}

const methods = {
createInstance,
createInstanceContext,
getRoot,
getDocument: getDoc,
registerService: register,
unregisterService: unregister,
callJS (id, tasks) {
Expand Down Expand Up @@ -200,12 +245,13 @@ function genInstance (methodName) {
destroy(id, { info, runtime: runtimeConfig })
}
})
delete instanceMap[id]
delete instanceTypeMap[id]
}

return result
}
return new Error(`invalid instance id "${id}"`)
return new Error(`[JS Framework] Using invalid instance id `
+ `"${id}" when calling ${methodName}.`)
}
}

Expand Down Expand Up @@ -240,14 +286,19 @@ export default function init (config) {
// `sendTasks(...args)`.
for (const name in frameworks) {
const framework = frameworks[name]
framework.init(config)
if (typeof framework.init === 'function') {
try {
framework.init(config)
}
catch (e) {}
}
}

adaptMethod('registerComponents', registerComponents)
adaptMethod('registerModules', registerModules)
adaptMethod('registerMethods')

; ['destroyInstance', 'refreshInstance', 'getRoot'].forEach(genInstance)
; ['destroyInstance', 'refreshInstance'].forEach(genInstance)

return methods
}
7 changes: 5 additions & 2 deletions html5/runtime/bridge/TaskCenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ export class TaskCenter {
return this.callbackManager.triggerHook(...args)
}

updateData (componentId, newData) {
this.callModule('dom', 'updateComponentData', [newData])
updateData (componentId, newData, callback) {
this.send('module', {
module: 'dom',
method: 'updateComponentData'
}, [componentId, newData, callback])
}

destroyCallback () {
Expand Down
5 changes: 0 additions & 5 deletions html5/test/unit/runtime/legacy-framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,6 @@ describe('framework entry', () => {
}
expect(json).to.be.deep.equal(expectJSON)
})

it('with a non-exist instanceId', () => {
const result = framework.getRoot('123')
expect(result).to.be.an.instanceof(Error)
})
})

describe('callJS', () => {
Expand Down
4 changes: 2 additions & 2 deletions html5/test/unit/runtime/runner/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ export function execute (type, code) {
const context = createContext()
return new Promise(resolve => {
const id = String(Date.now() + Math.random())
const instance = context.createInstance(id, `
context.createInstance(id, `
// { "framework": "${type}" }
${code}
`)
setTimeout(() => {
resolve(instance.document.body.toJSON())
resolve(context.getRoot(id))
}, 10)
})
}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "weex",
"version": "0.12.2",
"subversion": {
"framework": "0.22.4",
"framework": "0.23.6",
"transformer": ">=0.1.5 <0.5"
},
"description": "A framework for building Mobile cross-platform UI",
Expand Down Expand Up @@ -81,8 +81,8 @@
"query-string": "^4.2.3",
"semver": "^5.1.0",
"weex-picker": "^0.1.0",
"weex-rax-framework": "0.4.14",
"weex-vue-framework": "2.4.2-weex.6"
"weex-rax-framework": "0.4.20",
"weex-vue-framework": "2.5.11-weex.1"
},
"devDependencies": {
"@weex-project/weex-picker": "^0.2.4",
Expand Down
Loading