Skip to content

Commit

Permalink
feat(vue-next): add beforeRenderToNative hook (#2775)
Browse files Browse the repository at this point in the history
  • Loading branch information
shenchaoran authored and zoomchan-cxj committed Feb 6, 2023
1 parent 05c7348 commit 3839135
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed 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 { isFunction } from '@vue/shared';
import { HippyNode, NodeType } from '../../../src/runtime/node/hippy-node';
import { HippyElement } from '../../../src/runtime/element/hippy-element';

describe('beforeRenderToNative hook', () => {
beforeAll(() => {
global.__GLOBAL__ = {
nodeId: 101,
};
});

it('HippyElement API', async () => {
try {
const node = new HippyElement('div');

expect(isFunction(node.appendChild)).toBeTruthy();
expect(isFunction(node.insertBefore)).toBeTruthy();
expect(isFunction(node.moveChild)).toBeTruthy();
expect(isFunction(node.removeChild)).toBeTruthy();

expect(node.classList instanceof Set).toBeTruthy();
expect(node.style instanceof Object).toBeTruthy();
expect(node.attributes instanceof Object).toBeTruthy();
} catch (e) {
console.error('HippyElement APIs have breaking changes, please update const variable \'BEFORE_RENDER_TO_NATIVE_HOOK_VERSION\' to disable this hook');
throw e;
}
});

it('HippyNode API', async () => {
try {
const node = new HippyNode(NodeType.ElementNode);

expect(isFunction(node.appendChild)).toBeTruthy();
expect(isFunction(node.insertBefore)).toBeTruthy();
expect(isFunction(node.moveChild)).toBeTruthy();
expect(isFunction(node.removeChild)).toBeTruthy();

const childNode1 = new HippyNode(NodeType.ElementNode);
const childNode2 = new HippyNode(NodeType.ElementNode);
node.appendChild(childNode1);
node.appendChild(childNode2);
expect(node.firstChild === childNode1).toBeTruthy();
expect(node.lastChild === childNode2).toBeTruthy();
} catch (e) {
console.error('HippyNode APIs have breaking changes, please update const variable \'BEFORE_RENDER_TO_NATIVE_HOOK_VERSION\' to disable this hook');
throw e;
}
});
});
24 changes: 23 additions & 1 deletion packages/hippy-vue-next/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ import type { NativeApiType } from './runtime/native';
import './runtime/event/hippy-event-dispatcher';
import './runtime/websocket/websocket';
import type { HippyNode } from './runtime/node/hippy-node';
import { setBeforeLoadStyle, setSilent, setTrimWhitespace, trace } from './util';
import {
setBeforeLoadStyle,
setSilent,
setTrimWhitespace,
trace,
setBeforeRenderToNative,
} from './util';
import type { HippyCachedInstanceType } from './util/instance';
import {
getHippyCachedInstance,
Expand Down Expand Up @@ -266,6 +272,22 @@ export const createApp = (
return hippyApp;
};

/*
* used to validate beforeRenderToNative hook
* when ElementNode or ViewNode have breaking changes, add version number to disable
* beforeRenderToNative hook
*/
const BEFORE_RENDER_TO_NATIVE_HOOK_VERSION = 1;
export const _setBeforeRenderToNative = (hook, version) => {
if (isFunction(hook)) {
if (BEFORE_RENDER_TO_NATIVE_HOOK_VERSION === version) {
setBeforeRenderToNative(hook);
} else {
console.error('_setBeforeRenderToNative API had changed, the hook function will be ignored!');
}
}
};

export type {
NativeApiType,
HippyCachedInstanceType,
Expand Down
22 changes: 14 additions & 8 deletions packages/hippy-vue-next/src/runtime/element/hippy-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
deepCopy,
isStyleMatched,
whitespaceFilter,
getBeforeRenderToNative,
} from '../../util';
import { isRTL } from '../../util/i18n';
import { getHippyCachedInstance } from '../../util/instance';
Expand Down Expand Up @@ -716,7 +717,17 @@ export class HippyElement extends HippyNode {
}

// get styles
const style: NativeNodeProps = this.getNativeStyles();
let style: NativeNodeProps = this.getNativeStyles();

getBeforeRenderToNative()(this, style);

/*
* append defaultNativeStyle later to avoid incorrect compute style from
* inherit node in beforeRenderToNative hook
*/
if (this.component.defaultNativeStyle) {
style = { ...this.component.defaultNativeStyle, ...style };
}

const elementExtraAttributes: Partial<NativeNode> = {
name: this.component.name,
Expand Down Expand Up @@ -819,17 +830,12 @@ export class HippyElement extends HippyNode {
}

/**
* get the style attribute of the node according to the node attribute and the global style sheet
* get the style attribute of the node according to the global style sheet
*/
private getNativeStyles(): NativeNodeProps {
let style: NativeNodeProps = {};

// first add default style
if (this.component.defaultNativeStyle) {
style = { ...this.component.defaultNativeStyle };
}

// then get the styles from the global CSS stylesheet
// get the styles from the global CSS stylesheet
// rem needs to be processed here
const matchedSelectors = getCssMap().query(this);
matchedSelectors.selectors.forEach((matchedSelector) => {
Expand Down
24 changes: 23 additions & 1 deletion packages/hippy-vue-next/src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@

import type { ComponentPublicInstance } from '@vue/runtime-core';
import { capitalize } from '@vue/shared';
import type { NeedToTyped, CommonMapParams, CallbackType } from '../types';
import type {
NeedToTyped,
CommonMapParams,
CallbackType,
NativeNodeProps,
} from '../types';
import { HIPPY_DEBUG_ADDRESS, HIPPY_STATIC_PROTOCOL, IS_PROD } from '../config';
import { type HippyElement } from '../runtime/element/hippy-element';

Expand Down Expand Up @@ -145,6 +150,23 @@ export function getBeforeLoadStyle(): CallbackType {
return beforeLoadStyleHook;
}

/**
* before render ElementNode hook
*
* Use for do some hack to dom tree, such as fixed position, style inherit
* percentage unit, style variables etc.
*/
let beforeRenderToNativeHook = (_el: HippyElement, _style: NativeNodeProps) => {};

export function setBeforeRenderToNative(beforeRenderToNative) {
beforeRenderToNativeHook = beforeRenderToNative;
}

export function getBeforeRenderToNative() {
return beforeRenderToNativeHook;
}


/**
* Convert unicode format string to char type
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,11 @@ test('ElementNode API', async (t) => {
t.true(util.isFunction(node.insertBefore));
t.true(util.isFunction(node.moveChild));
t.true(util.isFunction(node.removeChild));
t.true(util.isFunction(node.getBoundingClientRect));

t.true(node.classList instanceof Set);
t.true(node.style instanceof Object);
t.true(node.attributes instanceof Object);
}, 'ElementNode APIs have breaking changes, please update const variable \'BEFORE_RENDER_TO_NATIVE_HOOK_VERSION\'');
}, 'ElementNode APIs have breaking changes, please update const variable \'BEFORE_RENDER_TO_NATIVE_HOOK_VERSION\' to disable this hook');
});

test('ViewNode API', async (t) => {
Expand All @@ -74,5 +73,5 @@ test('ViewNode API', async (t) => {
node.appendChild(childNode2);
t.true(node.firstChild === childNode1);
t.true(node.lastChild === childNode2);
}, 'ViewNode APIs have breaking changes, please update const variable \'BEFORE_RENDER_TO_NATIVE_HOOK_VERSION\'');
}, 'ViewNode APIs have breaking changes, please update const variable \'BEFORE_RENDER_TO_NATIVE_HOOK_VERSION\' to disable this hook');
});
10 changes: 10 additions & 0 deletions packages/hippy-vue/src/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ let _Vue;
* @returns {Object} decl - Processed declaration, original declaration by default.
*/
let _beforeLoadStyle = decl => decl;

/**
* before render ElementNode hook
*
* Use for do some hack to dom tree, such as fixed position, style inherit
* percentage unit, style variables etc.
*
* @param {Object} el - ElementNode
* @param {Object} style - computed style sheet
*/
let _beforeRenderToNative = () => {};

function setVue(Vue) {
Expand Down

0 comments on commit 3839135

Please sign in to comment.