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

Commit

Permalink
[jsfm] Enhance the multi-instance isolation (sandbox) (resolve #960)
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit fa7719f
Merge: 33ff3f0 11a1f3e
Author: Hanks <zhanghan.me@gmail.com>
Date:   Fri Dec 29 15:52:39 2017 +0800

    Merge branch 'master' into jsfm-feature-sandbox

commit 33ff3f0
Merge: 3d589d4 11a1f3e
Author: Hanks <zhanghan.me@gmail.com>
Date:   Fri Dec 29 15:51:51 2017 +0800

    Merge branch 'master' into jsfm-feature-sandbox

commit 3d589d4
Author: Hanks <zhanghan.me@gmail.com>
Date:   Fri Dec 29 15:38:47 2017 +0800

    * [jsfm] release v0.23.6

commit f8f8a15
Author: Hanks <zhanghan.me@gmail.com>
Date:   Thu Dec 28 12:18:12 2017 +0800

    * [jsfm] enhance the multi-instance isolation (sandbox)

    Use "createInstanceContext" instead of "createInstance".
    JS Framework only needs to prepare the instance context and no longer
    execute the js code. The js code will be executed by native.
    This *sandbox* feature requires native to cooperate to achieve.

commit 7c40162
Author: Hanks <zhanghan.me@gmail.com>
Date:   Thu Dec 28 12:15:29 2017 +0800

    * [jsfm] upgrade vue and rax

    upgrade weex-vue-framework to 2.5.11-weex.1
    upgrade weex-rax-framework to 0.4.20
  • Loading branch information
Hanks10100 committed Dec 29, 2017
1 parent 11a1f3e commit dc42844
Show file tree
Hide file tree
Showing 8 changed files with 2,998 additions and 2,142 deletions.
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

0 comments on commit dc42844

Please sign in to comment.