Skip to content

Commit

Permalink
Merge pull request #1517 from V4Fire/kormanowsky/issues/1389
Browse files Browse the repository at this point in the history
issues/1389 amendments by @kormanowsky
  • Loading branch information
kormanowsky authored Dec 19, 2024
2 parents b11acd7 + f63ccea commit 46c9b13
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 32 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ Changelog
_Note: Gaps between patch versions are faulty, broken or test releases._

## v4.0.0-beta.170 (2024-12-19)

#### :house: Internal

* [The `performance` option in the Vue engine config is set to true by default for the dev build `core/component/engines/vue3/config.ts`](https://github.com/V4Fire/Client/issues/1389)
* [Now key functions such as `createBlock` and `renderList` are being measured using the Performance API and will be available on the timeline `core/component/render/wrappers`](https://github.com/V4Fire/Client/issues/1389)

## v4.0.0-beta.169 (2024-12-17)

#### :house: Internal
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"packageManager": "[email protected]",
"typings": "index.d.ts",
"license": "MIT",
"version": "4.0.0-beta.169",
"version": "4.0.0-beta.170",
"author": {
"name": "kobezzza",
"email": "[email protected]",
Expand Down
6 changes: 6 additions & 0 deletions src/core/component/engines/vue3/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Changelog
> - :house: [Internal]
> - :nail_care: [Polish]
## v4.0.0-beta.170 (2024-12-19)

#### :house: Internal

* [The `performance` option in the Vue engine config is set to true by default for the dev build](https://github.com/V4Fire/Client/issues/1389)

## v4.0.0-beta.150 (2024-11-05)

#### :bug: Bug Fix
Expand Down
2 changes: 2 additions & 0 deletions src/core/component/engines/vue3/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ if (!IS_PROD) {
};
}

Vue.config.performance = !IS_PROD;

const
UNRECOGNIZED_COMPONENT_NAME = 'unrecognized-component',
ROOT_COMPONENT_NAME = 'root-component';
Expand Down
12 changes: 12 additions & 0 deletions src/core/component/init/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,15 @@ export function registerComponent(name: CanUndef<string>): CanNull<ComponentMeta

return components.get(name) ?? null;
}

/**
* Returns component metaobject by its name
* @param name
*/
export function getComponentMeta(name: CanUndef<string>): CanNull<ComponentMeta> {
if (name == null) {
return null;
}

return components.get(name) ?? null;
}
6 changes: 6 additions & 0 deletions src/core/component/render/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Changelog
> - :house: [Internal]
> - :nail_care: [Polish]
## v4.0.0-beta.170 (2024-12-19)

#### :house: Internal

* [Now key functions such as `createBlock` and `renderList` are being measured using the Performance API and will be available on the timeline](https://github.com/V4Fire/Client/issues/1389)

## v4.0.0-beta.153 (2024-11-15)

#### :house: Internal
Expand Down
98 changes: 67 additions & 31 deletions src/core/component/render/wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

/* eslint-disable prefer-spread */

import { wrapWithMeasurement } from 'core/performance';

import { app, isComponent, componentRenderFactories, ASYNC_RENDER_ID } from 'core/component/const';
import { attachTemplatesToMeta, ComponentMeta } from 'core/component/meta';

Expand Down Expand Up @@ -43,7 +45,7 @@ import type {

import type { ssrRenderSlot as ISSRRenderSlot } from '@vue/server-renderer';

import { registerComponent } from 'core/component/init';
import { getComponentMeta, registerComponent } from 'core/component/init';

import {

Expand Down Expand Up @@ -85,7 +87,26 @@ export function wrapCreateElementVNode<T extends typeof createElementVNode>(orig
* @param original
*/
export function wrapCreateBlock<T extends typeof createBlock>(original: T): T {
return Object.cast(function wrapCreateBlock(this: ComponentInterface, ...args: Parameters<T>) {
function getMeasurementName(this: ComponentInterface, ...args: Parameters<T>): CanNull<string> {
const [name] = args;

let component: CanNull<ComponentMeta> = null;

if (Object.isString(name)) {
component = getComponentMeta(name);

} else if (!Object.isPrimitive(name) && 'name' in name && name.name != null) {
component = getComponentMeta(name.name);
}

if (component == null) {
return null;
}

return `<${component.componentName.camelize(true)}> create block`;
}

function innerCreateBlock(this: ComponentInterface, ...args: Parameters<T>) {
let [name, attrs, slots, patchFlag, dynamicProps] = args;

let component: CanNull<ComponentMeta> = null;
Expand Down Expand Up @@ -234,18 +255,27 @@ export function wrapCreateBlock<T extends typeof createBlock>(original: T): T {
functionalVNode.dynamicChildren = [];

return vnode;
});
}

return Object.cast(
wrapWithMeasurement(
getMeasurementName,
innerCreateBlock
)
);
}

/**
* A wrapper for the component library `createElementBlock` function
* @param original
*/
export function wrapCreateElementBlock<T extends typeof createElementBlock>(original: T): T {
return Object.cast(function createElementBlock(this: ComponentInterface, ...args: Parameters<T>) {
args[3] = normalizePatchFlagUsingProps.call(this, args[3], args[1]);
return resolveAttrs.call(this, original.apply(null, args));
});
return Object.cast(
function createElementBlock(this: ComponentInterface, ...args: Parameters<T>) {
args[3] = normalizePatchFlagUsingProps.call(this, args[3], args[1]);
return resolveAttrs.call(this, original.apply(null, args));
}
);
}

/**
Expand Down Expand Up @@ -309,33 +339,39 @@ export function wrapMergeProps<T extends typeof mergeProps>(original: T): T {
* A wrapper for the component library `renderList` function
*
* @param original
* @param withCtx
*/
export function wrapRenderList<T extends typeof renderList>(original: T): T {
return Object.cast(function renderList(
this: ComponentInterface,
src: Nullable<Iterable<unknown> | Dictionary | number>,
cb: AnyFunction
) {
const wrappedCb: AnyFunction = Object.cast(cb);

const
vnodes = original(src, wrappedCb),
asyncRenderId = src?.[ASYNC_RENDER_ID];

if (asyncRenderId != null) {
this.$emit('[[V_FOR_CB]]', {wrappedCb});

Object.defineProperty(vnodes, ASYNC_RENDER_ID, {
writable: false,
enumerable: false,
configurable: false,
value: asyncRenderId
});
}
return Object.cast(
wrapWithMeasurement(
function getMeasurementName(this: ComponentInterface, ..._args: unknown[]) {
return `<${this.componentName.camelize(true)}> render list`;
},

function renderList(
this: ComponentInterface,
src: Nullable<Iterable<unknown> | Dictionary | number>,
cb: AnyFunction
) {
const
wrappedCb: AnyFunction = Object.cast(cb),
vnodes = original(src, wrappedCb),
asyncRenderId = src?.[ASYNC_RENDER_ID];

if (asyncRenderId != null) {
this.$emit('[[V_FOR_CB]]', {wrappedCb});

Object.defineProperty(vnodes, ASYNC_RENDER_ID, {
writable: false,
enumerable: false,
configurable: false,
value: asyncRenderId
});
}

return vnodes;
});
return vnodes;
}
)
);
}

/**
Expand Down
16 changes: 16 additions & 0 deletions src/core/performance/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Changelog
=========

> **Tags:**
> - :boom: [Breaking Change]
> - :rocket: [New Feature]
> - :bug: [Bug Fix]
> - :memo: [Documentation]
> - :house: [Internal]
> - :nail_care: [Polish]
## 4.0.0-beta.170 (2024-12-19)

#### :rocket: New Feature

* Initial release
3 changes: 3 additions & 0 deletions src/core/performance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# core/performance

The module provides an API for monitoring application performance at runtime.
9 changes: 9 additions & 0 deletions src/core/performance/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/

export * from 'core/performance/measure';
18 changes: 18 additions & 0 deletions src/core/performance/measure/engines/web.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/

/**
* {@link Performance.measure}
* @param args
*/
export function measure(...args: Parameters<Performance['measure']>): CanUndef<ReturnType<Performance['measure']>> {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (typeof globalThis.performance?.measure !== 'undefined') {
return performance.measure(...args);
}
}
60 changes: 60 additions & 0 deletions src/core/performance/measure/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/

//#unless node_js
import { measure as webMeasure } from 'core/performance/measure/engines/web';
//#endunless

/**
* The measure method creates a named `PerformanceMeasure` object representing a time measurement between two marks
* @param args
*/
export function measure(...args: Parameters<Performance['measure']>): CanUndef<ReturnType<Performance['measure']>> {
//#unless node_js
return webMeasure(...args);
//#endif
}

/**
* Wraps given function `original` with performance measurement with name `measurement`.
* Measurements are only enabled if IS_PROD is false.
*
* @param measurement
* @param original
*/
export function wrapWithMeasurement<TThis = unknown, TArgs extends unknown[] = unknown[], TResult = void>(
measurement: string | ((this: TThis, ...args: TArgs) => CanNull<string>),
original: (this: TThis, ...args: TArgs) => TResult
): (this: TThis, ...args: TArgs) => TResult {
if (IS_PROD) {
return original;
}

return function wrapper(this: TThis, ...args: TArgs): TResult {
const start = performance.now();

const result = original.apply(this, args);

const end = performance.now();

let computedMeasurement: CanNull<string> = null;

if (Object.isFunction(measurement)) {
computedMeasurement = measurement.apply(this, args);

} else {
computedMeasurement = measurement;
}

if (computedMeasurement != null) {
measure(computedMeasurement, {start, end});
}

return result;
};
}

0 comments on commit 46c9b13

Please sign in to comment.