Skip to content

Commit

Permalink
refactor(weex): Adjust the weex platform entry file to fit the new we…
Browse files Browse the repository at this point in the history
…ex runtime (vuejs#6620)

* trim trailing whitespace

* revert(weex): remove the new Function hack for V8, as Weex uses JSC now

Remove the `callFunctionNative` method and `compileBundle`, which is provided by modified V8. In
order to maintain the consistency of the js engine, Weex also use JSC on Android. The legacy hack
for V8 engine should be removed.

* refactor(weex): move module and component apis to weex runtime

Modules and components should be registered in weex runtime, not the specific framework. The
`registerModules`, `registerComponents`, `weex.supports` and `weex.requireModule` api is moved to
weex runtime, which is in the "apache/incubator-weex" repo.

* test(weex): refactor the test cases to fit the new weex-js-runtime

* fix(weex): use document instead of renderer to create Element
  • Loading branch information
Hanks10100 authored and yyx990803 committed Sep 18, 2017
1 parent 4441e0f commit 2deda3d
Show file tree
Hide file tree
Showing 13 changed files with 525 additions and 1,318 deletions.
2 changes: 1 addition & 1 deletion build/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const banner =

const weexFactoryPlugin = {
intro () {
return 'module.exports = function weexFactory (exports, renderer) {'
return 'module.exports = function weexFactory (exports, document) {'
},
outro () {
return '}'
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,7 @@
"typescript": "^2.3.4",
"uglify-js": "^3.0.15",
"webpack": "^2.6.1",
"weex-js-runtime": "^0.20.5",
"weex-vdom-tester": "^0.2.0"
"weex-js-runtime": "^0.22.0"
},
"config": {
"commitizen": {
Expand Down
232 changes: 16 additions & 216 deletions src/platforms/weex/entry-framework.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,19 @@
import TextNode from 'weex/runtime/text-node'

// this will be preserved during build
const VueFactory = require('./factory')

const instances = {}
const modules = {}
const components = {}

const renderer = {
TextNode,
instances,
modules,
components
}

/**
* Prepare framework config, basically about the virtual-DOM and JS bridge.
* @param {object} cfg
* Prepare framework config.
* Nothing need to do actually, just an interface provided to weex runtime.
*/
export function init (cfg) {
renderer.Document = cfg.Document
renderer.Element = cfg.Element
renderer.Comment = cfg.Comment
renderer.compileBundle = cfg.compileBundle
}
export function init () {}

/**
* Reset framework config and clear all registrations.
*/
export function reset () {
clear(instances)
clear(modules)
clear(components)
delete renderer.Document
delete renderer.Element
delete renderer.Comment
delete renderer.compileBundle
}

/**
Expand Down Expand Up @@ -63,47 +41,31 @@ export function createInstance (
data,
env = {}
) {
// Virtual-DOM object.
const document = new renderer.Document(instanceId, config.bundleUrl)

const weex = env.weex
const document = weex.document
const instance = instances[instanceId] = {
instanceId, config, data,
document
}

// Prepare native module getter and HTML5 Timer APIs.
const moduleGetter = genModuleGetter(instanceId)
const timerAPIs = getInstanceTimer(instanceId, moduleGetter)

// Prepare `weex` instance variable.
const weexInstanceVar = {
config,
document,
supports,
requireModule: moduleGetter
}
Object.freeze(weexInstanceVar)
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)

// Each instance has a independent `Vue` module instance
const Vue = instance.Vue = createVueModuleInstance(instanceId, moduleGetter)
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)

// The function which create a closure the JS Bundle will run in.
// It will declare some instance variables like `Vue`, HTML5 Timer APIs etc.
const instanceVars = Object.assign({
Vue,
weex: weexInstanceVar
weex
}, timerAPIs, env.services)

appCode = `(function(global){ \n${appCode}\n })(Object.create(this))`

if (!callFunctionNative(instanceVars, appCode)) {
// If failed to compile functionBody on native side,
// fallback to 'callFunction()'.
callFunction(instanceVars, appCode)
}
callFunction(instanceVars, appCode)

// Send `createFinish` signal to native.
instance.document.taskCenter.send('dom', { action: 'createFinish' }, [])
document.taskCenter.send('dom', { action: 'createFinish' }, [])

return instance
}
Expand All @@ -118,6 +80,8 @@ export function destroyInstance (instanceId) {
if (instance && instance.app instanceof instance.Vue) {
instance.document.destroy()
instance.app.$destroy()
delete instance.document
delete instance.app
}
delete instances[instanceId]
}
Expand Down Expand Up @@ -200,91 +164,12 @@ export function receiveTasks (id, tasks) {
return new Error(`invalid instance id "${id}" or tasks`)
}

/**
* Register native modules information.
* @param {object} newModules
*/
export function registerModules (newModules) {
for (const name in newModules) {
if (!modules[name]) {
modules[name] = {}
}
newModules[name].forEach(method => {
if (typeof method === 'string') {
modules[name][method] = true
} else {
modules[name][method.name] = method.args
}
})
}
}

/**
* Check whether the module or the method has been registered.
* @param {String} module name
* @param {String} method name (optional)
*/
export function isRegisteredModule (name, method) {
if (typeof method === 'string') {
return !!(modules[name] && modules[name][method])
}
return !!modules[name]
}

/**
* Register native components information.
* @param {array} newComponents
*/
export function registerComponents (newComponents) {
if (Array.isArray(newComponents)) {
newComponents.forEach(component => {
if (!component) {
return
}
if (typeof component === 'string') {
components[component] = true
} else if (typeof component === 'object' && typeof component.type === 'string') {
components[component.type] = component
}
})
}
}

/**
* Check whether the component has been registered.
* @param {String} component name
*/
export function isRegisteredComponent (name) {
return !!components[name]
}

/**
* Detects whether Weex supports specific features.
* @param {String} condition
*/
export function supports (condition) {
if (typeof condition !== 'string') return null

const res = condition.match(/^@(\w+)\/(\w+)(\.(\w+))?$/i)
if (res) {
const type = res[1]
const name = res[2]
const method = res[4]
switch (type) {
case 'module': return isRegisteredModule(name, method)
case 'component': return isRegisteredComponent(name)
}
}

return null
}

/**
* Create a fresh instance of Vue for each Weex instance.
*/
function createVueModuleInstance (instanceId, moduleGetter) {
function createVueModuleInstance (instanceId, weex) {
const exports = {}
VueFactory(exports, renderer)
VueFactory(exports, weex.document)
const Vue = exports.Vue

const instance = instances[instanceId]
Expand All @@ -295,7 +180,7 @@ function createVueModuleInstance (instanceId, moduleGetter) {
const isReservedTag = Vue.config.isReservedTag || (() => false)
const isRuntimeComponent = Vue.config.isRuntimeComponent || (() => false)
Vue.config.isReservedTag = name => {
return (!isRuntimeComponent(name) && components[name]) ||
return (!isRuntimeComponent(name) && weex.supports(`@component/${name}`)) ||
isReservedTag(name) ||
weexRegex.test(name)
}
Expand All @@ -307,7 +192,7 @@ function createVueModuleInstance (instanceId, moduleGetter) {

// expose weex native module getter on subVue prototype so that
// vdom runtime modules can access native modules via vnode.context
Vue.prototype.$requireWeexModule = moduleGetter
Vue.prototype.$requireWeexModule = weex.requireModule

// Hack `Vue` behavior to handle instance information and data
// before root component created.
Expand Down Expand Up @@ -340,39 +225,6 @@ function createVueModuleInstance (instanceId, moduleGetter) {
return Vue
}

/**
* Generate native module getter. Each native module has several
* methods to call. And all the behaviors is instance-related. So
* this getter will return a set of methods which additionally
* send current instance id to native when called.
* @param {string} instanceId
* @return {function}
*/
function genModuleGetter (instanceId) {
const instance = instances[instanceId]
return function (name) {
const nativeModule = modules[name] || []
const output = {}
for (const methodName in nativeModule) {
Object.defineProperty(output, methodName, {
enumerable: true,
configurable: true,
get: function proxyGetter () {
return (...args) => {
return instance.document.taskCenter.send('module', { module: name, method: methodName }, args)
}
},
set: function proxySetter (val) {
if (typeof val === 'function') {
return instance.document.taskCenter.send('module', { module: name, method: methodName }, [val])
}
}
})
}
return output
}
}

/**
* Generate HTML5 Timer APIs. An important point is that the callback
* will be converted into callback id when sent to native. So the
Expand Down Expand Up @@ -430,55 +282,3 @@ function callFunction (globalObjects, body) {
const result = new Function(...globalKeys)
return result(...globalValues)
}

/**
* Call a new function generated on the V8 native side.
*
* This function helps speed up bundle compiling. Normally, the V8
* engine needs to download, parse, and compile a bundle on every
* visit. If 'compileBundle()' is available on native side,
* the downloading, parsing, and compiling steps would be skipped.
* @param {object} globalObjects
* @param {string} body
* @return {boolean}
*/
function callFunctionNative (globalObjects, body) {
if (typeof renderer.compileBundle !== 'function') {
return false
}

let fn = void 0
let isNativeCompileOk = false
let script = '(function ('
const globalKeys = []
const globalValues = []
for (const key in globalObjects) {
globalKeys.push(key)
globalValues.push(globalObjects[key])
}
for (let i = 0; i < globalKeys.length - 1; ++i) {
script += globalKeys[i]
script += ','
}
script += globalKeys[globalKeys.length - 1]
script += ') {'
script += body
script += '} )'

try {
const weex = globalObjects.weex || {}
const config = weex.config || {}
fn = renderer.compileBundle(script,
config.bundleUrl,
config.bundleDigest,
config.codeCachePath)
if (fn && typeof fn === 'function') {
fn(...globalValues)
isNativeCompileOk = true
}
} catch (e) {
console.error(e)
}

return isNativeCompileOk
}
14 changes: 8 additions & 6 deletions src/platforms/weex/runtime/node-ops.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
/* globals renderer */
// renderer is injected by weex factory wrapper
/* globals document */
// document is injected by weex factory wrapper

import TextNode from 'weex/runtime/text-node'

export const namespaceMap = {}

export function createElement (tagName) {
return new renderer.Element(tagName)
return document.createElement(tagName)
}

export function createElementNS (namespace, tagName) {
return new renderer.Element(namespace + ':' + tagName)
return document.createElement(namespace + ':' + tagName)
}

export function createTextNode (text) {
return new renderer.TextNode(text)
return new TextNode(text)
}

export function createComment (text) {
return new renderer.Comment(text)
return document.createComment(text)
}

export function insertBefore (node, target, before) {
Expand Down
6 changes: 3 additions & 3 deletions src/platforms/weex/util/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* globals renderer */
/* globals document */

import { makeMap } from 'shared/util'

Expand Down Expand Up @@ -34,8 +34,8 @@ export function getTagNamespace () { /* console.log('getTagNamespace') */ }
export function isUnknownElement () { /* console.log('isUnknownElement') */ }

export function query (el, document) {
// renderer is injected by weex factory wrapper
const placeholder = new renderer.Comment('root')
// document is injected by weex factory wrapper
const placeholder = document.createComment('root')
placeholder.hasAttribute = placeholder.removeAttribute = function () {} // hack for patch
document.documentElement.appendChild(placeholder)
return placeholder
Expand Down
Loading

0 comments on commit 2deda3d

Please sign in to comment.