From 545464efeea8ab80584e4c2ff612a4235b2da037 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 21:10:50 +0200 Subject: [PATCH 01/24] chore(scripts): add a script to anlayze performance logs --- scripts/analyze-perf.ts | 231 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 scripts/analyze-perf.ts diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts new file mode 100644 index 0000000000..754a7ee7f5 --- /dev/null +++ b/scripts/analyze-perf.ts @@ -0,0 +1,231 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +interface PerfEntry { + operation: string; + time: number; + file: string; + fullLine: string; +} + +interface AggregatedStats { + totalTime: number; + count: number; + files: string[]; +} + +function stripAnsi(text: string): string { + // Remove ANSI escape codes - both the ESC[ format and the literal bracket format + return text.replace(/\x1b\[[0-9;]*m/g, '').replace(/\[(\d+)m/g, ''); +} + +function parsePerf(filePath: string): PerfEntry[] { + // Read as UTF-16 LE which is what PowerShell's Tee-Object writes + const content = fs.readFileSync(filePath, 'utf16le'); + const lines = content.split('\n'); + const entries: PerfEntry[] = []; + + // Match patterns like: "vite:load 7776.91ms [fs] /path/to/file" + // or "vite:transform 1234.56ms /path/to/file" + const timePattern = /(\d+\.\d+)ms/; + const operationPattern = /vite:(load|transform|resolve|time|import-analysis)/; + + for (let line of lines) { + // Strip ANSI color codes + line = stripAnsi(line); + + const timeMatch = line.match(timePattern); + const operationMatch = line.match(operationPattern); + + if (timeMatch && operationMatch) { + const time = parseFloat(timeMatch[1]); + const operation = operationMatch[1]; + + // Extract file path - it's usually after the timing and optional [fs]/[plugin] marker + let file = 'unknown'; + // Match file paths after [fs] or [plugin] or directly after timing + const pathMatch = line.match(/(?:\[(?:fs|plugin)\]\s+)?([/\\]?[\w/.@-]+\.[a-z]+(?:\?[^\s]*)?)/i); + if (pathMatch) { + file = pathMatch[1]; + // Normalize path separators + file = file.replace(/\\/g, '/'); + // Remove query params + file = file.replace(/\?.*$/, ''); + // Get just the filename for cleaner output + const fileName = path.basename(file); + if (file.includes('node_modules')) { + const nodeModulesMatch = file.match(/node_modules\/([^\/]+)/); + if (nodeModulesMatch) { + file = `npm:${nodeModulesMatch[1]}/${fileName}`; + } + } else if (file.includes('packages/')) { + const packagesMatch = file.match(/packages\/([^\/]+)/); + if (packagesMatch) { + file = `pkg:${packagesMatch[1]}/${fileName}`; + } + } else if (file.includes('.cache/vite/deps/')) { + const depsMatch = file.match(/deps\/([^?]+)/); + if (depsMatch) { + file = `deps:${depsMatch[1]}`; + } + } else if (file.startsWith('/')) { + // Remove leading /src/ or similar + file = file.replace(/^\/src\//, ''); + if (!file.includes('/')) { + file = fileName; + } + } else { + file = fileName; + } + } + + entries.push({ + operation, + time, + file, + fullLine: line.trim() + }); + } + } + + return entries; +} + +function analyzePerf(entries: PerfEntry[]) { + console.log('\nšŸ“Š VITE PERFORMANCE ANALYSIS\n'); + console.log('='.repeat(80)); + + // Top 20 slowest individual operations + console.log('\n🐌 TOP 20 SLOWEST OPERATIONS:\n'); + const sorted = [...entries].sort((a, b) => b.time - a.time).slice(0, 20); + sorted.forEach((entry, i) => { + console.log(`${String(i + 1).padStart(2)}. ${entry.time.toFixed(2).padStart(8)}ms [${entry.operation.padEnd(15)}] ${entry.file}`); + }); + + // Aggregate by operation type + console.log('\nāš™ļø BY OPERATION TYPE:\n'); + const byOperation = new Map(); + for (const entry of entries) { + if (!byOperation.has(entry.operation)) { + byOperation.set(entry.operation, { totalTime: 0, count: 0, files: [] }); + } + const stats = byOperation.get(entry.operation)!; + stats.totalTime += entry.time; + stats.count++; + } + + const operationsSorted = Array.from(byOperation.entries()) + .sort((a, b) => b[1].totalTime - a[1].totalTime); + + operationsSorted.forEach(([op, stats]) => { + const avgTime = stats.totalTime / stats.count; + console.log(`${op.padEnd(20)} ${stats.totalTime.toFixed(0).padStart(8)}ms total (${stats.count.toString().padStart(4)} ops, ${avgTime.toFixed(1)}ms avg)`); + }); + + // Aggregate by package/category + console.log('\nšŸ“¦ BY PACKAGE/CATEGORY:\n'); + const byPackage = new Map(); + for (const entry of entries) { + let category = 'other'; + if (entry.file.startsWith('pkg:ckeditor5')) { + category = 'CKEditor Core'; + } else if (entry.file.startsWith('pkg:')) { + category = entry.file.split('/')[0]; + } else if (entry.file.startsWith('deps:ckeditor5-premium')) { + category = 'CKEditor Premium'; + } else if (entry.file.startsWith('deps:ckeditor5')) { + category = 'CKEditor Core (deps)'; + } else if (entry.file.startsWith('deps:@codemirror')) { + category = 'CodeMirror'; + } else if (entry.file.startsWith('deps:')) { + category = 'Dependencies'; + } else if (entry.file.includes('.css')) { + category = 'CSS'; + } + + if (!byPackage.has(category)) { + byPackage.set(category, { totalTime: 0, count: 0, files: [] }); + } + const stats = byPackage.get(category)!; + stats.totalTime += entry.time; + stats.count++; + if (!stats.files.includes(entry.file)) { + stats.files.push(entry.file); + } + } + + const packagesSorted = Array.from(byPackage.entries()) + .sort((a, b) => b[1].totalTime - a[1].totalTime); + + packagesSorted.forEach(([pkg, stats]) => { + console.log(`${pkg.padEnd(30)} ${stats.totalTime.toFixed(0).padStart(8)}ms (${stats.count.toString().padStart(4)} files)`); + }); + + // CKEditor breakdown + console.log('\nāœļø CKEDITOR PLUGIN BREAKDOWN:\n'); + const ckeditorEntries = entries.filter(e => + e.file.includes('ckeditor5') && + (e.file.includes('admonition') || + e.file.includes('footnotes') || + e.file.includes('math') || + e.file.includes('mermaid') || + e.file.includes('keyboard-marker')) + ); + + const byCKPlugin = new Map(); + for (const entry of ckeditorEntries) { + let plugin = 'unknown'; + if (entry.file.includes('admonition')) plugin = 'admonition'; + else if (entry.file.includes('footnotes')) plugin = 'footnotes'; + else if (entry.file.includes('math')) plugin = 'math'; + else if (entry.file.includes('mermaid')) plugin = 'mermaid'; + else if (entry.file.includes('keyboard-marker')) plugin = 'keyboard-marker'; + + if (!byCKPlugin.has(plugin)) { + byCKPlugin.set(plugin, { totalTime: 0, count: 0, files: [] }); + } + const stats = byCKPlugin.get(plugin)!; + stats.totalTime += entry.time; + stats.count++; + } + + const pluginsSorted = Array.from(byCKPlugin.entries()) + .sort((a, b) => b[1].totalTime - a[1].totalTime); + + pluginsSorted.forEach(([plugin, stats]) => { + console.log(`${plugin.padEnd(20)} ${stats.totalTime.toFixed(0).padStart(8)}ms (${stats.count} files)`); + }); + + // Summary stats + const totalTime = entries.reduce((sum, e) => sum + e.time, 0); + const totalOps = entries.length; + + console.log('\nšŸ“ˆ SUMMARY:\n'); + console.log(`Total operations: ${totalOps}`); + console.log(`Total time: ${(totalTime / 1000).toFixed(1)}s`); + console.log(`Average per op: ${(totalTime / totalOps).toFixed(1)}ms`); + console.log(`Operations > 500ms: ${entries.filter(e => e.time > 500).length}`); + console.log(`Operations > 1000ms: ${entries.filter(e => e.time > 1000).length}`); + console.log(`Operations > 3000ms: ${entries.filter(e => e.time > 3000).length}`); + + console.log('\n' + '='.repeat(80) + '\n'); +} + +// Main +const perfFile = path.join(process.cwd(), 'perf.txt'); +if (!fs.existsSync(perfFile)) { + console.error('āŒ perf.txt not found. Run with DEBUG=vite:* first.'); + process.exit(1); +} + +console.log(`šŸ“‚ Reading ${perfFile}...`); +const entries = parsePerf(perfFile); +console.log(`šŸ“Š Found ${entries.length} performance entries`); + +if (entries.length === 0) { + console.error('āŒ No performance data found in perf.txt'); + console.error(' Expected lines like: "vite:load 123.45ms [fs] /path/to/file"'); + process.exit(1); +} + +analyzePerf(entries); From fb1530423d9527bd6804c06c6dfa5b887b8b7247 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 21:12:35 +0200 Subject: [PATCH 02/24] chore(scripts): add more categories to analyze performance --- scripts/analyze-perf.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts index 754a7ee7f5..d93e571bae 100644 --- a/scripts/analyze-perf.ts +++ b/scripts/analyze-perf.ts @@ -126,7 +126,9 @@ function analyzePerf(entries: PerfEntry[]) { console.log('\nšŸ“¦ BY PACKAGE/CATEGORY:\n'); const byPackage = new Map(); for (const entry of entries) { - let category = 'other'; + let category = 'Other'; + + // Check package prefixes first if (entry.file.startsWith('pkg:ckeditor5')) { category = 'CKEditor Core'; } else if (entry.file.startsWith('pkg:')) { @@ -139,8 +141,32 @@ function analyzePerf(entries: PerfEntry[]) { category = 'CodeMirror'; } else if (entry.file.startsWith('deps:')) { category = 'Dependencies'; + } + // Break down app source files + else if (entry.file.includes('widgets/')) { + if (entry.file.includes('type_widgets/')) { + category = 'App: Type Widgets'; + } else if (entry.file.includes('collections/')) { + category = 'App: Collections'; + } else if (entry.file.includes('ribbon/')) { + category = 'App: Ribbon'; + } else if (entry.file.includes('dialogs/')) { + category = 'App: Dialogs'; + } else if (entry.file.includes('launch_bar/')) { + category = 'App: Launch Bar'; + } else { + category = 'App: Widgets'; + } + } else if (entry.file.includes('services/')) { + category = 'App: Services'; + } else if (entry.file.includes('components/')) { + category = 'App: Components'; + } else if (entry.file.includes('menus/')) { + category = 'App: Menus'; } else if (entry.file.includes('.css')) { category = 'CSS'; + } else if (entry.file.match(/\.(png|jpg|jpeg|svg|gif|woff|woff2|ttf|eot)$/i)) { + category = 'Assets'; } if (!byPackage.has(category)) { From c7d446f4aa3960381ba564ebee8154fb85cd6a04 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 21:13:34 +0200 Subject: [PATCH 03/24] chore(scripts): display time in seconds --- scripts/analyze-perf.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts index d93e571bae..e064513c07 100644 --- a/scripts/analyze-perf.ts +++ b/scripts/analyze-perf.ts @@ -99,7 +99,7 @@ function analyzePerf(entries: PerfEntry[]) { console.log('\n🐌 TOP 20 SLOWEST OPERATIONS:\n'); const sorted = [...entries].sort((a, b) => b.time - a.time).slice(0, 20); sorted.forEach((entry, i) => { - console.log(`${String(i + 1).padStart(2)}. ${entry.time.toFixed(2).padStart(8)}ms [${entry.operation.padEnd(15)}] ${entry.file}`); + console.log(`${String(i + 1).padStart(2)}. ${(entry.time / 1000).toFixed(2).padStart(6)}s [${entry.operation.padEnd(15)}] ${entry.file}`); }); // Aggregate by operation type @@ -119,7 +119,7 @@ function analyzePerf(entries: PerfEntry[]) { operationsSorted.forEach(([op, stats]) => { const avgTime = stats.totalTime / stats.count; - console.log(`${op.padEnd(20)} ${stats.totalTime.toFixed(0).padStart(8)}ms total (${stats.count.toString().padStart(4)} ops, ${avgTime.toFixed(1)}ms avg)`); + console.log(`${op.padEnd(20)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s total (${stats.count.toString().padStart(4)} ops, ${(avgTime / 1000).toFixed(3)}s avg)`); }); // Aggregate by package/category @@ -127,7 +127,7 @@ function analyzePerf(entries: PerfEntry[]) { const byPackage = new Map(); for (const entry of entries) { let category = 'Other'; - + // Check package prefixes first if (entry.file.startsWith('pkg:ckeditor5')) { category = 'CKEditor Core'; @@ -141,7 +141,7 @@ function analyzePerf(entries: PerfEntry[]) { category = 'CodeMirror'; } else if (entry.file.startsWith('deps:')) { category = 'Dependencies'; - } + } // Break down app source files else if (entry.file.includes('widgets/')) { if (entry.file.includes('type_widgets/')) { @@ -184,7 +184,7 @@ function analyzePerf(entries: PerfEntry[]) { .sort((a, b) => b[1].totalTime - a[1].totalTime); packagesSorted.forEach(([pkg, stats]) => { - console.log(`${pkg.padEnd(30)} ${stats.totalTime.toFixed(0).padStart(8)}ms (${stats.count.toString().padStart(4)} files)`); + console.log(`${pkg.padEnd(30)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s (${stats.count.toString().padStart(4)} files)`); }); // CKEditor breakdown @@ -219,7 +219,7 @@ function analyzePerf(entries: PerfEntry[]) { .sort((a, b) => b[1].totalTime - a[1].totalTime); pluginsSorted.forEach(([plugin, stats]) => { - console.log(`${plugin.padEnd(20)} ${stats.totalTime.toFixed(0).padStart(8)}ms (${stats.count} files)`); + console.log(`${plugin.padEnd(20)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s (${stats.count} files)`); }); // Summary stats From 1f72ab959357b4fba367c6de461874c7c71d9f02 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 21:20:13 +0200 Subject: [PATCH 04/24] chore(scripts): spawn process automatically --- scripts/analyze-perf.ts | 90 ++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts index e064513c07..e76d9ca8ad 100644 --- a/scripts/analyze-perf.ts +++ b/scripts/analyze-perf.ts @@ -1,5 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; +import { spawn } from 'child_process'; interface PerfEntry { operation: string; @@ -19,10 +20,7 @@ function stripAnsi(text: string): string { return text.replace(/\x1b\[[0-9;]*m/g, '').replace(/\[(\d+)m/g, ''); } -function parsePerf(filePath: string): PerfEntry[] { - // Read as UTF-16 LE which is what PowerShell's Tee-Object writes - const content = fs.readFileSync(filePath, 'utf16le'); - const lines = content.split('\n'); +function parsePerfFromLines(lines: string[]): PerfEntry[] { const entries: PerfEntry[] = []; // Match patterns like: "vite:load 7776.91ms [fs] /path/to/file" @@ -237,21 +235,75 @@ function analyzePerf(entries: PerfEntry[]) { console.log('\n' + '='.repeat(80) + '\n'); } -// Main -const perfFile = path.join(process.cwd(), 'perf.txt'); -if (!fs.existsSync(perfFile)) { - console.error('āŒ perf.txt not found. Run with DEBUG=vite:* first.'); - process.exit(1); +// Main - runs pnpm server:start and analyzes output automatically +async function runPerfAnalysis() { + console.log('šŸš€ Starting pnpm server:start with DEBUG=vite:*...\n'); + console.log('ā³ This will take about 60 seconds...\n'); + + const lines: string[] = []; + let dataCount = 0; + + return new Promise((resolve, reject) => { + const child = spawn('pnpm', ['server:start'], { + env: { ...process.env, DEBUG: 'vite:*' }, + shell: true, + cwd: path.join(__dirname, '..'), + stdio: ['ignore', 'pipe', 'pipe'] + }); + + child.stdout?.setEncoding('utf8'); + child.stderr?.setEncoding('utf8'); + + child.stdout?.on('data', (data) => { + dataCount++; + const text = String(data); + lines.push(...text.split('\n')); + process.stdout.write('.'); + }); + + child.stderr?.on('data', (data) => { + dataCount++; + const text = String(data); + lines.push(...text.split('\n')); + process.stdout.write('.'); + }); + + // Wait 60 seconds then kill the process + setTimeout(() => { + child.kill('SIGTERM'); + + // Give it a moment to clean up + setTimeout(() => { + console.log('\n\nāœ… Collected output, analyzing...\n'); + console.log(` Received ${dataCount} data chunks, ${lines.length} lines`); + + const entries = parsePerfFromLines(lines); + console.log(`šŸ“Š Found ${entries.length} performance entries`); + + if (entries.length === 0) { + console.error('āŒ No performance data found'); + console.error(' Expected lines like: "vite:load 123.45ms [fs] /path/to/file"'); + console.error(`\n Sample lines collected (first 20):`); + lines.slice(0, 20).forEach(line => { + if (line.trim()) console.error(` "${line}"`); + }); + reject(new Error('No performance data found')); + return; + } + + analyzePerf(entries); + resolve(); + }, 1000); + }, 60000); + + child.on('error', (error) => { + console.error(`āŒ Failed to start process: ${error.message}`); + reject(error); + }); + }); } -console.log(`šŸ“‚ Reading ${perfFile}...`); -const entries = parsePerf(perfFile); -console.log(`šŸ“Š Found ${entries.length} performance entries`); - -if (entries.length === 0) { - console.error('āŒ No performance data found in perf.txt'); - console.error(' Expected lines like: "vite:load 123.45ms [fs] /path/to/file"'); +runPerfAnalysis().catch(error => { + console.error('āŒ Analysis failed:', error); process.exit(1); -} - -analyzePerf(entries); +}); From c834c01c8ec9d067c9fb200274f55c00305061f1 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 21:48:27 +0200 Subject: [PATCH 05/24] chore(scripts): improve performance analysis script by timing out earlier --- scripts/analyze-perf.ts | 109 ++++++++++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 16 deletions(-) diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts index e76d9ca8ad..96305f88c4 100644 --- a/scripts/analyze-perf.ts +++ b/scripts/analyze-perf.ts @@ -235,6 +235,45 @@ function analyzePerf(entries: PerfEntry[]) { console.log('\n' + '='.repeat(80) + '\n'); } +// Helper to make HTTP request to trigger Vite rendering +async function makeHttpRequest(): Promise { + return new Promise((resolve) => { + console.log('\n🌐 Making request to http://localhost:8080 to trigger Vite...'); + + const http = require('http'); + const req = http.get('http://localhost:8080', (res: any) => { + console.log(` āœ… Response status: ${res.statusCode}`); + console.log(` Response headers:`, res.headers); + + let body = ''; + res.on('data', (chunk: any) => { + body += chunk; + }); + + res.on('end', () => { + console.log(` Response body length: ${body.length} bytes`); + if (body.length < 1000) { + console.log(` Response body: ${body}`); + } else { + console.log(` Response body preview (first 500 chars):\n${body.substring(0, 500)}`); + } + resolve(); + }); + }); + + req.on('error', (err: any) => { + console.log(` āŒ Request failed: ${err.message}`); + resolve(); // Continue anyway + }); + + req.setTimeout(5000, () => { + console.log(` ā±ļø Request timed out after 5 seconds`); + req.destroy(); + resolve(); + }); + }); +} + // Main - runs pnpm server:start and analyzes output automatically async function runPerfAnalysis() { console.log('šŸš€ Starting pnpm server:start with DEBUG=vite:*...\n'); @@ -245,7 +284,11 @@ async function runPerfAnalysis() { return new Promise((resolve, reject) => { const child = spawn('pnpm', ['server:start'], { - env: { ...process.env, DEBUG: 'vite:*' }, + env: { + ...process.env, + DEBUG: 'vite:*', + TRILIUM_GENERAL_NOAUTHENTICATION: '1' + }, shell: true, cwd: path.join(__dirname, '..'), stdio: ['ignore', 'pipe', 'pipe'] @@ -254,28 +297,22 @@ async function runPerfAnalysis() { child.stdout?.setEncoding('utf8'); child.stderr?.setEncoding('utf8'); - child.stdout?.on('data', (data) => { - dataCount++; - const text = String(data); - lines.push(...text.split('\n')); - process.stdout.write('.'); - }); + let lastActivityTime = Date.now(); + let maxTimeoutHandle: NodeJS.Timeout; + let inactivityCheckInterval: NodeJS.Interval; + let serverStarted = false; - child.stderr?.on('data', (data) => { - dataCount++; - const text = String(data); - lines.push(...text.split('\n')); - process.stdout.write('.'); - }); - - // Wait 60 seconds then kill the process - setTimeout(() => { + const finishCollection = () => { + clearTimeout(maxTimeoutHandle); + clearInterval(inactivityCheckInterval); child.kill('SIGTERM'); // Give it a moment to clean up setTimeout(() => { + const elapsedSeconds = ((Date.now() - lastActivityTime) / 1000).toFixed(1); console.log('\n\nāœ… Collected output, analyzing...\n'); console.log(` Received ${dataCount} data chunks, ${lines.length} lines`); + console.log(` Last activity was ${elapsedSeconds}s ago`); const entries = parsePerfFromLines(lines); console.log(`šŸ“Š Found ${entries.length} performance entries`); @@ -294,8 +331,48 @@ async function runPerfAnalysis() { analyzePerf(entries); resolve(); }, 1000); + }; + + child.stdout?.on('data', (data) => { + dataCount++; + lastActivityTime = Date.now(); + const text = String(data); + lines.push(...text.split('\n')); + process.stdout.write('.'); + + // Check if server has started + if (!serverStarted && text.includes('Listening on')) { + serverStarted = true; + // Wait 2 seconds for Vite to initialize, then make a request + setTimeout(async () => { + await makeHttpRequest(); + }, 2000); + } + }); + + child.stderr?.on('data', (data) => { + dataCount++; + lastActivityTime = Date.now(); + const text = String(data); + lines.push(...text.split('\n')); + process.stdout.write('.'); + }); + + // Maximum timeout of 60 seconds + maxTimeoutHandle = setTimeout(() => { + console.log('\nā±ļø Reached 60 second maximum timeout'); + finishCollection(); }, 60000); + // Check every second for 10 seconds of inactivity + inactivityCheckInterval = setInterval(() => { + const inactiveSeconds = (Date.now() - lastActivityTime) / 1000; + if (inactiveSeconds >= 10) { + console.log('\nā±ļø No activity for 10 seconds, finishing...'); + finishCollection(); + } + }, 1000); + child.on('error', (error) => { console.error(`āŒ Failed to start process: ${error.message}`); reject(error); From f503c4ca6ce034be42ba5a7819304e80e7cb2a72 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 21:49:16 +0200 Subject: [PATCH 06/24] feat(ckeditor5-math): use dynamic import to reduce loading time --- packages/ckeditor5-math/src/index.ts | 5 +---- packages/ckeditor5-math/src/ui/mathinputview.ts | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/ckeditor5-math/src/index.ts b/packages/ckeditor5-math/src/index.ts index eac4d7b223..fca15d1b00 100644 --- a/packages/ckeditor5-math/src/index.ts +++ b/packages/ckeditor5-math/src/index.ts @@ -1,9 +1,6 @@ import ckeditor from './../theme/icons/math.svg?raw'; import './augmentation.js'; -import "../theme/mathform.css"; -import 'mathlive'; -import 'mathlive/fonts.css'; -import 'mathlive/static.css'; +import '../theme/mathform.css'; export { default as Math } from './math.js'; export { default as MathUI } from './mathui.js'; diff --git a/packages/ckeditor5-math/src/ui/mathinputview.ts b/packages/ckeditor5-math/src/ui/mathinputview.ts index 027b7aab9b..2eb0347e58 100644 --- a/packages/ckeditor5-math/src/ui/mathinputview.ts +++ b/packages/ckeditor5-math/src/ui/mathinputview.ts @@ -2,6 +2,7 @@ // and keeps them in sync for the CKEditor 5 math dialog. import { View, type Locale, type FocusableView } from 'ckeditor5'; import 'mathlive/fonts.css'; // Auto-bundles offline fonts +import 'mathlive/static.css'; // Static styles for mathlive declare global { interface Window { From a5512267c123ba17736ba06499c89319d3614430 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 21:54:23 +0200 Subject: [PATCH 07/24] feat(ckeditor5): lazy-load premium features --- .../src/widgets/type_widgets/text/config.ts | 27 +++++++++---------- packages/ckeditor5/src/index.ts | 5 ++-- packages/ckeditor5/src/plugins.ts | 17 +++++++----- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/apps/client/src/widgets/type_widgets/text/config.ts b/apps/client/src/widgets/type_widgets/text/config.ts index 4457059273..4066387fc1 100644 --- a/apps/client/src/widgets/type_widgets/text/config.ts +++ b/apps/client/src/widgets/type_widgets/text/config.ts @@ -1,15 +1,16 @@ -import { ALLOWED_PROTOCOLS, DISPLAYABLE_LOCALE_IDS, MIME_TYPE_AUTO } from "@triliumnext/commons"; -import { buildExtraCommands, type EditorConfig, getCkLocale, PREMIUM_PLUGINS, TemplateDefinition } from "@triliumnext/ckeditor5"; -import { getHighlightJsNameForMime } from "../../../services/mime_types.js"; -import options from "../../../services/options.js"; -import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js"; +import { buildExtraCommands, type EditorConfig, getCkLocale, loadPremiumPlugins, TemplateDefinition } from "@triliumnext/ckeditor5"; import emojiDefinitionsUrl from "@triliumnext/ckeditor5/src/emoji_definitions/en.json?url"; +import { ALLOWED_PROTOCOLS, DISPLAYABLE_LOCALE_IDS, MIME_TYPE_AUTO } from "@triliumnext/commons"; +import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; + import { copyTextWithToast } from "../../../services/clipboard_ext.js"; import { t } from "../../../services/i18n.js"; import { getMermaidConfig } from "../../../services/mermaid.js"; -import noteAutocompleteService, { type Suggestion } from "../../../services/note_autocomplete.js"; +import { getHighlightJsNameForMime } from "../../../services/mime_types.js"; import mimeTypesService from "../../../services/mime_types.js"; -import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; +import noteAutocompleteService, { type Suggestion } from "../../../services/note_autocomplete.js"; +import options from "../../../services/options.js"; +import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js"; import { buildToolbarConfig } from "./toolbar.js"; export const OPEN_SOURCE_LICENSE_KEY = "GPL"; @@ -36,7 +37,7 @@ export async function buildConfig(opts: BuildEditorOptions): Promise { - (window as any).katex = (await import("../../../services/math.js")).default + (window as any).katex = (await import("../../../services/math.js")).default; }, forceOutputType: false, // forces output to use outputType enablePreview: true // Enable preview view @@ -172,7 +173,7 @@ export async function buildConfig(opts: BuildEditorOptions): Promise { + const { SlashCommand, Template, FormatPainter } = await import('ckeditor5-premium-features'); + // Also load the CSS when premium features are used + await import('ckeditor5-premium-features/ckeditor5-premium-features.css'); + return [SlashCommand, Template, FormatPainter]; +} /** * The set of plugins that are required for the editor to work. This is used in normal text editors (floating or fixed toolbar) but not in the attribute editor. From e298f5ea6fea8c05ac47a60b9c3c057a503746d1 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 22:12:41 +0200 Subject: [PATCH 08/24] chore(client): optimize dependencies more aggressively --- apps/client/vite.config.mts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index 8d3b0c5834..3fcea46f36 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -1,9 +1,9 @@ /// +import preact from "@preact/preset-vite"; import { join, resolve } from 'path'; +import webpackStatsPlugin from 'rollup-plugin-webpack-stats'; import { defineConfig, type Plugin } from 'vite'; import { viteStaticCopy } from 'vite-plugin-static-copy' -import webpackStatsPlugin from 'rollup-plugin-webpack-stats'; -import preact from "@preact/preset-vite"; const assets = [ "assets", "stylesheets", "fonts", "translations" ]; @@ -62,6 +62,22 @@ export default defineConfig(() => ({ "preact/hooks" ] }, + optimizeDeps: { + include: [ + "ckeditor5-premium-features", + "ckeditor5", + "codemirror", + "mathlive", + "@triliumnext/ckeditor5", + "@triliumnext/ckeditor5-math", + "@triliumnext/ckeditor5-mermaid", + "@triliumnext/ckeditor5-admonition", + "@triliumnext/ckeditor5-footnotes", + "@triliumnext/ckeditor5-keyboard-marker", + "@triliumnext/codemirror", + "@triliumnext/highlightjs" + ] + }, build: { target: "esnext", outDir: './dist', From a238fc16b20f8e89eee0f4a0e439550fe005587d Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 22:26:01 +0200 Subject: [PATCH 09/24] chore(client): add more optimize deps --- apps/server/src/routes/assets.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/server/src/routes/assets.ts b/apps/server/src/routes/assets.ts index 983c482c4b..72d7ce7e26 100644 --- a/apps/server/src/routes/assets.ts +++ b/apps/server/src/routes/assets.ts @@ -29,7 +29,23 @@ async function register(app: express.Application) { cacheDir: path.join(srcRoot, "../../.cache/vite"), base: `/${assetUrlFragment}/`, root: clientDir, - css: { devSourcemap: true } + css: { devSourcemap: true }, + optimizeDeps: { + include: [ + "ckeditor5-premium-features", + "ckeditor5", + "codemirror", + "mathlive", + "@triliumnext/ckeditor5", + "@triliumnext/ckeditor5-math", + "@triliumnext/ckeditor5-mermaid", + "@triliumnext/ckeditor5-admonition", + "@triliumnext/ckeditor5-footnotes", + "@triliumnext/ckeditor5-keyboard-marker", + "@triliumnext/codemirror", + "@triliumnext/highlightjs" + ] + }, }); app.use(`/${assetUrlFragment}/`, (req, res, next) => { req.url = `/${assetUrlFragment}${req.url}`; From 7773059ac0571893d931c77f573a3b0abef60dda Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 22:39:12 +0200 Subject: [PATCH 10/24] chore(client): optimize babel --- apps/client/vite.config.mts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index 3fcea46f36..1b018a165d 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -10,8 +10,10 @@ const assets = [ "assets", "stylesheets", "fonts", "translations" ]; const isDev = process.env.NODE_ENV === "development"; let plugins: any = [ preact({ - babel: { - compact: !isDev + // Disable Babel in dev for faster transforms (use esbuild instead) + // Babel takes ~2.5s per TSX file, esbuild takes ~100ms + babel: isDev ? undefined : { + compact: true } }) ]; From df1beb1ffb8f2e9a5fa593d9cf3ede61cfe6f2ff Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 23:03:43 +0200 Subject: [PATCH 11/24] chore(client): set up LightningCSS --- apps/client/package.json | 1 + apps/client/vite.config.mts | 6 + pnpm-lock.yaml | 294 +++++++++++++++++------------------- 3 files changed, 145 insertions(+), 156 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index a76b75b3bc..cb27f7617d 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -79,6 +79,7 @@ "@types/tabulator-tables": "6.3.1", "copy-webpack-plugin": "13.0.1", "happy-dom": "20.0.11", + "lightningcss": "1.30.2", "script-loader": "0.7.2", "vite-plugin-static-copy": "3.1.4" } diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index 1b018a165d..cb5f4291dd 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -45,6 +45,12 @@ export default defineConfig(() => ({ cacheDir: '../../node_modules/.vite/apps/client', base: "", plugins, + css: { + // Use Lightning CSS (Rust-based) for much faster CSS transforms + transformer: 'lightningcss', + // Disable CSS source maps in dev for faster transforms + devSourcemap: false + }, resolve: { alias: [ { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 19d8f1a839..84ec2fe15b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,10 +54,10 @@ importers: version: 24.10.4 '@vitest/browser-webdriverio': specifier: 4.0.16 - version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) + version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) '@vitest/coverage-v8': specifier: 4.0.16 - version: 4.0.16(@vitest/browser@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16))(vitest@4.0.16) + version: 4.0.16(@vitest/browser@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16))(vitest@4.0.16) '@vitest/ui': specifier: 4.0.16 version: 4.0.16(vitest@4.0.16) @@ -105,7 +105,7 @@ importers: version: 0.18.0 rollup-plugin-webpack-stats: specifier: 2.1.9 - version: 2.1.9(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.1.9(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) tslib: specifier: 2.8.1 version: 2.8.1 @@ -123,13 +123,13 @@ importers: version: 2.0.1 vite: specifier: 7.3.0 - version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) vite-plugin-dts: specifier: ~4.5.0 - version: 4.5.4(@types/node@24.10.4)(rollup@4.52.0)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 4.5.4(@types/node@24.10.4)(rollup@4.52.0)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: 4.0.16 - version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) apps/build-docs: devDependencies: @@ -313,7 +313,7 @@ importers: version: 5.0.0 '@preact/preset-vite': specifier: 2.10.2 - version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@types/bootstrap': specifier: 5.2.10 version: 5.2.10 @@ -341,12 +341,15 @@ importers: happy-dom: specifier: 20.0.11 version: 20.0.11 + lightningcss: + specifier: 1.30.2 + version: 1.30.2 script-loader: specifier: 0.7.2 version: 0.7.2 vite-plugin-static-copy: specifier: 3.1.4 - version: 3.1.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 3.1.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) apps/db-compare: dependencies: @@ -521,7 +524,7 @@ importers: version: 2.1.3(electron@39.2.7) '@preact/preset-vite': specifier: 2.10.2 - version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@triliumnext/commons': specifier: workspace:* version: link:../../packages/commons @@ -794,7 +797,7 @@ importers: version: 1.0.1 vite: specifier: 7.3.0 - version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) ws: specifier: 8.18.3 version: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -834,7 +837,7 @@ importers: devDependencies: '@preact/preset-vite': specifier: 2.10.2 - version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) @@ -849,10 +852,10 @@ importers: version: 0.4.2 vite: specifier: 7.3.0 - version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) vitest: specifier: 4.0.16 - version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) packages/ckeditor5: dependencies: @@ -907,7 +910,7 @@ importers: version: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 4.0.16 - version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) + version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) '@vitest/coverage-istanbul': specifier: 4.0.16 version: 4.0.16(vitest@4.0.16) @@ -940,10 +943,10 @@ importers: version: 5.9.3 vite-plugin-svgo: specifier: ~2.0.0 - version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: 4.0.16 - version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) webdriverio: specifier: 9.23.0 version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -967,7 +970,7 @@ importers: version: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 4.0.16 - version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) + version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) '@vitest/coverage-istanbul': specifier: 4.0.16 version: 4.0.16(vitest@4.0.16) @@ -1000,10 +1003,10 @@ importers: version: 5.9.3 vite-plugin-svgo: specifier: ~2.0.0 - version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: 4.0.16 - version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) webdriverio: specifier: 9.23.0 version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -1027,7 +1030,7 @@ importers: version: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 4.0.16 - version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) + version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) '@vitest/coverage-istanbul': specifier: 4.0.16 version: 4.0.16(vitest@4.0.16) @@ -1060,10 +1063,10 @@ importers: version: 5.9.3 vite-plugin-svgo: specifier: ~2.0.0 - version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: 4.0.16 - version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) webdriverio: specifier: 9.23.0 version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -1094,7 +1097,7 @@ importers: version: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 4.0.16 - version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) + version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) '@vitest/coverage-istanbul': specifier: 4.0.16 version: 4.0.16(vitest@4.0.16) @@ -1127,10 +1130,10 @@ importers: version: 5.9.3 vite-plugin-svgo: specifier: ~2.0.0 - version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: 4.0.16 - version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) webdriverio: specifier: 9.23.0 version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -1161,7 +1164,7 @@ importers: version: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 4.0.16 - version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) + version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) '@vitest/coverage-istanbul': specifier: 4.0.16 version: 4.0.16(vitest@4.0.16) @@ -1194,10 +1197,10 @@ importers: version: 5.9.3 vite-plugin-svgo: specifier: ~2.0.0 - version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: 4.0.16 - version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) webdriverio: specifier: 9.23.0 version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -9949,68 +9952,74 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lightningcss-darwin-arm64@1.30.1: - resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.1: - resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.1: - resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.1: - resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.1: - resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.30.1: - resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.30.1: - resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.30.1: - resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.30.1: - resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.1: - resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.1: - resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} lilconfig@2.1.0: @@ -15229,6 +15238,8 @@ snapshots: '@ckeditor/ckeditor5-core': 47.3.0 '@ckeditor/ckeditor5-upload': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-ai@47.3.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -15299,6 +15310,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-block-quote@47.3.0': dependencies: @@ -15309,6 +15322,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-bookmark@47.3.0': dependencies: @@ -15365,12 +15380,16 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 '@ckeditor/ckeditor5-widget': 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-cloud-services@47.3.0': dependencies: '@ckeditor/ckeditor5-core': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-code-block@47.3.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -15544,8 +15563,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-easy-image@47.3.0': dependencies: @@ -15565,6 +15582,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-classic@47.3.0': dependencies: @@ -15574,6 +15593,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.3.0': dependencies: @@ -15594,6 +15615,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-multi-root@47.3.0': dependencies: @@ -15628,8 +15651,6 @@ snapshots: ckeditor5: 47.3.0 es-toolkit: 1.39.5 fuzzysort: 3.1.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-engine@47.3.0': dependencies: @@ -15641,8 +15662,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.3.0 '@ckeditor/ckeditor5-engine': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-essentials@47.3.0': dependencies: @@ -15698,8 +15717,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-font@47.3.0': dependencies: @@ -15749,8 +15766,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-highlight@47.3.0': dependencies: @@ -15759,8 +15774,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-horizontal-line@47.3.0': dependencies: @@ -15770,8 +15783,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.3.0': dependencies: @@ -15781,8 +15792,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-support@47.3.0': dependencies: @@ -15798,8 +15807,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-icons@47.3.0': {} @@ -15817,8 +15824,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-import-word@47.3.0': dependencies: @@ -15842,8 +15847,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-inspector@5.0.0': {} @@ -15853,8 +15856,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-line-height@47.3.0': dependencies: @@ -15865,8 +15866,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-link@47.3.0': dependencies: @@ -15881,8 +15880,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-list-multi-level@47.3.0': dependencies: @@ -15893,8 +15890,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-list@47.3.0': dependencies: @@ -15908,8 +15903,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-markdown-gfm@47.3.0': dependencies: @@ -16030,8 +16023,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-pagination@47.3.0': dependencies: @@ -16139,8 +16130,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-slash-command@47.3.0': dependencies: @@ -16153,8 +16142,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-source-editing-enhanced@47.3.0': dependencies: @@ -16202,8 +16189,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-table@47.3.0': dependencies: @@ -16326,8 +16311,6 @@ snapshots: '@ckeditor/ckeditor5-engine': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-widget@47.3.0': dependencies: @@ -16347,8 +16330,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@codemirror/autocomplete@6.18.6': dependencies: @@ -18672,18 +18653,18 @@ snapshots: '@popperjs/core@2.11.8': {} - '@preact/preset-vite@2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': + '@preact/preset-vite@2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.0) '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.0) - '@prefresh/vite': 2.4.8(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + '@prefresh/vite': 2.4.8(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@rollup/pluginutils': 4.2.1 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.0) debug: 4.4.1 picocolors: 1.1.1 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) - vite-prerender-plugin: 0.5.11(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite-prerender-plugin: 0.5.11(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) transitivePeerDependencies: - preact - supports-color @@ -18703,7 +18684,7 @@ snapshots: '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.8(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': + '@prefresh/vite@2.4.8(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 '@prefresh/babel-plugin': 0.5.2 @@ -18711,7 +18692,7 @@ snapshots: '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 preact: 10.28.1 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -20872,10 +20853,10 @@ snapshots: - bufferutil - utf-8-validate - '@vitest/browser-webdriverio@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))': + '@vitest/browser-webdriverio@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))': dependencies: - '@vitest/browser': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) - vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + '@vitest/browser': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) + vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) webdriverio: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: - bufferutil @@ -20883,16 +20864,16 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)': + '@vitest/browser@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)': dependencies: - '@vitest/mocker': 4.0.16(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + '@vitest/mocker': 4.0.16(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@vitest/utils': 4.0.16 magic-string: 0.30.21 pixelmatch: 7.1.0 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: - bufferutil @@ -20913,11 +20894,11 @@ snapshots: magicast: 0.5.1 obug: 2.1.1 tinyrainbow: 3.0.3 - vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.16(@vitest/browser@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16))(vitest@4.0.16)': + '@vitest/coverage-v8@4.0.16(@vitest/browser@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16))(vitest@4.0.16)': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.16 @@ -20930,9 +20911,9 @@ snapshots: obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) optionalDependencies: - '@vitest/browser': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) + '@vitest/browser': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16) transitivePeerDependencies: - supports-color @@ -20945,14 +20926,14 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.16(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': + '@vitest/mocker@4.0.16(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@vitest/spy': 4.0.16 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.7.5(@types/node@24.10.4)(typescript@5.9.3) - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) '@vitest/pretty-format@4.0.16': dependencies: @@ -20980,7 +20961,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) '@vitest/utils@4.0.16': dependencies: @@ -22034,8 +22015,6 @@ snapshots: ckeditor5-collaboration@47.3.0: dependencies: '@ckeditor/ckeditor5-collaboration-core': 47.3.0 - transitivePeerDependencies: - - supports-color ckeditor5-premium-features@47.3.0(bufferutil@4.0.9)(ckeditor5@47.3.0)(utf-8-validate@6.0.5): dependencies: @@ -25944,51 +25923,54 @@ snapshots: dependencies: immediate: 3.0.6 - lightningcss-darwin-arm64@1.30.1: + lightningcss-android-arm64@1.30.2: optional: true - lightningcss-darwin-x64@1.30.1: + lightningcss-darwin-arm64@1.30.2: optional: true - lightningcss-freebsd-x64@1.30.1: + lightningcss-darwin-x64@1.30.2: optional: true - lightningcss-linux-arm-gnueabihf@1.30.1: + lightningcss-freebsd-x64@1.30.2: optional: true - lightningcss-linux-arm64-gnu@1.30.1: + lightningcss-linux-arm-gnueabihf@1.30.2: optional: true - lightningcss-linux-arm64-musl@1.30.1: + lightningcss-linux-arm64-gnu@1.30.2: optional: true - lightningcss-linux-x64-gnu@1.30.1: + lightningcss-linux-arm64-musl@1.30.2: optional: true - lightningcss-linux-x64-musl@1.30.1: + lightningcss-linux-x64-gnu@1.30.2: optional: true - lightningcss-win32-arm64-msvc@1.30.1: + lightningcss-linux-x64-musl@1.30.2: optional: true - lightningcss-win32-x64-msvc@1.30.1: + lightningcss-win32-arm64-msvc@1.30.2: optional: true - lightningcss@1.30.1: + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-darwin-arm64: 1.30.1 - lightningcss-darwin-x64: 1.30.1 - lightningcss-freebsd-x64: 1.30.1 - lightningcss-linux-arm-gnueabihf: 1.30.1 - lightningcss-linux-arm64-gnu: 1.30.1 - lightningcss-linux-arm64-musl: 1.30.1 - lightningcss-linux-x64-gnu: 1.30.1 - lightningcss-linux-x64-musl: 1.30.1 - lightningcss-win32-arm64-msvc: 1.30.1 - lightningcss-win32-x64-msvc: 1.30.1 - optional: true + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 lilconfig@2.1.0: {} @@ -28816,11 +28798,11 @@ snapshots: '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.29 optional: true - rollup-plugin-stats@1.5.4(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): + rollup-plugin-stats@1.5.4(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): optionalDependencies: rolldown: 1.0.0-beta.29 rollup: 4.52.0 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) rollup-plugin-styles@4.0.0(rollup@4.52.0): dependencies: @@ -28849,13 +28831,13 @@ snapshots: '@rollup/pluginutils': 5.1.4(rollup@4.52.0) rollup: 4.52.0 - rollup-plugin-webpack-stats@2.1.9(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): + rollup-plugin-webpack-stats@2.1.9(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: - rollup-plugin-stats: 1.5.4(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + rollup-plugin-stats: 1.5.4(rolldown@1.0.0-beta.29)(rollup@4.52.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) optionalDependencies: rolldown: 1.0.0-beta.29 rollup: 4.52.0 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) rollup@4.52.0: dependencies: @@ -30768,7 +30750,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-plugin-dts@4.5.4(@types/node@24.10.4)(rollup@4.52.0)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-plugin-dts@4.5.4(@types/node@24.10.4)(rollup@4.52.0)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: '@microsoft/api-extractor': 7.52.8(@types/node@24.10.4) '@rollup/pluginutils': 5.1.4(rollup@4.52.0) @@ -30781,27 +30763,27 @@ snapshots: magic-string: 0.30.21 typescript: 5.9.3 optionalDependencies: - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-static-copy@3.1.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-plugin-static-copy@3.1.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: chokidar: 3.6.0 p-map: 7.0.3 picocolors: 1.1.1 tinyglobby: 0.2.15 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) - vite-plugin-svgo@2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-plugin-svgo@2.0.0(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: svgo: 3.3.2 typescript: 5.9.3 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) - vite-prerender-plugin@0.5.11(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-prerender-plugin@0.5.11(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: kolorist: 1.8.0 magic-string: 0.30.18 @@ -30809,9 +30791,9 @@ snapshots: simple-code-frame: 1.3.0 source-map: 0.7.6 stack-trace: 1.0.0-pre2 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) - vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1): + vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1): dependencies: esbuild: 0.27.1 fdir: 6.5.0(picomatch@4.0.3) @@ -30824,17 +30806,17 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 less: 4.1.3 - lightningcss: 1.30.1 + lightningcss: 1.30.2 sass: 1.91.0 sass-embedded: 1.91.0 terser: 5.44.0 tsx: 4.21.0 yaml: 2.8.1 - vitest@4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1): + vitest@4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.2)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1): dependencies: '@vitest/expect': 4.0.16 - '@vitest/mocker': 4.0.16(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) + '@vitest/mocker': 4.0.16(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@vitest/pretty-format': 4.0.16 '@vitest/runner': 4.0.16 '@vitest/snapshot': 4.0.16 @@ -30851,12 +30833,12 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.10.4 - '@vitest/browser-webdriverio': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) + '@vitest/browser-webdriverio': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) '@vitest/ui': 4.0.16(vitest@4.0.16) happy-dom: 20.0.11 jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) From 5dd600a291dcbdf5203632531feb056bfe20e446 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 23:09:51 +0200 Subject: [PATCH 12/24] chore(client): shared config --- apps/client/vite.config.mts | 2 +- apps/server/src/routes/assets.ts | 22 ++-------------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index cb5f4291dd..4fe9646e45 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -42,7 +42,7 @@ if (!isDev) { export default defineConfig(() => ({ root: __dirname, - cacheDir: '../../node_modules/.vite/apps/client', + cacheDir: '../../.cache/vite', base: "", plugins, css: { diff --git a/apps/server/src/routes/assets.ts b/apps/server/src/routes/assets.ts index 72d7ce7e26..3f0eb25a89 100644 --- a/apps/server/src/routes/assets.ts +++ b/apps/server/src/routes/assets.ts @@ -26,26 +26,8 @@ async function register(app: express.Application) { const vite = await createViteServer({ server: { middlewareMode: true }, appType: "custom", - cacheDir: path.join(srcRoot, "../../.cache/vite"), - base: `/${assetUrlFragment}/`, - root: clientDir, - css: { devSourcemap: true }, - optimizeDeps: { - include: [ - "ckeditor5-premium-features", - "ckeditor5", - "codemirror", - "mathlive", - "@triliumnext/ckeditor5", - "@triliumnext/ckeditor5-math", - "@triliumnext/ckeditor5-mermaid", - "@triliumnext/ckeditor5-admonition", - "@triliumnext/ckeditor5-footnotes", - "@triliumnext/ckeditor5-keyboard-marker", - "@triliumnext/codemirror", - "@triliumnext/highlightjs" - ] - }, + configFile: path.join(clientDir, "vite.config.mts"), + base: `/${assetUrlFragment}/` }); app.use(`/${assetUrlFragment}/`, (req, res, next) => { req.url = `/${assetUrlFragment}${req.url}`; From e2cf0c6e3e7fbae17c33ab617eee7446734963b7 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 10 Jan 2026 23:27:14 +0200 Subject: [PATCH 13/24] chore(client): disable preact preset-vite --- apps/client/vite.config.mts | 17 +++++++---------- pnpm-lock.yaml | 2 ++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index 4fe9646e45..1deb7469cb 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -1,5 +1,4 @@ /// -import preact from "@preact/preset-vite"; import { join, resolve } from 'path'; import webpackStatsPlugin from 'rollup-plugin-webpack-stats'; import { defineConfig, type Plugin } from 'vite'; @@ -8,15 +7,7 @@ import { viteStaticCopy } from 'vite-plugin-static-copy' const assets = [ "assets", "stylesheets", "fonts", "translations" ]; const isDev = process.env.NODE_ENV === "development"; -let plugins: any = [ - preact({ - // Disable Babel in dev for faster transforms (use esbuild instead) - // Babel takes ~2.5s per TSX file, esbuild takes ~100ms - babel: isDev ? undefined : { - compact: true - } - }) -]; +let plugins: any = []; if (!isDev) { plugins = [ @@ -45,6 +36,12 @@ export default defineConfig(() => ({ cacheDir: '../../.cache/vite', base: "", plugins, + // Use esbuild for JSX transformation (much faster than Babel) + esbuild: { + jsx: 'automatic', + jsxImportSource: 'preact', + jsxDev: isDev + }, css: { // Use Lightning CSS (Rust-based) for much faster CSS transforms transformer: 'lightningcss', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84ec2fe15b..83189eb865 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15949,6 +15949,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-merge-fields@47.3.0': dependencies: From ecdb8190670ca5943128c0f3b604ef6ac47f9004 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 00:11:13 +0200 Subject: [PATCH 14/24] chore(scripts): address requested changes --- scripts/analyze-perf.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts index 96305f88c4..b92b22656b 100644 --- a/scripts/analyze-perf.ts +++ b/scripts/analyze-perf.ts @@ -1,5 +1,5 @@ -import * as fs from 'fs'; import * as path from 'path'; +import * as http from "http"; import { spawn } from 'child_process'; interface PerfEntry { @@ -240,13 +240,12 @@ async function makeHttpRequest(): Promise { return new Promise((resolve) => { console.log('\n🌐 Making request to http://localhost:8080 to trigger Vite...'); - const http = require('http'); - const req = http.get('http://localhost:8080', (res: any) => { + const req = http.get('http://localhost:8080', (res: http.IncomingMessage) => { console.log(` āœ… Response status: ${res.statusCode}`); console.log(` Response headers:`, res.headers); let body = ''; - res.on('data', (chunk: any) => { + res.on('data', (chunk: Buffer | string) => { body += chunk; }); @@ -261,7 +260,7 @@ async function makeHttpRequest(): Promise { }); }); - req.on('error', (err: any) => { + req.on('error', (err: Error) => { console.log(` āŒ Request failed: ${err.message}`); resolve(); // Continue anyway }); @@ -299,7 +298,7 @@ async function runPerfAnalysis() { let lastActivityTime = Date.now(); let maxTimeoutHandle: NodeJS.Timeout; - let inactivityCheckInterval: NodeJS.Interval; + let inactivityCheckInterval: NodeJS.Timeout; let serverStarted = false; const finishCollection = () => { From 2e35e0a830b563919ff9e447cef96d3e2db8878f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 00:21:32 +0200 Subject: [PATCH 15/24] chore(client): re-enable source maps --- apps/client/vite.config.mts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index 1deb7469cb..335435d8fd 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -43,10 +43,8 @@ export default defineConfig(() => ({ jsxDev: isDev }, css: { - // Use Lightning CSS (Rust-based) for much faster CSS transforms transformer: 'lightningcss', - // Disable CSS source maps in dev for faster transforms - devSourcemap: false + devSourcemap: true }, resolve: { alias: [ From 94d4a307cf6b612acc6d7e0d94f5975532412a5c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 00:21:38 +0200 Subject: [PATCH 16/24] chore(scripts): remove analyze-perf --- scripts/analyze-perf.ts | 385 ---------------------------------------- 1 file changed, 385 deletions(-) delete mode 100644 scripts/analyze-perf.ts diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts deleted file mode 100644 index b92b22656b..0000000000 --- a/scripts/analyze-perf.ts +++ /dev/null @@ -1,385 +0,0 @@ -import * as path from 'path'; -import * as http from "http"; -import { spawn } from 'child_process'; - -interface PerfEntry { - operation: string; - time: number; - file: string; - fullLine: string; -} - -interface AggregatedStats { - totalTime: number; - count: number; - files: string[]; -} - -function stripAnsi(text: string): string { - // Remove ANSI escape codes - both the ESC[ format and the literal bracket format - return text.replace(/\x1b\[[0-9;]*m/g, '').replace(/\[(\d+)m/g, ''); -} - -function parsePerfFromLines(lines: string[]): PerfEntry[] { - const entries: PerfEntry[] = []; - - // Match patterns like: "vite:load 7776.91ms [fs] /path/to/file" - // or "vite:transform 1234.56ms /path/to/file" - const timePattern = /(\d+\.\d+)ms/; - const operationPattern = /vite:(load|transform|resolve|time|import-analysis)/; - - for (let line of lines) { - // Strip ANSI color codes - line = stripAnsi(line); - - const timeMatch = line.match(timePattern); - const operationMatch = line.match(operationPattern); - - if (timeMatch && operationMatch) { - const time = parseFloat(timeMatch[1]); - const operation = operationMatch[1]; - - // Extract file path - it's usually after the timing and optional [fs]/[plugin] marker - let file = 'unknown'; - // Match file paths after [fs] or [plugin] or directly after timing - const pathMatch = line.match(/(?:\[(?:fs|plugin)\]\s+)?([/\\]?[\w/.@-]+\.[a-z]+(?:\?[^\s]*)?)/i); - if (pathMatch) { - file = pathMatch[1]; - // Normalize path separators - file = file.replace(/\\/g, '/'); - // Remove query params - file = file.replace(/\?.*$/, ''); - // Get just the filename for cleaner output - const fileName = path.basename(file); - if (file.includes('node_modules')) { - const nodeModulesMatch = file.match(/node_modules\/([^\/]+)/); - if (nodeModulesMatch) { - file = `npm:${nodeModulesMatch[1]}/${fileName}`; - } - } else if (file.includes('packages/')) { - const packagesMatch = file.match(/packages\/([^\/]+)/); - if (packagesMatch) { - file = `pkg:${packagesMatch[1]}/${fileName}`; - } - } else if (file.includes('.cache/vite/deps/')) { - const depsMatch = file.match(/deps\/([^?]+)/); - if (depsMatch) { - file = `deps:${depsMatch[1]}`; - } - } else if (file.startsWith('/')) { - // Remove leading /src/ or similar - file = file.replace(/^\/src\//, ''); - if (!file.includes('/')) { - file = fileName; - } - } else { - file = fileName; - } - } - - entries.push({ - operation, - time, - file, - fullLine: line.trim() - }); - } - } - - return entries; -} - -function analyzePerf(entries: PerfEntry[]) { - console.log('\nšŸ“Š VITE PERFORMANCE ANALYSIS\n'); - console.log('='.repeat(80)); - - // Top 20 slowest individual operations - console.log('\n🐌 TOP 20 SLOWEST OPERATIONS:\n'); - const sorted = [...entries].sort((a, b) => b.time - a.time).slice(0, 20); - sorted.forEach((entry, i) => { - console.log(`${String(i + 1).padStart(2)}. ${(entry.time / 1000).toFixed(2).padStart(6)}s [${entry.operation.padEnd(15)}] ${entry.file}`); - }); - - // Aggregate by operation type - console.log('\nāš™ļø BY OPERATION TYPE:\n'); - const byOperation = new Map(); - for (const entry of entries) { - if (!byOperation.has(entry.operation)) { - byOperation.set(entry.operation, { totalTime: 0, count: 0, files: [] }); - } - const stats = byOperation.get(entry.operation)!; - stats.totalTime += entry.time; - stats.count++; - } - - const operationsSorted = Array.from(byOperation.entries()) - .sort((a, b) => b[1].totalTime - a[1].totalTime); - - operationsSorted.forEach(([op, stats]) => { - const avgTime = stats.totalTime / stats.count; - console.log(`${op.padEnd(20)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s total (${stats.count.toString().padStart(4)} ops, ${(avgTime / 1000).toFixed(3)}s avg)`); - }); - - // Aggregate by package/category - console.log('\nšŸ“¦ BY PACKAGE/CATEGORY:\n'); - const byPackage = new Map(); - for (const entry of entries) { - let category = 'Other'; - - // Check package prefixes first - if (entry.file.startsWith('pkg:ckeditor5')) { - category = 'CKEditor Core'; - } else if (entry.file.startsWith('pkg:')) { - category = entry.file.split('/')[0]; - } else if (entry.file.startsWith('deps:ckeditor5-premium')) { - category = 'CKEditor Premium'; - } else if (entry.file.startsWith('deps:ckeditor5')) { - category = 'CKEditor Core (deps)'; - } else if (entry.file.startsWith('deps:@codemirror')) { - category = 'CodeMirror'; - } else if (entry.file.startsWith('deps:')) { - category = 'Dependencies'; - } - // Break down app source files - else if (entry.file.includes('widgets/')) { - if (entry.file.includes('type_widgets/')) { - category = 'App: Type Widgets'; - } else if (entry.file.includes('collections/')) { - category = 'App: Collections'; - } else if (entry.file.includes('ribbon/')) { - category = 'App: Ribbon'; - } else if (entry.file.includes('dialogs/')) { - category = 'App: Dialogs'; - } else if (entry.file.includes('launch_bar/')) { - category = 'App: Launch Bar'; - } else { - category = 'App: Widgets'; - } - } else if (entry.file.includes('services/')) { - category = 'App: Services'; - } else if (entry.file.includes('components/')) { - category = 'App: Components'; - } else if (entry.file.includes('menus/')) { - category = 'App: Menus'; - } else if (entry.file.includes('.css')) { - category = 'CSS'; - } else if (entry.file.match(/\.(png|jpg|jpeg|svg|gif|woff|woff2|ttf|eot)$/i)) { - category = 'Assets'; - } - - if (!byPackage.has(category)) { - byPackage.set(category, { totalTime: 0, count: 0, files: [] }); - } - const stats = byPackage.get(category)!; - stats.totalTime += entry.time; - stats.count++; - if (!stats.files.includes(entry.file)) { - stats.files.push(entry.file); - } - } - - const packagesSorted = Array.from(byPackage.entries()) - .sort((a, b) => b[1].totalTime - a[1].totalTime); - - packagesSorted.forEach(([pkg, stats]) => { - console.log(`${pkg.padEnd(30)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s (${stats.count.toString().padStart(4)} files)`); - }); - - // CKEditor breakdown - console.log('\nāœļø CKEDITOR PLUGIN BREAKDOWN:\n'); - const ckeditorEntries = entries.filter(e => - e.file.includes('ckeditor5') && - (e.file.includes('admonition') || - e.file.includes('footnotes') || - e.file.includes('math') || - e.file.includes('mermaid') || - e.file.includes('keyboard-marker')) - ); - - const byCKPlugin = new Map(); - for (const entry of ckeditorEntries) { - let plugin = 'unknown'; - if (entry.file.includes('admonition')) plugin = 'admonition'; - else if (entry.file.includes('footnotes')) plugin = 'footnotes'; - else if (entry.file.includes('math')) plugin = 'math'; - else if (entry.file.includes('mermaid')) plugin = 'mermaid'; - else if (entry.file.includes('keyboard-marker')) plugin = 'keyboard-marker'; - - if (!byCKPlugin.has(plugin)) { - byCKPlugin.set(plugin, { totalTime: 0, count: 0, files: [] }); - } - const stats = byCKPlugin.get(plugin)!; - stats.totalTime += entry.time; - stats.count++; - } - - const pluginsSorted = Array.from(byCKPlugin.entries()) - .sort((a, b) => b[1].totalTime - a[1].totalTime); - - pluginsSorted.forEach(([plugin, stats]) => { - console.log(`${plugin.padEnd(20)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s (${stats.count} files)`); - }); - - // Summary stats - const totalTime = entries.reduce((sum, e) => sum + e.time, 0); - const totalOps = entries.length; - - console.log('\nšŸ“ˆ SUMMARY:\n'); - console.log(`Total operations: ${totalOps}`); - console.log(`Total time: ${(totalTime / 1000).toFixed(1)}s`); - console.log(`Average per op: ${(totalTime / totalOps).toFixed(1)}ms`); - console.log(`Operations > 500ms: ${entries.filter(e => e.time > 500).length}`); - console.log(`Operations > 1000ms: ${entries.filter(e => e.time > 1000).length}`); - console.log(`Operations > 3000ms: ${entries.filter(e => e.time > 3000).length}`); - - console.log('\n' + '='.repeat(80) + '\n'); -} - -// Helper to make HTTP request to trigger Vite rendering -async function makeHttpRequest(): Promise { - return new Promise((resolve) => { - console.log('\n🌐 Making request to http://localhost:8080 to trigger Vite...'); - - const req = http.get('http://localhost:8080', (res: http.IncomingMessage) => { - console.log(` āœ… Response status: ${res.statusCode}`); - console.log(` Response headers:`, res.headers); - - let body = ''; - res.on('data', (chunk: Buffer | string) => { - body += chunk; - }); - - res.on('end', () => { - console.log(` Response body length: ${body.length} bytes`); - if (body.length < 1000) { - console.log(` Response body: ${body}`); - } else { - console.log(` Response body preview (first 500 chars):\n${body.substring(0, 500)}`); - } - resolve(); - }); - }); - - req.on('error', (err: Error) => { - console.log(` āŒ Request failed: ${err.message}`); - resolve(); // Continue anyway - }); - - req.setTimeout(5000, () => { - console.log(` ā±ļø Request timed out after 5 seconds`); - req.destroy(); - resolve(); - }); - }); -} - -// Main - runs pnpm server:start and analyzes output automatically -async function runPerfAnalysis() { - console.log('šŸš€ Starting pnpm server:start with DEBUG=vite:*...\n'); - console.log('ā³ This will take about 60 seconds...\n'); - - const lines: string[] = []; - let dataCount = 0; - - return new Promise((resolve, reject) => { - const child = spawn('pnpm', ['server:start'], { - env: { - ...process.env, - DEBUG: 'vite:*', - TRILIUM_GENERAL_NOAUTHENTICATION: '1' - }, - shell: true, - cwd: path.join(__dirname, '..'), - stdio: ['ignore', 'pipe', 'pipe'] - }); - - child.stdout?.setEncoding('utf8'); - child.stderr?.setEncoding('utf8'); - - let lastActivityTime = Date.now(); - let maxTimeoutHandle: NodeJS.Timeout; - let inactivityCheckInterval: NodeJS.Timeout; - let serverStarted = false; - - const finishCollection = () => { - clearTimeout(maxTimeoutHandle); - clearInterval(inactivityCheckInterval); - child.kill('SIGTERM'); - - // Give it a moment to clean up - setTimeout(() => { - const elapsedSeconds = ((Date.now() - lastActivityTime) / 1000).toFixed(1); - console.log('\n\nāœ… Collected output, analyzing...\n'); - console.log(` Received ${dataCount} data chunks, ${lines.length} lines`); - console.log(` Last activity was ${elapsedSeconds}s ago`); - - const entries = parsePerfFromLines(lines); - console.log(`šŸ“Š Found ${entries.length} performance entries`); - - if (entries.length === 0) { - console.error('āŒ No performance data found'); - console.error(' Expected lines like: "vite:load 123.45ms [fs] /path/to/file"'); - console.error(`\n Sample lines collected (first 20):`); - lines.slice(0, 20).forEach(line => { - if (line.trim()) console.error(` "${line}"`); - }); - reject(new Error('No performance data found')); - return; - } - - analyzePerf(entries); - resolve(); - }, 1000); - }; - - child.stdout?.on('data', (data) => { - dataCount++; - lastActivityTime = Date.now(); - const text = String(data); - lines.push(...text.split('\n')); - process.stdout.write('.'); - - // Check if server has started - if (!serverStarted && text.includes('Listening on')) { - serverStarted = true; - // Wait 2 seconds for Vite to initialize, then make a request - setTimeout(async () => { - await makeHttpRequest(); - }, 2000); - } - }); - - child.stderr?.on('data', (data) => { - dataCount++; - lastActivityTime = Date.now(); - const text = String(data); - lines.push(...text.split('\n')); - process.stdout.write('.'); - }); - - // Maximum timeout of 60 seconds - maxTimeoutHandle = setTimeout(() => { - console.log('\nā±ļø Reached 60 second maximum timeout'); - finishCollection(); - }, 60000); - - // Check every second for 10 seconds of inactivity - inactivityCheckInterval = setInterval(() => { - const inactiveSeconds = (Date.now() - lastActivityTime) / 1000; - if (inactiveSeconds >= 10) { - console.log('\nā±ļø No activity for 10 seconds, finishing...'); - finishCollection(); - } - }, 1000); - - child.on('error', (error) => { - console.error(`āŒ Failed to start process: ${error.message}`); - reject(error); - }); - }); -} - -runPerfAnalysis().catch(error => { - console.error('āŒ Analysis failed:', error); - process.exit(1); -}); From 83a8f07998c20ba7fd3ce372a1c3a839337fa319 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 00:31:48 +0200 Subject: [PATCH 17/24] chore(client): change vite config --- apps/client/vite.config.mts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index 335435d8fd..d40f5f5aeb 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -1,7 +1,7 @@ /// -import { join, resolve } from 'path'; +import { join } from 'path'; import webpackStatsPlugin from 'rollup-plugin-webpack-stats'; -import { defineConfig, type Plugin } from 'vite'; +import { defineConfig } from 'vite'; import { viteStaticCopy } from 'vite-plugin-static-copy' const assets = [ "assets", "stylesheets", "fonts", "translations" ]; @@ -44,7 +44,7 @@ export default defineConfig(() => ({ }, css: { transformer: 'lightningcss', - devSourcemap: true + devSourcemap: isDev }, resolve: { alias: [ @@ -69,9 +69,7 @@ export default defineConfig(() => ({ include: [ "ckeditor5-premium-features", "ckeditor5", - "codemirror", "mathlive", - "@triliumnext/ckeditor5", "@triliumnext/ckeditor5-math", "@triliumnext/ckeditor5-mermaid", "@triliumnext/ckeditor5-admonition", From 349203e30047cbdbb8a20b067ae02209e7975810 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 00:35:11 +0200 Subject: [PATCH 18/24] chore(client): remove dependency to @preact/preset-vite --- apps/client/package.json | 1 - apps/server/package.json | 1 - pnpm-lock.yaml | 12 ++++-------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index cb27f7617d..d368e0deb8 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -69,7 +69,6 @@ }, "devDependencies": { "@ckeditor/ckeditor5-inspector": "5.0.0", - "@preact/preset-vite": "2.10.2", "@types/bootstrap": "5.2.10", "@types/jquery": "3.5.33", "@types/leaflet": "1.9.21", diff --git a/apps/server/package.json b/apps/server/package.json index bf4b4750cd..e769677575 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -38,7 +38,6 @@ "@anthropic-ai/sdk": "0.71.2", "@braintree/sanitize-url": "7.1.1", "@electron/remote": "2.1.3", - "@preact/preset-vite": "2.10.2", "@triliumnext/commons": "workspace:*", "@triliumnext/express-partial-content": "workspace:*", "@triliumnext/highlightjs": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83189eb865..a40362a8e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -311,9 +311,6 @@ importers: '@ckeditor/ckeditor5-inspector': specifier: 5.0.0 version: 5.0.0 - '@preact/preset-vite': - specifier: 2.10.2 - version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@types/bootstrap': specifier: 5.2.10 version: 5.2.10 @@ -522,9 +519,6 @@ importers: '@electron/remote': specifier: 2.1.3 version: 2.1.3(electron@39.2.7) - '@preact/preset-vite': - specifier: 2.10.2 - version: 2.10.2(@babel/core@7.28.0)(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@triliumnext/commons': specifier: workspace:* version: link:../../packages/commons @@ -15651,6 +15645,8 @@ snapshots: ckeditor5: 47.3.0 es-toolkit: 1.39.5 fuzzysort: 3.1.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-engine@47.3.0': dependencies: @@ -15756,6 +15752,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-heading@47.3.0': dependencies: @@ -15949,8 +15947,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-merge-fields@47.3.0': dependencies: From 8dc8b046fb4534d958ce3625a4bc5d1d6f1b60a5 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 00:55:42 +0200 Subject: [PATCH 19/24] chore(client): reintroduce live refresh --- apps/client/vite.config.mts | 9 +++++++-- pnpm-lock.yaml | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index d40f5f5aeb..18d6a5f6a6 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -1,4 +1,5 @@ /// +import prefresh from '@prefresh/vite'; import { join } from 'path'; import webpackStatsPlugin from 'rollup-plugin-webpack-stats'; import { defineConfig } from 'vite'; @@ -9,9 +10,13 @@ const assets = [ "assets", "stylesheets", "fonts", "translations" ]; const isDev = process.env.NODE_ENV === "development"; let plugins: any = []; -if (!isDev) { +if (isDev) { + // Add Prefresh for Preact HMR in development + plugins = [ + prefresh() + ]; +} else { plugins = [ - ...plugins, viteStaticCopy({ targets: assets.map((asset) => ({ src: `src/${asset}/*`, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a40362a8e5..95c5bf529d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15752,8 +15752,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-heading@47.3.0': dependencies: @@ -15947,6 +15945,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-merge-fields@47.3.0': dependencies: From d609ee028e760aac90194d2cf2ec61dd4de107a6 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 10:55:13 +0200 Subject: [PATCH 20/24] chore(client): get rid of workspace projects from optimizeDeps --- apps/client/vite.config.mts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/client/vite.config.mts b/apps/client/vite.config.mts index 18d6a5f6a6..ccd150703d 100644 --- a/apps/client/vite.config.mts +++ b/apps/client/vite.config.mts @@ -74,14 +74,7 @@ export default defineConfig(() => ({ include: [ "ckeditor5-premium-features", "ckeditor5", - "mathlive", - "@triliumnext/ckeditor5-math", - "@triliumnext/ckeditor5-mermaid", - "@triliumnext/ckeditor5-admonition", - "@triliumnext/ckeditor5-footnotes", - "@triliumnext/ckeditor5-keyboard-marker", - "@triliumnext/codemirror", - "@triliumnext/highlightjs" + "mathlive" ] }, build: { From 244294f69966faf3d0b3c0de429e80e9685fa83b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 10:55:47 +0200 Subject: [PATCH 21/24] Revert "chore(scripts): remove analyze-perf" This reverts commit 94d4a307cf6b612acc6d7e0d94f5975532412a5c. --- scripts/analyze-perf.ts | 385 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 scripts/analyze-perf.ts diff --git a/scripts/analyze-perf.ts b/scripts/analyze-perf.ts new file mode 100644 index 0000000000..b92b22656b --- /dev/null +++ b/scripts/analyze-perf.ts @@ -0,0 +1,385 @@ +import * as path from 'path'; +import * as http from "http"; +import { spawn } from 'child_process'; + +interface PerfEntry { + operation: string; + time: number; + file: string; + fullLine: string; +} + +interface AggregatedStats { + totalTime: number; + count: number; + files: string[]; +} + +function stripAnsi(text: string): string { + // Remove ANSI escape codes - both the ESC[ format and the literal bracket format + return text.replace(/\x1b\[[0-9;]*m/g, '').replace(/\[(\d+)m/g, ''); +} + +function parsePerfFromLines(lines: string[]): PerfEntry[] { + const entries: PerfEntry[] = []; + + // Match patterns like: "vite:load 7776.91ms [fs] /path/to/file" + // or "vite:transform 1234.56ms /path/to/file" + const timePattern = /(\d+\.\d+)ms/; + const operationPattern = /vite:(load|transform|resolve|time|import-analysis)/; + + for (let line of lines) { + // Strip ANSI color codes + line = stripAnsi(line); + + const timeMatch = line.match(timePattern); + const operationMatch = line.match(operationPattern); + + if (timeMatch && operationMatch) { + const time = parseFloat(timeMatch[1]); + const operation = operationMatch[1]; + + // Extract file path - it's usually after the timing and optional [fs]/[plugin] marker + let file = 'unknown'; + // Match file paths after [fs] or [plugin] or directly after timing + const pathMatch = line.match(/(?:\[(?:fs|plugin)\]\s+)?([/\\]?[\w/.@-]+\.[a-z]+(?:\?[^\s]*)?)/i); + if (pathMatch) { + file = pathMatch[1]; + // Normalize path separators + file = file.replace(/\\/g, '/'); + // Remove query params + file = file.replace(/\?.*$/, ''); + // Get just the filename for cleaner output + const fileName = path.basename(file); + if (file.includes('node_modules')) { + const nodeModulesMatch = file.match(/node_modules\/([^\/]+)/); + if (nodeModulesMatch) { + file = `npm:${nodeModulesMatch[1]}/${fileName}`; + } + } else if (file.includes('packages/')) { + const packagesMatch = file.match(/packages\/([^\/]+)/); + if (packagesMatch) { + file = `pkg:${packagesMatch[1]}/${fileName}`; + } + } else if (file.includes('.cache/vite/deps/')) { + const depsMatch = file.match(/deps\/([^?]+)/); + if (depsMatch) { + file = `deps:${depsMatch[1]}`; + } + } else if (file.startsWith('/')) { + // Remove leading /src/ or similar + file = file.replace(/^\/src\//, ''); + if (!file.includes('/')) { + file = fileName; + } + } else { + file = fileName; + } + } + + entries.push({ + operation, + time, + file, + fullLine: line.trim() + }); + } + } + + return entries; +} + +function analyzePerf(entries: PerfEntry[]) { + console.log('\nšŸ“Š VITE PERFORMANCE ANALYSIS\n'); + console.log('='.repeat(80)); + + // Top 20 slowest individual operations + console.log('\n🐌 TOP 20 SLOWEST OPERATIONS:\n'); + const sorted = [...entries].sort((a, b) => b.time - a.time).slice(0, 20); + sorted.forEach((entry, i) => { + console.log(`${String(i + 1).padStart(2)}. ${(entry.time / 1000).toFixed(2).padStart(6)}s [${entry.operation.padEnd(15)}] ${entry.file}`); + }); + + // Aggregate by operation type + console.log('\nāš™ļø BY OPERATION TYPE:\n'); + const byOperation = new Map(); + for (const entry of entries) { + if (!byOperation.has(entry.operation)) { + byOperation.set(entry.operation, { totalTime: 0, count: 0, files: [] }); + } + const stats = byOperation.get(entry.operation)!; + stats.totalTime += entry.time; + stats.count++; + } + + const operationsSorted = Array.from(byOperation.entries()) + .sort((a, b) => b[1].totalTime - a[1].totalTime); + + operationsSorted.forEach(([op, stats]) => { + const avgTime = stats.totalTime / stats.count; + console.log(`${op.padEnd(20)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s total (${stats.count.toString().padStart(4)} ops, ${(avgTime / 1000).toFixed(3)}s avg)`); + }); + + // Aggregate by package/category + console.log('\nšŸ“¦ BY PACKAGE/CATEGORY:\n'); + const byPackage = new Map(); + for (const entry of entries) { + let category = 'Other'; + + // Check package prefixes first + if (entry.file.startsWith('pkg:ckeditor5')) { + category = 'CKEditor Core'; + } else if (entry.file.startsWith('pkg:')) { + category = entry.file.split('/')[0]; + } else if (entry.file.startsWith('deps:ckeditor5-premium')) { + category = 'CKEditor Premium'; + } else if (entry.file.startsWith('deps:ckeditor5')) { + category = 'CKEditor Core (deps)'; + } else if (entry.file.startsWith('deps:@codemirror')) { + category = 'CodeMirror'; + } else if (entry.file.startsWith('deps:')) { + category = 'Dependencies'; + } + // Break down app source files + else if (entry.file.includes('widgets/')) { + if (entry.file.includes('type_widgets/')) { + category = 'App: Type Widgets'; + } else if (entry.file.includes('collections/')) { + category = 'App: Collections'; + } else if (entry.file.includes('ribbon/')) { + category = 'App: Ribbon'; + } else if (entry.file.includes('dialogs/')) { + category = 'App: Dialogs'; + } else if (entry.file.includes('launch_bar/')) { + category = 'App: Launch Bar'; + } else { + category = 'App: Widgets'; + } + } else if (entry.file.includes('services/')) { + category = 'App: Services'; + } else if (entry.file.includes('components/')) { + category = 'App: Components'; + } else if (entry.file.includes('menus/')) { + category = 'App: Menus'; + } else if (entry.file.includes('.css')) { + category = 'CSS'; + } else if (entry.file.match(/\.(png|jpg|jpeg|svg|gif|woff|woff2|ttf|eot)$/i)) { + category = 'Assets'; + } + + if (!byPackage.has(category)) { + byPackage.set(category, { totalTime: 0, count: 0, files: [] }); + } + const stats = byPackage.get(category)!; + stats.totalTime += entry.time; + stats.count++; + if (!stats.files.includes(entry.file)) { + stats.files.push(entry.file); + } + } + + const packagesSorted = Array.from(byPackage.entries()) + .sort((a, b) => b[1].totalTime - a[1].totalTime); + + packagesSorted.forEach(([pkg, stats]) => { + console.log(`${pkg.padEnd(30)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s (${stats.count.toString().padStart(4)} files)`); + }); + + // CKEditor breakdown + console.log('\nāœļø CKEDITOR PLUGIN BREAKDOWN:\n'); + const ckeditorEntries = entries.filter(e => + e.file.includes('ckeditor5') && + (e.file.includes('admonition') || + e.file.includes('footnotes') || + e.file.includes('math') || + e.file.includes('mermaid') || + e.file.includes('keyboard-marker')) + ); + + const byCKPlugin = new Map(); + for (const entry of ckeditorEntries) { + let plugin = 'unknown'; + if (entry.file.includes('admonition')) plugin = 'admonition'; + else if (entry.file.includes('footnotes')) plugin = 'footnotes'; + else if (entry.file.includes('math')) plugin = 'math'; + else if (entry.file.includes('mermaid')) plugin = 'mermaid'; + else if (entry.file.includes('keyboard-marker')) plugin = 'keyboard-marker'; + + if (!byCKPlugin.has(plugin)) { + byCKPlugin.set(plugin, { totalTime: 0, count: 0, files: [] }); + } + const stats = byCKPlugin.get(plugin)!; + stats.totalTime += entry.time; + stats.count++; + } + + const pluginsSorted = Array.from(byCKPlugin.entries()) + .sort((a, b) => b[1].totalTime - a[1].totalTime); + + pluginsSorted.forEach(([plugin, stats]) => { + console.log(`${plugin.padEnd(20)} ${(stats.totalTime / 1000).toFixed(1).padStart(6)}s (${stats.count} files)`); + }); + + // Summary stats + const totalTime = entries.reduce((sum, e) => sum + e.time, 0); + const totalOps = entries.length; + + console.log('\nšŸ“ˆ SUMMARY:\n'); + console.log(`Total operations: ${totalOps}`); + console.log(`Total time: ${(totalTime / 1000).toFixed(1)}s`); + console.log(`Average per op: ${(totalTime / totalOps).toFixed(1)}ms`); + console.log(`Operations > 500ms: ${entries.filter(e => e.time > 500).length}`); + console.log(`Operations > 1000ms: ${entries.filter(e => e.time > 1000).length}`); + console.log(`Operations > 3000ms: ${entries.filter(e => e.time > 3000).length}`); + + console.log('\n' + '='.repeat(80) + '\n'); +} + +// Helper to make HTTP request to trigger Vite rendering +async function makeHttpRequest(): Promise { + return new Promise((resolve) => { + console.log('\n🌐 Making request to http://localhost:8080 to trigger Vite...'); + + const req = http.get('http://localhost:8080', (res: http.IncomingMessage) => { + console.log(` āœ… Response status: ${res.statusCode}`); + console.log(` Response headers:`, res.headers); + + let body = ''; + res.on('data', (chunk: Buffer | string) => { + body += chunk; + }); + + res.on('end', () => { + console.log(` Response body length: ${body.length} bytes`); + if (body.length < 1000) { + console.log(` Response body: ${body}`); + } else { + console.log(` Response body preview (first 500 chars):\n${body.substring(0, 500)}`); + } + resolve(); + }); + }); + + req.on('error', (err: Error) => { + console.log(` āŒ Request failed: ${err.message}`); + resolve(); // Continue anyway + }); + + req.setTimeout(5000, () => { + console.log(` ā±ļø Request timed out after 5 seconds`); + req.destroy(); + resolve(); + }); + }); +} + +// Main - runs pnpm server:start and analyzes output automatically +async function runPerfAnalysis() { + console.log('šŸš€ Starting pnpm server:start with DEBUG=vite:*...\n'); + console.log('ā³ This will take about 60 seconds...\n'); + + const lines: string[] = []; + let dataCount = 0; + + return new Promise((resolve, reject) => { + const child = spawn('pnpm', ['server:start'], { + env: { + ...process.env, + DEBUG: 'vite:*', + TRILIUM_GENERAL_NOAUTHENTICATION: '1' + }, + shell: true, + cwd: path.join(__dirname, '..'), + stdio: ['ignore', 'pipe', 'pipe'] + }); + + child.stdout?.setEncoding('utf8'); + child.stderr?.setEncoding('utf8'); + + let lastActivityTime = Date.now(); + let maxTimeoutHandle: NodeJS.Timeout; + let inactivityCheckInterval: NodeJS.Timeout; + let serverStarted = false; + + const finishCollection = () => { + clearTimeout(maxTimeoutHandle); + clearInterval(inactivityCheckInterval); + child.kill('SIGTERM'); + + // Give it a moment to clean up + setTimeout(() => { + const elapsedSeconds = ((Date.now() - lastActivityTime) / 1000).toFixed(1); + console.log('\n\nāœ… Collected output, analyzing...\n'); + console.log(` Received ${dataCount} data chunks, ${lines.length} lines`); + console.log(` Last activity was ${elapsedSeconds}s ago`); + + const entries = parsePerfFromLines(lines); + console.log(`šŸ“Š Found ${entries.length} performance entries`); + + if (entries.length === 0) { + console.error('āŒ No performance data found'); + console.error(' Expected lines like: "vite:load 123.45ms [fs] /path/to/file"'); + console.error(`\n Sample lines collected (first 20):`); + lines.slice(0, 20).forEach(line => { + if (line.trim()) console.error(` "${line}"`); + }); + reject(new Error('No performance data found')); + return; + } + + analyzePerf(entries); + resolve(); + }, 1000); + }; + + child.stdout?.on('data', (data) => { + dataCount++; + lastActivityTime = Date.now(); + const text = String(data); + lines.push(...text.split('\n')); + process.stdout.write('.'); + + // Check if server has started + if (!serverStarted && text.includes('Listening on')) { + serverStarted = true; + // Wait 2 seconds for Vite to initialize, then make a request + setTimeout(async () => { + await makeHttpRequest(); + }, 2000); + } + }); + + child.stderr?.on('data', (data) => { + dataCount++; + lastActivityTime = Date.now(); + const text = String(data); + lines.push(...text.split('\n')); + process.stdout.write('.'); + }); + + // Maximum timeout of 60 seconds + maxTimeoutHandle = setTimeout(() => { + console.log('\nā±ļø Reached 60 second maximum timeout'); + finishCollection(); + }, 60000); + + // Check every second for 10 seconds of inactivity + inactivityCheckInterval = setInterval(() => { + const inactiveSeconds = (Date.now() - lastActivityTime) / 1000; + if (inactiveSeconds >= 10) { + console.log('\nā±ļø No activity for 10 seconds, finishing...'); + finishCollection(); + } + }, 1000); + + child.on('error', (error) => { + console.error(`āŒ Failed to start process: ${error.message}`); + reject(error); + }); + }); +} + +runPerfAnalysis().catch(error => { + console.error('āŒ Analysis failed:', error); + process.exit(1); +}); From b4df4aaf0d21601dfcc691aa23675aae0df8af4c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 11:06:59 +0200 Subject: [PATCH 22/24] chore(client): address requested changes --- apps/client/package.json | 1 + .../src/widgets/type_widgets/text/config.ts | 6 +-- pnpm-lock.yaml | 39 ++++++++++++++++++- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index d368e0deb8..6323ddb836 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -69,6 +69,7 @@ }, "devDependencies": { "@ckeditor/ckeditor5-inspector": "5.0.0", + "@prefresh/vite": "2.4.11", "@types/bootstrap": "5.2.10", "@types/jquery": "3.5.33", "@types/leaflet": "1.9.21", diff --git a/apps/client/src/widgets/type_widgets/text/config.ts b/apps/client/src/widgets/type_widgets/text/config.ts index 4066387fc1..29b1a02699 100644 --- a/apps/client/src/widgets/type_widgets/text/config.ts +++ b/apps/client/src/widgets/type_widgets/text/config.ts @@ -1,13 +1,11 @@ import { buildExtraCommands, type EditorConfig, getCkLocale, loadPremiumPlugins, TemplateDefinition } from "@triliumnext/ckeditor5"; import emojiDefinitionsUrl from "@triliumnext/ckeditor5/src/emoji_definitions/en.json?url"; -import { ALLOWED_PROTOCOLS, DISPLAYABLE_LOCALE_IDS, MIME_TYPE_AUTO } from "@triliumnext/commons"; -import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; +import { ALLOWED_PROTOCOLS, DISPLAYABLE_LOCALE_IDS, MIME_TYPE_AUTO, normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; import { copyTextWithToast } from "../../../services/clipboard_ext.js"; import { t } from "../../../services/i18n.js"; import { getMermaidConfig } from "../../../services/mermaid.js"; -import { getHighlightJsNameForMime } from "../../../services/mime_types.js"; -import mimeTypesService from "../../../services/mime_types.js"; +import { default as mimeTypesService, getHighlightJsNameForMime } from "../../../services/mime_types.js"; import noteAutocompleteService, { type Suggestion } from "../../../services/note_autocomplete.js"; import options from "../../../services/options.js"; import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 95c5bf529d..734a4c6de0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -311,6 +311,9 @@ importers: '@ckeditor/ckeditor5-inspector': specifier: 5.0.0 version: 5.0.0 + '@prefresh/vite': + specifier: 2.4.11 + version: 2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) '@types/bootstrap': specifier: 5.2.10 version: 5.2.10 @@ -4171,6 +4174,12 @@ packages: '@prefresh/utils@1.2.1': resolution: {integrity: sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw==} + '@prefresh/vite@2.4.11': + resolution: {integrity: sha512-/XjURQqdRiCG3NpMmWqE9kJwrg9IchIOWHzulCfqg2sRe/8oQ1g5De7xrk9lbqPIQLn7ntBkKdqWXIj4E9YXyg==} + peerDependencies: + preact: 10.28.1 + vite: '>=2.0.0' + '@prefresh/vite@2.4.8': resolution: {integrity: sha512-H7vlo9UbJInuRbZhRQrdgVqLP7qKjDoX7TgYWWwIVhEHeHO0hZ4zyicvwBrV1wX5A3EPOmArgRkUaN7cPI2VXQ==} peerDependencies: @@ -15713,6 +15722,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-font@47.3.0': dependencies: @@ -15722,6 +15733,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-footnotes@47.3.0': dependencies: @@ -15752,6 +15765,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-heading@47.3.0': dependencies: @@ -15762,6 +15777,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-highlight@47.3.0': dependencies: @@ -15770,6 +15787,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.3.0 '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-horizontal-line@47.3.0': dependencies: @@ -15779,6 +15798,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-html-embed@47.3.0': dependencies: @@ -15788,6 +15809,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-html-support@47.3.0': dependencies: @@ -15803,6 +15826,8 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-icons@47.3.0': {} @@ -15945,8 +15970,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.3.0 ckeditor5: 47.3.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-merge-fields@47.3.0': dependencies: @@ -18682,6 +18705,18 @@ snapshots: '@prefresh/utils@1.2.1': {} + '@prefresh/vite@2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': + dependencies: + '@babel/core': 7.28.0 + '@prefresh/babel-plugin': 0.5.2 + '@prefresh/core': 1.5.5(preact@10.28.1) + '@prefresh/utils': 1.2.1 + '@rollup/pluginutils': 4.2.1 + preact: 10.28.1 + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + '@prefresh/vite@2.4.8(preact@10.28.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.2)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 From 3d4b84c7c4bb439dda0569e0d25e55e13d533fe8 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 11:49:49 +0200 Subject: [PATCH 23/24] e2e(server): format file --- apps/server-e2e/playwright.config.ts | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/apps/server-e2e/playwright.config.ts b/apps/server-e2e/playwright.config.ts index 3d7da5782a..d4fe1ecd5c 100644 --- a/apps/server-e2e/playwright.config.ts +++ b/apps/server-e2e/playwright.config.ts @@ -9,36 +9,36 @@ const baseURL = process.env['BASE_URL'] || `http://127.0.0.1:${port}`; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: "src", - reporter: [["list"], ["html", { outputFolder: "test-output" }]], - outputDir: "test-output", - retries: 3, + testDir: "src", + reporter: [["list"], ["html", { outputFolder: "test-output" }]], + outputDir: "test-output", + retries: 3, - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - baseURL, - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - }, - - /* Run your local dev server before starting the tests */ - webServer: !process.env.TRILIUM_DOCKER ? { - command: 'pnpm start-prod-no-dir', - url: baseURL, - reuseExistingServer: !process.env.CI, - cwd: join(__dirname, "../server"), - env: { - TRILIUM_DATA_DIR: "spec/db", - TRILIUM_PORT: port, - TRILIUM_INTEGRATION_TEST: "memory" + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + baseURL, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', }, - timeout: 5 * 60 * 1000 - } : undefined, - projects: [ - { - name: "chromium", - use: { ...devices["Desktop Chrome"] }, - } - ] + /* Run your local dev server before starting the tests */ + webServer: !process.env.TRILIUM_DOCKER ? { + command: 'pnpm start-prod-no-dir', + url: baseURL, + reuseExistingServer: !process.env.CI, + cwd: join(__dirname, "../server"), + env: { + TRILIUM_DATA_DIR: "spec/db", + TRILIUM_PORT: port, + TRILIUM_INTEGRATION_TEST: "memory" + }, + timeout: 5 * 60 * 1000 + } : undefined, + + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + } + ] }); From 7fcd93a61b2280413b82a872bf0868d198c74f28 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 11 Jan 2026 11:55:49 +0200 Subject: [PATCH 24/24] e2e(server): fix broken e2e test after MathTex integration --- apps/server-e2e/src/note_types/text.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server-e2e/src/note_types/text.spec.ts b/apps/server-e2e/src/note_types/text.spec.ts index 052745ee25..d283ed419f 100644 --- a/apps/server-e2e/src/note_types/text.spec.ts +++ b/apps/server-e2e/src/note_types/text.spec.ts @@ -64,7 +64,7 @@ test("Displays math popup", async ({ page, context }) => { const mathForm = page.locator(".ck-math-form"); await expect(mathForm).toBeVisible(); - const input = mathForm.locator(".ck-input").first(); + const input = mathForm.locator(".ck-latex-textarea").first(); await expect(input).toBeVisible(); await expect(input).toBeEnabled(); await input.click();