From fe8a7221d683e31b613fc6acf5fae29b17ea57e4 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Fri, 4 Jul 2025 13:01:01 +0300 Subject: [PATCH] feat(editor): Add vue-scan for frontend performance tracking (no-changelog) (#16995) --- package.json | 3 +- packages/frontend/editor-ui/package.json | 3 +- packages/frontend/editor-ui/src/main.ts | 9 +++++ packages/frontend/editor-ui/src/shims.d.ts | 1 + packages/frontend/editor-ui/vite.config.mts | 2 +- patches/z-vue-scan.patch | 44 +++++++++++++++++++++ pnpm-lock.yaml | 20 ++++++++++ 7 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 patches/z-vue-scan.patch diff --git a/package.json b/package.json index db816a565c..508aa0963e 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,8 @@ "@types/uuencode@0.0.3": "patches/@types__uuencode@0.0.3.patch", "vue-tsc@2.2.8": "patches/vue-tsc@2.2.8.patch", "element-plus@2.4.3": "patches/element-plus@2.4.3.patch", - "js-base64": "patches/js-base64.patch" + "js-base64": "patches/js-base64.patch", + "z-vue-scan": "patches/z-vue-scan.patch" } } } diff --git a/packages/frontend/editor-ui/package.json b/packages/frontend/editor-ui/package.json index bc3d3244d4..94f377e000 100644 --- a/packages/frontend/editor-ui/package.json +++ b/packages/frontend/editor-ui/package.json @@ -99,7 +99,8 @@ "vue3-touch-events": "^4.1.3", "vuedraggable": "4.1.0", "web-tree-sitter": "0.24.3", - "xss": "catalog:" + "xss": "catalog:", + "z-vue-scan": "^0.0.35" }, "devDependencies": { "@faker-js/faker": "^8.0.2", diff --git a/packages/frontend/editor-ui/src/main.ts b/packages/frontend/editor-ui/src/main.ts index f3c22496c0..c5ccbd9ba8 100644 --- a/packages/frontend/editor-ui/src/main.ts +++ b/packages/frontend/editor-ui/src/main.ts @@ -25,6 +25,8 @@ import { createPinia, PiniaVuePlugin } from 'pinia'; import { ChartJSPlugin } from '@/plugins/chartjs'; import { SentryPlugin } from '@/plugins/sentry'; +import type { VueScanOptions } from 'z-vue-scan'; + const pinia = createPinia(); const app = createApp(App); @@ -40,6 +42,13 @@ app.use(router); app.use(i18nInstance); app.use(ChartJSPlugin); +if (import.meta.env.VUE_SCAN) { + const { default: VueScan } = await import('z-vue-scan'); + app.use(VueScan, { + enable: true, + }); +} + app.mount('#app'); if (!import.meta.env.PROD) { diff --git a/packages/frontend/editor-ui/src/shims.d.ts b/packages/frontend/editor-ui/src/shims.d.ts index 0fa35a73f0..ce55fae98c 100644 --- a/packages/frontend/editor-ui/src/shims.d.ts +++ b/packages/frontend/editor-ui/src/shims.d.ts @@ -14,6 +14,7 @@ declare global { PROD: boolean; NODE_ENV: 'development' | 'production'; VUE_APP_URL_BASE_API: string; + VUE_SCAN: boolean; }; } diff --git a/packages/frontend/editor-ui/vite.config.mts b/packages/frontend/editor-ui/vite.config.mts index fc73e91d38..3d5a6e47f6 100644 --- a/packages/frontend/editor-ui/vite.config.mts +++ b/packages/frontend/editor-ui/vite.config.mts @@ -131,7 +131,7 @@ export default mergeConfig( plugins, resolve: { alias }, base: publicPath, - envPrefix: 'VUE_APP', + envPrefix: 'VUE', css: { preprocessorOptions: { scss: { diff --git a/patches/z-vue-scan.patch b/patches/z-vue-scan.patch new file mode 100644 index 0000000000..70a9836b9d --- /dev/null +++ b/patches/z-vue-scan.patch @@ -0,0 +1,44 @@ +diff --git a/dist/shared/z-vue-scan.3fa3a39a.mjs b/dist/shared/z-vue-scan.3fa3a39a.mjs +index 90c64048960e7e55d0d6798b5bc11fe9099c79b0..c6af398931a3f5efaf6e507a201e65515daf6c58 100644 +--- a/dist/shared/z-vue-scan.3fa3a39a.mjs ++++ b/dist/shared/z-vue-scan.3fa3a39a.mjs +@@ -1020,7 +1020,7 @@ class HighlightCanvas { + render() { + const now = Date.now(); + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); +- this.ctx.font = "12px sans-serif"; ++ this.ctx.font = "10px sans-serif"; + this.ctx.textBaseline = "middle"; + for (const [uuid, item] of this.highlights.entries()) { + if (!isInViewport(item.bounds)) +@@ -1065,7 +1065,7 @@ class HighlightCanvas { + drawBorder(item) { + const { bounds, flashCount, opacity } = item; + this.ctx.strokeStyle = `rgba(${Math.min(255, flashCount * 6)}, ${Math.max(0, 255 - flashCount * 6)}, 0, ${opacity})`; +- this.ctx.lineWidth = 2; ++ this.ctx.lineWidth = 1; + this.ctx.strokeRect( + bounds.left, + bounds.top, +diff --git a/dist/shared/z-vue-scan.e44c49f3.cjs b/dist/shared/z-vue-scan.e44c49f3.cjs +index 25100c556b300d60f86b81f46e3ae4168a203c14..c8d3ca42cb41d21f2726716d2aa8d8f63e6a85e8 100644 +--- a/dist/shared/z-vue-scan.e44c49f3.cjs ++++ b/dist/shared/z-vue-scan.e44c49f3.cjs +@@ -1022,7 +1022,7 @@ class HighlightCanvas { + render() { + const now = Date.now(); + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); +- this.ctx.font = "12px sans-serif"; ++ this.ctx.font = "10px sans-serif"; + this.ctx.textBaseline = "middle"; + for (const [uuid, item] of this.highlights.entries()) { + if (!isInViewport(item.bounds)) +@@ -1067,7 +1067,7 @@ class HighlightCanvas { + drawBorder(item) { + const { bounds, flashCount, opacity } = item; + this.ctx.strokeStyle = `rgba(${Math.min(255, flashCount * 6)}, ${Math.max(0, 255 - flashCount * 6)}, 0, ${opacity})`; +- this.ctx.lineWidth = 2; ++ this.ctx.lineWidth = 1; + this.ctx.strokeRect( + bounds.left, + bounds.top, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c35adeda5d..2b45d4df81 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -231,6 +231,9 @@ patchedDependencies: vue-tsc@2.2.8: hash: e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f path: patches/vue-tsc@2.2.8.patch + z-vue-scan: + hash: bbd573be7e456224f369aafb4d66374523c4847964a4655a6a1654fd40e8b0f8 + path: patches/z-vue-scan.patch importers: @@ -2460,6 +2463,9 @@ importers: xss: specifier: 'catalog:' version: 1.0.15 + z-vue-scan: + specifier: ^0.0.35 + version: 0.0.35(patch_hash=bbd573be7e456224f369aafb4d66374523c4847964a4655a6a1654fd40e8b0f8)(vue@3.5.13(typescript@5.8.3)) devDependencies: '@faker-js/faker': specifier: ^8.0.2 @@ -15610,6 +15616,15 @@ packages: resolution: {integrity: sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==} engines: {node: '>=10'} + z-vue-scan@0.0.35: + resolution: {integrity: sha512-isWALsDyRFhvGJrWCKbZ8ORYXmrWp+ewvoaBxBQe0WWvilzyuoTLW8IG5gL2kORLdTWmyj2j1NvehaJpKavJcw==} + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^2.0.0 || >=3.0.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} @@ -31488,6 +31503,11 @@ snapshots: property-expr: 2.0.5 toposort: 2.0.2 + z-vue-scan@0.0.35(patch_hash=bbd573be7e456224f369aafb4d66374523c4847964a4655a6a1654fd40e8b0f8)(vue@3.5.13(typescript@5.8.3)): + dependencies: + vue: 3.5.13(typescript@5.8.3) + vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.3)) + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2