From d0e82cef870b0a36a29d0c94f8960fb895341d3f Mon Sep 17 00:00:00 2001 From: lingniu Date: Thu, 16 Jul 2026 02:58:18 +0800 Subject: [PATCH] perf(web): isolate Excel export worker --- vehicle-data-platform/apps/web/package.json | 2 +- .../apps/web/scripts/verify-build.mjs | 18 +++ .../web/src/v2/domain/mileageExport.test.ts | 15 +- .../apps/web/src/v2/domain/mileageExport.ts | 139 +----------------- .../web/src/v2/domain/mileageExport.worker.ts | 3 +- .../apps/web/src/v2/domain/mileageWorkbook.ts | 135 +++++++++++++++++ .../docs/frontend-production-readiness.md | 2 + 7 files changed, 173 insertions(+), 141 deletions(-) create mode 100644 vehicle-data-platform/apps/web/scripts/verify-build.mjs create mode 100644 vehicle-data-platform/apps/web/src/v2/domain/mileageWorkbook.ts diff --git a/vehicle-data-platform/apps/web/package.json b/vehicle-data-platform/apps/web/package.json index 5527ec67..d4103914 100644 --- a/vehicle-data-platform/apps/web/package.json +++ b/vehicle-data-platform/apps/web/package.json @@ -3,7 +3,7 @@ "type": "module", "scripts": { "dev": "vite --host 0.0.0.0 --port 20301", - "build": "tsc -b && vite build", + "build": "tsc -b && vite build && node scripts/verify-build.mjs", "test": "vitest run --exclude src/test/App.test.tsx", "test:legacy": "vitest run src/test/App.test.tsx", "test:all": "vitest run" diff --git a/vehicle-data-platform/apps/web/scripts/verify-build.mjs b/vehicle-data-platform/apps/web/scripts/verify-build.mjs new file mode 100644 index 00000000..e0586072 --- /dev/null +++ b/vehicle-data-platform/apps/web/scripts/verify-build.mjs @@ -0,0 +1,18 @@ +import { readdirSync, statSync } from 'node:fs'; +import { resolve } from 'node:path'; + +const assetsDirectory = resolve(process.cwd(), 'dist/assets'); +const assets = readdirSync(assetsDirectory); +const excelAssets = assets.filter((name) => /^exceljs(?:\.min)?-[\w-]+\.js$/.test(name)); +const mileageWorkers = assets.filter((name) => /^mileageExport\.worker-[\w-]+\.js$/.test(name)); + +if (excelAssets.length !== 1) { + throw new Error(`production build must contain exactly one ExcelJS asset, found ${excelAssets.length}: ${excelAssets.join(', ') || 'none'}`); +} +if (mileageWorkers.length !== 1) { + throw new Error(`production build must contain exactly one mileage export worker, found ${mileageWorkers.length}: ${mileageWorkers.join(', ') || 'none'}`); +} + +const excelBytes = statSync(resolve(assetsDirectory, excelAssets[0])).size; +const workerBytes = statSync(resolve(assetsDirectory, mileageWorkers[0])).size; +process.stdout.write(`web_build_gate=ok exceljs_assets=1 exceljs_bytes=${excelBytes} mileage_workers=1 worker_bytes=${workerBytes}\n`); diff --git a/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.test.ts b/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.test.ts index cfe23114..debb9471 100644 --- a/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.test.ts +++ b/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.test.ts @@ -1,5 +1,6 @@ import { afterEach, expect, test, vi } from 'vitest'; -import { createMileageWorkbook, downloadMileageWorkbook } from './mileageExport'; +import { downloadMileageWorkbook } from './mileageExport'; +import { createMileageWorkbook } from './mileageWorkbook'; afterEach(() => vi.unstubAllGlobals()); @@ -52,6 +53,18 @@ test('does not build or download a workbook after cancellation', async () => { }, controller.signal)).rejects.toMatchObject({ name: 'AbortError' }); }); +test('refuses a main-thread workbook fallback when module workers are unavailable', async () => { + vi.stubGlobal('Worker', undefined); + await expect(downloadMileageWorkbook({ + dateFrom: '2026-07-13', + dateTo: '2026-07-14', + dates: ['2026-07-13', '2026-07-14'], + vehicles: [], + mileageRows: [], + sources: [] + })).rejects.toThrow('当前浏览器不支持后台 Excel 导出'); +}); + test('terminates the workbook worker when an active export is cancelled', async () => { const terminate = vi.fn(); const postMessage = vi.fn(); diff --git a/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.ts b/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.ts index 68bc614b..150705b0 100644 --- a/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.ts +++ b/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.ts @@ -23,147 +23,10 @@ function throwIfAborted(signal?: AbortSignal) { if (signal?.aborted) throw abortError(); } -function excelColumn(index: number) { - let value = index; - let result = ''; - while (value > 0) { - value -= 1; - result = String.fromCharCode(65 + value % 26) + result; - value = Math.floor(value / 26); - } - return result; -} - -function localDateTime(value: Date) { - return new Intl.DateTimeFormat('zh-CN', { - year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false - }).format(value).split('/').join('-'); -} - -export async function createMileageWorkbook(input: MileageExportInput) { - const { Workbook } = await import('exceljs'); - const workbook = new Workbook(); - workbook.creator = '灵牛车辆数据中台'; - workbook.company = '灵牛科技'; - workbook.created = input.exportedAt ?? new Date(); - workbook.modified = input.exportedAt ?? new Date(); - workbook.calcProperties.fullCalcOnLoad = true; - - const sheet = workbook.addWorksheet('里程查询', { - views: [{ state: 'frozen', xSplit: 2, ySplit: 6, activeCell: 'C7', showGridLines: false }], - pageSetup: { orientation: 'landscape', fitToPage: true, fitToWidth: 1, fitToHeight: 0, paperSize: 9, margins: { left: .25, right: .25, top: .45, bottom: .45, header: .2, footer: .2 } }, - properties: { defaultRowHeight: 21 } - }); - const firstDateColumn = 3; - const lastDateColumn = firstDateColumn + input.dates.length - 1; - const totalColumn = lastDateColumn + 1; - const lastColumnLetter = excelColumn(totalColumn); - const headerRowNumber = 6; - const firstDataRow = headerRowNumber + 1; - const lastDataRow = firstDataRow + input.vehicles.length - 1; - const exportedAt = input.exportedAt ?? new Date(); - const sourceDescription = input.sources.map((source, index) => `${index + 1}. ${source.label}(${source.mileageType})`).join(' > '); - - const title = sheet.getCell('A1'); - title.value = '车辆里程查询明细'; - title.font = { name: 'Microsoft YaHei', size: 18, bold: true, color: { argb: 'FF17345C' } }; - title.alignment = { vertical: 'middle', horizontal: 'left' }; - title.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE8F1FC' } }; - for (let column = 1; column <= totalColumn; column += 1) { - const cell = sheet.getCell(1, column); - cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE8F1FC' } }; - cell.border = { bottom: { style: 'medium', color: { argb: 'FFBDD0E8' } } }; - } - sheet.getRow(1).height = 38; - - sheet.getRow(2).values = ['日期范围', `${input.dateFrom} 至 ${input.dateTo}`, '车辆范围', `${input.vehicles.length} 辆`]; - sheet.getRow(3).values = ['来源优先级', sourceDescription]; - const periodTotal = input.mileageRows.reduce((sum, row) => sum + (Number.isFinite(row.dailyMileageKm) ? row.dailyMileageKm : 0), 0); - sheet.getRow(4).values = ['区间总里程', null, '有效车辆日', `${input.mileageRows.length} 条`]; - sheet.getCell('B4').value = input.vehicles.length ? { formula: `SUM(${lastColumnLetter}${firstDataRow}:${lastColumnLetter}${lastDataRow})`, result: periodTotal } : 0; - sheet.getCell('B4').numFmt = '#,##0.0" km"'; - for (let rowNumber = 2; rowNumber <= 4; rowNumber += 1) { - const row = sheet.getRow(rowNumber); - row.height = 25; - row.eachCell({ includeEmpty: true }, (cell, columnNumber) => { - cell.font = { name: 'Microsoft YaHei', size: 10, bold: columnNumber === 1 || columnNumber === 3, color: { argb: columnNumber === 1 || columnNumber === 3 ? 'FF53657D' : 'FF213149' } }; - cell.alignment = { vertical: 'middle', horizontal: columnNumber === 1 || columnNumber === 3 ? 'left' : 'right' }; - cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: rowNumber % 2 ? 'FFF8FAFD' : 'FFF2F6FB' } }; - cell.border = { bottom: { style: 'thin', color: { argb: 'FFE1E8F1' } } }; - }); - } - sheet.getRow(5).height = 8; - - const header = sheet.getRow(headerRowNumber); - header.values = ['车牌', 'VIN', ...input.dates.map((date) => new Date(`${date}T12:00:00Z`)), '区间总里程']; - header.height = 30; - header.eachCell((cell, columnNumber) => { - const isDateHeader = columnNumber >= firstDateColumn && columnNumber <= lastDateColumn; - cell.font = { name: 'Microsoft YaHei', size: 10, bold: true, color: { argb: columnNumber === totalColumn ? 'FF1C4F91' : 'FF304158' } }; - cell.alignment = { - vertical: 'middle', - horizontal: columnNumber <= 2 ? 'left' : isDateHeader ? 'center' : 'right' - }; - cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: columnNumber === totalColumn ? 'FFDCEBFF' : 'FFEAF0F7' } }; - cell.border = { bottom: { style: 'medium', color: { argb: 'FFC3D0DF' } } }; - if (isDateHeader) cell.numFmt = 'm/d'; - }); - - const rowsByVin = new Map>(); - for (const row of input.mileageRows) { - if (!rowsByVin.has(row.vin)) rowsByVin.set(row.vin, new Map()); - rowsByVin.get(row.vin)!.set(row.date, row); - } - input.vehicles.forEach((vehicle, index) => { - const rowNumber = firstDataRow + index; - const mileageByDate = rowsByVin.get(vehicle.vin) ?? new Map(); - const dailyValues = input.dates.map((date) => mileageByDate.get(date)?.dailyMileageKm ?? null); - const total = dailyValues.reduce((sum, value) => sum + (value ?? 0), 0); - const row = sheet.getRow(rowNumber); - row.values = [vehicle.plate || '未绑定', vehicle.vin, ...dailyValues, null]; - row.height = 25; - row.eachCell({ includeEmpty: true }, (cell, columnNumber) => { - cell.font = { name: columnNumber === 2 ? 'Consolas' : 'Microsoft YaHei', size: columnNumber === 2 ? 9 : 10, color: { argb: columnNumber === totalColumn ? 'FF1D4E89' : 'FF34445A' }, bold: columnNumber === 1 || columnNumber === totalColumn }; - cell.alignment = { vertical: 'middle', horizontal: columnNumber <= 2 ? 'left' : 'right' }; - cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: index % 2 ? 'FFF9FBFD' : 'FFFFFFFF' } }; - cell.border = { bottom: { style: 'thin', color: { argb: 'FFE6ECF3' } } }; - if (columnNumber >= firstDateColumn) cell.numFmt = '#,##0.0" km"'; - }); - const dateStart = excelColumn(firstDateColumn); - const dateEnd = excelColumn(lastDateColumn); - const totalCell = sheet.getCell(rowNumber, totalColumn); - totalCell.value = { formula: `SUM(${dateStart}${rowNumber}:${dateEnd}${rowNumber})`, result: total }; - totalCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: index % 2 ? 'FFEDF5FF' : 'FFF4F8FE' } }; - row.commit(); - }); - - sheet.getColumn(1).width = 15; - sheet.getColumn(2).width = 24; - for (let column = firstDateColumn; column <= lastDateColumn; column += 1) sheet.getColumn(column).width = 12; - sheet.getColumn(totalColumn).width = 17; - if (input.vehicles.length) { - sheet.autoFilter = { from: { row: headerRowNumber, column: 1 }, to: { row: lastDataRow, column: totalColumn } }; - sheet.addConditionalFormatting({ - ref: `${excelColumn(firstDateColumn)}${firstDataRow}:${excelColumn(lastDateColumn)}${lastDataRow}`, - rules: [{ - type: 'colorScale', priority: 1, - cfvo: [{ type: 'min' }, { type: 'percentile', value: 50 }, { type: 'max' }], - color: [{ argb: 'FFFFFFFF' }, { argb: 'FFE8F2FF' }, { argb: 'FFB9D8FF' }] - }] - }); - } - sheet.headerFooter.oddFooter = '&L灵牛车辆数据中台&C第 &P / &N 页&R导出于 ' + localDateTime(exportedAt); - return workbook; -} - async function createMileageWorkbookBuffer(input: MileageExportInput, signal?: AbortSignal) { throwIfAborted(signal); if (typeof Worker === 'undefined') { - const workbook = await createMileageWorkbook(input); - throwIfAborted(signal); - const output = await workbook.xlsx.writeBuffer(); - throwIfAborted(signal); - return new Uint8Array(output as ArrayBuffer).slice().buffer; + throw new Error('当前浏览器不支持后台 Excel 导出,请升级到最新版 Chrome、Edge 或 Safari 后重试'); } return new Promise((resolve, reject) => { diff --git a/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.worker.ts b/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.worker.ts index 1d57a864..43b4ffa1 100644 --- a/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.worker.ts +++ b/vehicle-data-platform/apps/web/src/v2/domain/mileageExport.worker.ts @@ -1,4 +1,5 @@ -import { createMileageWorkbook, type MileageExportInput } from './mileageExport'; +import type { MileageExportInput } from './mileageExport'; +import { createMileageWorkbook } from './mileageWorkbook'; type MileageWorkerResponse = { ok: true; buffer: ArrayBuffer } | { ok: false; message: string }; type WorkerScope = { diff --git a/vehicle-data-platform/apps/web/src/v2/domain/mileageWorkbook.ts b/vehicle-data-platform/apps/web/src/v2/domain/mileageWorkbook.ts new file mode 100644 index 00000000..96bc4c96 --- /dev/null +++ b/vehicle-data-platform/apps/web/src/v2/domain/mileageWorkbook.ts @@ -0,0 +1,135 @@ +import type { DailyMileageRow } from '../../api/types'; +import type { MileageExportInput } from './mileageExport'; + +function excelColumn(index: number) { + let value = index; + let result = ''; + while (value > 0) { + value -= 1; + result = String.fromCharCode(65 + value % 26) + result; + value = Math.floor(value / 26); + } + return result; +} + +function localDateTime(value: Date) { + return new Intl.DateTimeFormat('zh-CN', { + year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false + }).format(value).split('/').join('-'); +} + +export async function createMileageWorkbook(input: MileageExportInput) { + const { Workbook } = await import('exceljs'); + const workbook = new Workbook(); + workbook.creator = '灵牛车辆数据中台'; + workbook.company = '灵牛科技'; + workbook.created = input.exportedAt ?? new Date(); + workbook.modified = input.exportedAt ?? new Date(); + workbook.calcProperties.fullCalcOnLoad = true; + + const sheet = workbook.addWorksheet('里程查询', { + views: [{ state: 'frozen', xSplit: 2, ySplit: 6, activeCell: 'C7', showGridLines: false }], + pageSetup: { orientation: 'landscape', fitToPage: true, fitToWidth: 1, fitToHeight: 0, paperSize: 9, margins: { left: .25, right: .25, top: .45, bottom: .45, header: .2, footer: .2 } }, + properties: { defaultRowHeight: 21 } + }); + const firstDateColumn = 3; + const lastDateColumn = firstDateColumn + input.dates.length - 1; + const totalColumn = lastDateColumn + 1; + const lastColumnLetter = excelColumn(totalColumn); + const headerRowNumber = 6; + const firstDataRow = headerRowNumber + 1; + const lastDataRow = firstDataRow + input.vehicles.length - 1; + const exportedAt = input.exportedAt ?? new Date(); + const sourceDescription = input.sources.map((source, index) => `${index + 1}. ${source.label}(${source.mileageType})`).join(' > '); + + const title = sheet.getCell('A1'); + title.value = '车辆里程查询明细'; + title.font = { name: 'Microsoft YaHei', size: 18, bold: true, color: { argb: 'FF17345C' } }; + title.alignment = { vertical: 'middle', horizontal: 'left' }; + title.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE8F1FC' } }; + for (let column = 1; column <= totalColumn; column += 1) { + const cell = sheet.getCell(1, column); + cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE8F1FC' } }; + cell.border = { bottom: { style: 'medium', color: { argb: 'FFBDD0E8' } } }; + } + sheet.getRow(1).height = 38; + + sheet.getRow(2).values = ['日期范围', `${input.dateFrom} 至 ${input.dateTo}`, '车辆范围', `${input.vehicles.length} 辆`]; + sheet.getRow(3).values = ['来源优先级', sourceDescription]; + const periodTotal = input.mileageRows.reduce((sum, row) => sum + (Number.isFinite(row.dailyMileageKm) ? row.dailyMileageKm : 0), 0); + sheet.getRow(4).values = ['区间总里程', null, '有效车辆日', `${input.mileageRows.length} 条`]; + sheet.getCell('B4').value = input.vehicles.length ? { formula: `SUM(${lastColumnLetter}${firstDataRow}:${lastColumnLetter}${lastDataRow})`, result: periodTotal } : 0; + sheet.getCell('B4').numFmt = '#,##0.0" km"'; + for (let rowNumber = 2; rowNumber <= 4; rowNumber += 1) { + const row = sheet.getRow(rowNumber); + row.height = 25; + row.eachCell({ includeEmpty: true }, (cell, columnNumber) => { + cell.font = { name: 'Microsoft YaHei', size: 10, bold: columnNumber === 1 || columnNumber === 3, color: { argb: columnNumber === 1 || columnNumber === 3 ? 'FF53657D' : 'FF213149' } }; + cell.alignment = { vertical: 'middle', horizontal: columnNumber === 1 || columnNumber === 3 ? 'left' : 'right' }; + cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: rowNumber % 2 ? 'FFF8FAFD' : 'FFF2F6FB' } }; + cell.border = { bottom: { style: 'thin', color: { argb: 'FFE1E8F1' } } }; + }); + } + sheet.getRow(5).height = 8; + + const header = sheet.getRow(headerRowNumber); + header.values = ['车牌', 'VIN', ...input.dates.map((date) => new Date(`${date}T12:00:00Z`)), '区间总里程']; + header.height = 30; + header.eachCell((cell, columnNumber) => { + const isDateHeader = columnNumber >= firstDateColumn && columnNumber <= lastDateColumn; + cell.font = { name: 'Microsoft YaHei', size: 10, bold: true, color: { argb: columnNumber === totalColumn ? 'FF1C4F91' : 'FF304158' } }; + cell.alignment = { + vertical: 'middle', + horizontal: columnNumber <= 2 ? 'left' : isDateHeader ? 'center' : 'right' + }; + cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: columnNumber === totalColumn ? 'FFDCEBFF' : 'FFEAF0F7' } }; + cell.border = { bottom: { style: 'medium', color: { argb: 'FFC3D0DF' } } }; + if (isDateHeader) cell.numFmt = 'm/d'; + }); + + const rowsByVin = new Map>(); + for (const row of input.mileageRows) { + if (!rowsByVin.has(row.vin)) rowsByVin.set(row.vin, new Map()); + rowsByVin.get(row.vin)!.set(row.date, row); + } + input.vehicles.forEach((vehicle, index) => { + const rowNumber = firstDataRow + index; + const mileageByDate = rowsByVin.get(vehicle.vin) ?? new Map(); + const dailyValues = input.dates.map((date) => mileageByDate.get(date)?.dailyMileageKm ?? null); + const total = dailyValues.reduce((sum, value) => sum + (value ?? 0), 0); + const row = sheet.getRow(rowNumber); + row.values = [vehicle.plate || '未绑定', vehicle.vin, ...dailyValues, null]; + row.height = 25; + row.eachCell({ includeEmpty: true }, (cell, columnNumber) => { + cell.font = { name: columnNumber === 2 ? 'Consolas' : 'Microsoft YaHei', size: columnNumber === 2 ? 9 : 10, color: { argb: columnNumber === totalColumn ? 'FF1D4E89' : 'FF34445A' }, bold: columnNumber === 1 || columnNumber === totalColumn }; + cell.alignment = { vertical: 'middle', horizontal: columnNumber <= 2 ? 'left' : 'right' }; + cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: index % 2 ? 'FFF9FBFD' : 'FFFFFFFF' } }; + cell.border = { bottom: { style: 'thin', color: { argb: 'FFE6ECF3' } } }; + if (columnNumber >= firstDateColumn) cell.numFmt = '#,##0.0" km"'; + }); + const dateStart = excelColumn(firstDateColumn); + const dateEnd = excelColumn(lastDateColumn); + const totalCell = sheet.getCell(rowNumber, totalColumn); + totalCell.value = { formula: `SUM(${dateStart}${rowNumber}:${dateEnd}${rowNumber})`, result: total }; + totalCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: index % 2 ? 'FFEDF5FF' : 'FFF4F8FE' } }; + row.commit(); + }); + + sheet.getColumn(1).width = 15; + sheet.getColumn(2).width = 24; + for (let column = firstDateColumn; column <= lastDateColumn; column += 1) sheet.getColumn(column).width = 12; + sheet.getColumn(totalColumn).width = 17; + if (input.vehicles.length) { + sheet.autoFilter = { from: { row: headerRowNumber, column: 1 }, to: { row: lastDataRow, column: totalColumn } }; + sheet.addConditionalFormatting({ + ref: `${excelColumn(firstDateColumn)}${firstDataRow}:${excelColumn(lastDateColumn)}${lastDataRow}`, + rules: [{ + type: 'colorScale', priority: 1, + cfvo: [{ type: 'min' }, { type: 'percentile', value: 50 }, { type: 'max' }], + color: [{ argb: 'FFFFFFFF' }, { argb: 'FFE8F2FF' }, { argb: 'FFB9D8FF' }] + }] + }); + } + sheet.headerFooter.oddFooter = '&L灵牛车辆数据中台&C第 &P / &N 页&R导出于 ' + localDateTime(exportedAt); + return workbook; +} diff --git a/vehicle-data-platform/docs/frontend-production-readiness.md b/vehicle-data-platform/docs/frontend-production-readiness.md index 97971cf2..3231a1e3 100644 --- a/vehicle-data-platform/docs/frontend-production-readiness.md +++ b/vehicle-data-platform/docs/frontend-production-readiness.md @@ -90,6 +90,8 @@ The first continuity pass only warmed Monitor, Tracks, History and Statistics in A production route-memory loop did not prove a retained application leak: after natural collection, JS heap returned to roughly its initial 31 MB range and old map documents/frames were released. It did expose an ineffective rendering hint: `content-visibility: auto` was attached to the always-visible vehicle scroll viewport instead of the 200 independently off-screen rows. The containment boundary now lives on every desktop rail row and mobile list card, paired with `contain-intrinsic-size` so skipped content keeps stable scroll geometry. This follows the CSS Containment specification's long-scroll-list use case while avoiding the documented scrollbar jump caused by missing intrinsic size: . +Excel export previously produced two independent 940 KB ExcelJS assets because the worker imported the browser download module while that module also retained a main-thread workbook fallback. Workbook construction now lives in a worker-only runtime module; unsupported legacy browsers receive an upgrade message instead of freezing the page with a main-thread build. The production output contains one ExcelJS asset, the Statistics route chunk is smaller, and `scripts/verify-build.mjs` makes exactly one ExcelJS asset plus one mileage worker a mandatory `pnpm build` gate. + The navigation and progressive-loading direction follows mature observability systems: persistent global controls, collapsible sections and loading only the content needed for the current task. Elastic documents these dashboard interaction and panel-organization patterns here: and . ### Remaining audit queue