You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by gu...@apache.org on 2017/10/23 07:23:25 UTC

[07/11] incubator-weex git commit: + [jsfm] add weex variable api in runtime

+ [jsfm] add weex variable api in runtime


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/84ff2660
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/84ff2660
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/84ff2660

Branch: refs/heads/release-0.16
Commit: 84ff266096243fae98ab1cc59ab035314b9fb9c7
Parents: bef20bd
Author: Hanks <zh...@gmail.com>
Authored: Wed Oct 11 17:19:48 2017 +0800
Committer: jianbai.gbj <ji...@alibaba-inc.com>
Committed: Mon Oct 23 10:02:35 2017 +0800

----------------------------------------------------------------------
 html5/runtime/api/WeexInstance.js | 126 +++++++++++++++++++++++++++++++++
 html5/runtime/api/component.js    |  51 +++++++++++++
 html5/runtime/api/init.js         | 107 +++++++++++++++++-----------
 html5/runtime/api/module.js       |  56 +++++++++++++++
 4 files changed, 300 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/84ff2660/html5/runtime/api/WeexInstance.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/WeexInstance.js b/html5/runtime/api/WeexInstance.js
new file mode 100644
index 0000000..2093f17
--- /dev/null
+++ b/html5/runtime/api/WeexInstance.js
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Document from '../vdom/Document'
+import { isRegisteredModule, getModuleDescription } from './module'
+import { isRegisteredComponent } from './component'
+
+const moduleProxies = {}
+
+function setId (weex, id) {
+  Object.defineProperty(weex, '[[CurrentInstanceId]]', { value: id })
+}
+
+function getId (weex) {
+  return weex['[[CurrentInstanceId]]']
+}
+
+function moduleGetter (module, method, taskCenter) {
+  return (...args) => taskCenter.send('module', { module, method }, args)
+}
+
+export default class WeexInstance {
+  constructor (id, config) {
+    setId(this, id)
+    this.config = config || {}
+    this.document = new Document(id, this.config.bundleUrl)
+    this.requireModule = this.requireModule.bind(this)
+    this.isRegisteredModule = isRegisteredModule
+    this.isRegisteredComponent = isRegisteredComponent
+  }
+
+  requireModule (moduleName) {
+    const id = getId(this)
+    if (!(id && this.document && this.document.taskCenter)) {
+      console.error(`[JS Framework] invalid instance id "${id}"`)
+      return
+    }
+
+    // warn for unknown module
+    if (!isRegisteredModule(moduleName)) {
+      console.warn(`[JS Framework] using unregistered weex module "${moduleName}"`)
+      return
+    }
+
+    // create new module proxy
+    if (!moduleProxies[moduleName]) {
+      const moduleDefine = getModuleDescription(moduleName)
+      const taskCenter = this.document.taskCenter
+
+      // create registered module apis
+      const moduleApis = {}
+      for (const methodName in moduleDefine) {
+        Object.defineProperty(moduleApis, methodName, {
+          enumerable: true,
+          configurable: true,
+          get: () => moduleGetter(moduleName, methodName, taskCenter),
+          set (fn) {
+            if (typeof fn === 'function') {
+              return taskCenter.send('module', {
+                module: moduleName,
+                method: methodName
+              }, [fn])
+            }
+          }
+        })
+      }
+
+      // create module Proxy
+      if (typeof Proxy === 'function') {
+        moduleProxies[moduleName] = new Proxy(moduleApis, {
+          get (target, methodName) {
+            if (methodName in target) {
+              return target[methodName]
+            }
+            console.warn(`[JS Framework] using unregistered method "${moduleName}.${methodName}"`)
+            return moduleGetter(moduleName, methodName, taskCenter)
+          }
+        })
+      }
+      else {
+        moduleProxies[moduleName] = moduleApis
+      }
+    }
+
+    return moduleProxies[moduleName]
+  }
+
+  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
+  }
+
+  // registerStyleSheet (styles) {
+  //   if (this.document) {
+  //     this.document.registerStyleSheet(styles)
+  //   }
+  // }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/84ff2660/html5/runtime/api/component.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/component.js b/html5/runtime/api/component.js
new file mode 100644
index 0000000..8a56961
--- /dev/null
+++ b/html5/runtime/api/component.js
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { registerElement } from '../vdom/WeexElement'
+
+const weexComponents = {}
+
+/**
+ * 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') {
+        weexComponents[component] = true
+      }
+      else if (typeof component === 'object' && typeof component.type === 'string') {
+        weexComponents[component.type] = component
+        registerElement(component.type, component.methods)
+      }
+    })
+  }
+}
+
+/**
+ * Check whether the component has been registered.
+ * @param {String} component name
+ */
+export function isRegisteredComponent (name) {
+  return !!weexComponents[name]
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/84ff2660/html5/runtime/api/init.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/init.js b/html5/runtime/api/init.js
index 024afa7..cad0179 100644
--- a/html5/runtime/api/init.js
+++ b/html5/runtime/api/init.js
@@ -18,8 +18,10 @@
  */
 
 import { init as initTaskHandler } from '../bridge/TaskCenter'
-import { registerElement } from '../vdom/WeexElement'
+import { registerModules } from './module'
+import { registerComponents } from './component'
 import { services, register, unregister } from './service'
+import WeexInstance from './WeexInstance'
 
 let frameworks
 let runtimeConfig
@@ -95,58 +97,61 @@ function createInstance (id, code, config, data) {
   config = JSON.parse(JSON.stringify(config || {}))
   config.env = JSON.parse(JSON.stringify(global.WXEnvironment || {}))
 
-  const context = {
-    config,
+  const weex = new WeexInstance(id, config)
+  Object.freeze(weex)
+
+  const runtimeEnv = {
+    weex,
+    config, // TODO: deprecated
     created: Date.now(),
     framework: bundleType
   }
-  context.services = createServices(id, context, runtimeConfig)
-  instanceMap[id] = context
+  runtimeEnv.services = createServices(id, runtimeEnv, runtimeConfig)
+  instanceMap[id] = runtimeEnv
 
-  if (process.env.NODE_ENV === 'development') {
-    console.debug(`[JS Framework] create an ${bundleType} instance`)
-  }
+  const runtimeContext = Object.create(null)
+  Object.assign(runtimeContext, runtimeEnv.services, { weex })
 
-  const fm = frameworks[bundleType]
-  if (!fm) {
+  const framework = runtimeConfig.frameworks[bundleType]
+  if (!framework) {
     return new Error(`invalid bundle type "${bundleType}".`)
   }
 
-  return fm.createInstance(id, code, config, data, context)
-}
-
-const methods = {
-  createInstance,
-  registerService: register,
-  unregisterService: unregister
+  // run create instance
+  if (typeof framework.prepareInstanceContext === 'function') {
+    const instanceContext = framework.prepareInstanceContext(runtimeContext)
+    return runInContext(code, instanceContext)
+  }
+  return framework.createInstance(id, code, config, data, runtimeEnv)
 }
 
 /**
- * Register methods which init each frameworks.
- * @param {string} methodName
+ * Run js code in a specific context.
+ * @param {string} code
+ * @param {object} context
  */
-function genInit (methodName) {
-  methods[methodName] = function (...args) {
-    if (methodName === 'registerComponents') {
-      checkComponentMethods(args[0])
-    }
-    for (const name in frameworks) {
-      const framework = frameworks[name]
-      if (framework && framework[methodName]) {
-        framework[methodName](...args)
-      }
-    }
+function runInContext (code, context) {
+  const keys = []
+  const args = []
+  for (const key in context) {
+    keys.push(key)
+    args.push(context[key])
   }
+
+  const bundle = `
+    (function (global) {
+      "use strict";
+      ${code}
+    })(Object.create(this))
+  `
+
+  return (new Function(...keys, bundle))(...args)
 }
 
-function checkComponentMethods (components) {
-  if (Array.isArray(components)) {
-    components.forEach((name) => {
-      if (name && name.type && name.methods) {
-        registerElement(name.type, name.methods)
-      }
-    })
-  }
+const methods = {
+  createInstance,
+  registerService: register,
+  unregisterService: unregister
 }
 
 /**
@@ -203,6 +208,27 @@ function adaptInstance (methodName, nativeMethodName) {
   }
 }
 
+/**
+ * Register methods which init each frameworks.
+ * @param {string} methodName
+ * @param {function} sharedMethod
+ */
+function adaptMethod (methodName, sharedMethod) {
+  methods[methodName] = function (...args) {
+    if (typeof sharedMethod === 'function') {
+      sharedMethod(...args)
+    }
+
+    // TODO: deprecated
+    for (const name in runtimeConfig.frameworks) {
+      const framework = runtimeConfig.frameworks[name]
+      if (framework && framework[methodName]) {
+        framework[methodName](...args)
+      }
+    }
+  }
+}
+
 export default function init (config) {
   runtimeConfig = config || {}
   frameworks = runtimeConfig.frameworks || {}
@@ -216,8 +242,9 @@ export default function init (config) {
     framework.init(config)
   }
 
-  // @todo: The method `registerMethods` will be re-designed or removed later.
-  ; ['registerComponents', 'registerModules', 'registerMethods'].forEach(genInit)
+  adaptMethod('registerComponents', registerComponents)
+  adaptMethod('registerModules', registerModules)
+  adaptMethod('registerMethods')
 
   ; ['destroyInstance', 'refreshInstance', 'receiveTasks', 'getRoot'].forEach(genInstance)
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/84ff2660/html5/runtime/api/module.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/module.js b/html5/runtime/api/module.js
new file mode 100644
index 0000000..df26b92
--- /dev/null
+++ b/html5/runtime/api/module.js
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const weexModules = {}
+
+/**
+ * Register native modules information.
+ * @param {object} newModules
+ */
+export function registerModules (newModules) {
+  for (const name in newModules) {
+    if (!weexModules[name]) {
+      weexModules[name] = {}
+    }
+    newModules[name].forEach(method => {
+      if (typeof method === 'string') {
+        weexModules[name][method] = true
+      }
+      else {
+        weexModules[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 !!(weexModules[name] && weexModules[name][method])
+  }
+  return !!weexModules[name]
+}
+
+export function getModuleDescription (name) {
+  return weexModules[name]
+}