diff --git a/.gitignore b/.gitignore index 5e4224bd1..574ad161f 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,9 @@ Temporary Items # Log *.log +# Node version +.node-version + # Web node_modules coverage diff --git a/tenon/.eslintrc.js b/tenon/.eslintrc.js index 04cba9b4c..1fb05f885 100644 --- a/tenon/.eslintrc.js +++ b/tenon/.eslintrc.js @@ -21,7 +21,8 @@ module.exports = { 'error', 'ObjectExpression > SpreadElement', 'ObjectPattern > RestElement' - ] + ], + 'no-restricted-syntax': 'off' }, overrides: [ // tests, no restrictions (runs in Node / jest with jsdom) diff --git a/tenon/packages/tenon-dev-tool/src/index.ts b/tenon/packages/tenon-dev-tool/src/index.ts index 3017134d7..5d526b6a4 100644 --- a/tenon/packages/tenon-dev-tool/src/index.ts +++ b/tenon/packages/tenon-dev-tool/src/index.ts @@ -42,13 +42,21 @@ export function run(container: any, type: string = 'tenon-vue') { 'getViewTree': function (ws: any, params: any) { let data = getViewData(formatedNode, type) viewMap = data.viewMap - if (formatedNode?.element?.dbg_getDescription) { - formatedNode.element.dbg_getDescription((node: any) => { + if (params.refresh) { + formatedNode?.element?.dbg_getDescription((node: any) => { + // tenon 特殊处理,外层包裹一个 template,和组件对齐 + if(type === 'tenon-vue'){ + node.tagName = 'template' + } + let refreshFormatedNode = formatNode(node, type, true) + let refreshData = getViewData(refreshFormatedNode, type) + viewMap = refreshData.viewMap; sendMessage(ws, { method: 'setViewTree', params: { ...params, - viewTree: [data.simpleRoot], + refresh: true, + viewTree: [refreshData.simpleRoot], path: path, baseInfo: __GLOBAL__.Hummer.env, devToolType: type @@ -60,6 +68,7 @@ export function run(container: any, type: string = 'tenon-vue') { method: 'setViewTree', params: { ...params, + refresh: false, viewTree: [data.simpleRoot], path: path, baseInfo: __GLOBAL__.Hummer.env, diff --git a/tenon/packages/tenon-dev-tool/src/utils.ts b/tenon/packages/tenon-dev-tool/src/utils.ts index b7e061b80..dae171a00 100644 --- a/tenon/packages/tenon-dev-tool/src/utils.ts +++ b/tenon/packages/tenon-dev-tool/src/utils.ts @@ -70,10 +70,10 @@ export const getPartUrlByParam = (url: string, param: string) => { * @param type * @returns simplenode */ -export const formatNode = function (node: any, type: string = 'tenon-vue') { +export const formatNode = function (node: any, type: string = 'tenon-vue', refresh = false) { let formatedNode = Object.create({}) const treeTraveler = function (node: any, rootView: any) { - processView(node, rootView, type) + processView(node, rootView, type, refresh) if (node.children) { // hummer children类型Array tenon-vue类型Set 处理一下 let arr = Array.from(node.children) @@ -179,7 +179,7 @@ export const getViewData = function (container: any, type: string = 'tenon-vue') // return res // }) // } -const processView = function (node: any, rootView: any, type: string = 'tenon-vue') { +const processView = function (node: any, rootView: any, type: string = 'tenon-vue', refresh = false) { let nameKey = '__NAME', idKey = '__view_id', textKey = '_text', @@ -198,6 +198,16 @@ const processView = function (node: any, rootView: any, type: string = 'tenon-vu srcKey = 'content' rootView.style = node.element.style break; + case 'tenon-vue': + // 刷新之后的节点要格式化一下 + if(refresh){ + nameKey = 'tagName'; + idKey = 'id'; + textKey = 'content'; + srcKey = 'content'; + rootView.style = node.element.style; + } + break default: break; } diff --git a/tenon/packages/tenon-vue/src/runtime/handlers/events.ts b/tenon/packages/tenon-vue/src/runtime/handlers/events.ts index 9ac556733..ba7421056 100644 --- a/tenon/packages/tenon-vue/src/runtime/handlers/events.ts +++ b/tenon/packages/tenon-vue/src/runtime/handlers/events.ts @@ -1,6 +1,7 @@ import { Base } from '../nodes/Base' import { - ComponentInternalInstance + ComponentInternalInstance, + callWithAsyncErrorHandling } from '@vue/runtime-core' const LongPress = 'longpress' @@ -34,19 +35,27 @@ export function patchEvents( } } +function patchInvokerHandler(initialValue: any, instance: ComponentInternalInstance | null, args: any) { + // TODO: Array.isArray兼容性测试 + if (Array.isArray(initialValue)) { + return initialValue.map(func => () => func && func.apply(instance, args)) + } else { + return () => initialValue.apply(instance, args) + } +} + function createInvoker( initialValue: EventValue, instance: ComponentInternalInstance | null ){ - // TODO: Array.isArray兼容性测试 const invoker:Invoker = (...args) => { - if(Array.isArray(initialValue)){ - initialValue.forEach((func:Function) => { - func.apply(instance, [...args]) - }) - }else { - initialValue.apply(instance, [...args]) - } + // 搜集 Error + callWithAsyncErrorHandling( + patchInvokerHandler(initialValue, instance, [...args]), + instance, + 5, + [...args] + ); } invoker.value = initialValue initialValue.invoker = invoker diff --git a/tenon/packages/tenon-vue/src/runtime/helper/lifecycle-helper.ts b/tenon/packages/tenon-vue/src/runtime/helper/lifecycle-helper.ts index 574f09536..0e0e981e4 100644 --- a/tenon/packages/tenon-vue/src/runtime/helper/lifecycle-helper.ts +++ b/tenon/packages/tenon-vue/src/runtime/helper/lifecycle-helper.ts @@ -1,3 +1,4 @@ +import { ComponentInternalInstance, callWithAsyncErrorHandling } from "@vue/runtime-core" interface LifeCycleMixins { onLoad: Array, onReady: Array, @@ -78,14 +79,15 @@ export const initPageLifeCycle = (container: any, instance: any, config: any) => container[lifecycle] = () => { globalLifeCycleMixins[lifecycle].forEach((func: Function) => { - applyLifeCycle(instance, func) - }) - extendOptions && applyLifeCycle(instance, extendOptions[lifecycle]) + lifecycleAsyncErrorTracker(instance, func); + }); + extendOptions && lifecycleAsyncErrorTracker(instance, extendOptions[lifecycle]); + lifeCycleMixins[lifecycle].forEach((func: Function) => { - applyLifeCycle(instance, func) - }) - applyLifeCycle(instance, config[lifecycle]) - } + lifecycleAsyncErrorTracker(instance, func); + }); + lifecycleAsyncErrorTracker(instance, config[lifecycle]); + }; }) } @@ -116,3 +118,8 @@ function applyPageMixin(mixins: any): (LifeCycleMixins | null) { function applyLifeCycle(instance: any, func: Function) { return func && func.apply(instance); } +function lifecycleAsyncErrorTracker(instance: any, func: Function){ + // instance 是编译主入口的 proxy 格式数据,而 instance._ 是 createComponentInstance 实例 + const errorInternalInstance: ComponentInternalInstance = instance._ + func && callWithAsyncErrorHandling(() => applyLifeCycle(instance, func), errorInternalInstance, 10) +} \ No newline at end of file diff --git a/tenon/packages/tenon-vue/src/runtime/nodes/Base.ts b/tenon/packages/tenon-vue/src/runtime/nodes/Base.ts index f72b75d3d..e82bd2f67 100644 --- a/tenon/packages/tenon-vue/src/runtime/nodes/Base.ts +++ b/tenon/packages/tenon-vue/src/runtime/nodes/Base.ts @@ -202,7 +202,9 @@ export class Base { private setCacheProp(key:string, value:any){ // 如果是 datattr 格式的属性,缓存到 dataset 中,方便事件可以获取到 dataset (Chameleon事件需求) if(/^data/.test(key)){ - let dataKey = key.slice(4).toLowerCase() + // 父组件 data 开头就截取4个,子组件 data- 开头就截取5个 + let cutNum = key.includes('-') ? 5 : 4 + let dataKey = key.slice(cutNum).toLowerCase() if(dataKey){ this.dataset[dataKey] = value }