| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- export function progressTrackingPlugin() {
- let server
- const moduleStats = {
- total: 0,
- processed: 0,
- pending: new Set()
- }
-
- return {
- name: 'progress-tracking',
- apply: 'serve',
- enforce: 'pre',
- configureServer(_server) {
- server = _server
- },
- async transform(code, id) {
- if (server && id) {
- moduleStats.total++
- moduleStats.pending.add(id)
-
- server.ws.send('progress:update', {
- total: moduleStats.total,
- processed: moduleStats.processed,
- current: id
- })
-
- await server.waitForRequestsIdle(id)
-
- moduleStats.processed++
- moduleStats.pending.delete(id)
-
- server.ws.send('progress:update', {
- total: moduleStats.total,
- processed: moduleStats.processed,
- current: null
- })
- }
- },
- transformIndexHtml: {
- order: 'pre',
- handler(html, ctx) {
- return {
- html,
- tags: [
- {
- tag: 'style',
- children: `
- #vite-progress-bar {
- position: fixed;
- top: 0;
- left: 0;
- width: 0%;
- height: 3px;
- background: #646cff;
- transition: width 0.3s;
- z-index: 9999;
- }
- `,
- injectTo: 'head'
- },
- {
- tag: 'div',
- attrs: { id: 'vite-progress-bar' },
- injectTo: 'body-prepend'
- },
- {
- tag: 'script',
- attrs: { type: 'module' },
- children: `
- if (import.meta.hot) {
- // 进度跟踪状态
- let serverProgress = 0;
- let clientProgress = { loaded: 0, total: 0 };
- let dynamicImports = { loaded: 0, total: 0 };
- let preloadProgress = { loaded: 0, total: 0 };
-
- // 更新进度条的统一函数
- function updateProgressBar() {
- const bar = document.getElementById('vite-progress-bar');
- if (!bar) return;
-
- // 计算各部分进度 (服务端40%, 客户端资源30%, 动态导入15%, 预加载15%)
- const server = serverProgress * 0.4;
- const client = clientProgress.total > 0 ?
- (clientProgress.loaded / clientProgress.total) * 0.3 : 0;
- const dynamic = dynamicImports.total > 0 ?
- (dynamicImports.loaded / dynamicImports.total) * 0.15 : 0;
- const preload = preloadProgress.total > 0 ?
- (preloadProgress.loaded / preloadProgress.total) * 0.15 : 0;
-
- const totalProgress = (server + client + dynamic + preload) * 100;
- bar.style.width = Math.min(totalProgress, 100) + '%';
-
- if (totalProgress >= 100) {
- setTimeout(() => bar.style.display = 'none', 1000);
- }
- }
-
- // 1. 监控服务端编译进度
- import.meta.hot.on('progress:update', (data) => {
- serverProgress = data.total > 0 ? data.processed / data.total : 0;
- updateProgressBar();
- });
-
- // 2. 监控动态导入
- const originalImport = window.import;
- if (originalImport) {
- window.import = async function(specifier) {
- dynamicImports.total++;
- updateProgressBar();
-
- try {
- const result = await originalImport.call(this, specifier);
- dynamicImports.loaded++;
- updateProgressBar();
- return result;
- } catch (error) {
- dynamicImports.loaded++;
- updateProgressBar();
- throw error;
- }
- };
- }
-
- // 3. 监控预加载资源
- function setupPreloadMonitoring() {
- const preloadLinks = document.querySelectorAll('link[rel="preload"], link[rel="modulepreload"]');
- preloadProgress.total = preloadLinks.length;
-
- preloadLinks.forEach(link => {
- // 检查是否已经加载完成
- if (link.sheet || link.complete) {
- preloadProgress.loaded++;
- } else {
- link.addEventListener('load', () => {
- preloadProgress.loaded++;
- updateProgressBar();
- });
- link.addEventListener('error', () => {
- preloadProgress.loaded++;
- updateProgressBar();
- });
- }
- });
- updateProgressBar();
- }
-
- // 4. 监控客户端资源加载 (通过Performance API)
- if (window.PerformanceObserver) {
- const observer = new PerformanceObserver((list) => {
- for (const entry of list.getEntries()) {
- if (entry.entryType === 'resource' &&
- (entry.name.includes('.js') || entry.name.includes('.css') ||
- entry.name.includes('.ts') || entry.name.includes('.vue'))) {
- clientProgress.loaded++;
- updateProgressBar();
- }
- }
- });
- observer.observe({ entryTypes: ['resource'] });
- }
-
- // 初始化时统计需要加载的资源
- document.addEventListener('DOMContentLoaded', () => {
- const scripts = document.querySelectorAll('script[src]');
- const links = document.querySelectorAll('link[href][rel="stylesheet"]');
- clientProgress.total = scripts.length + links.length;
-
- setupPreloadMonitoring();
- updateProgressBar();
- });
-
- // 如果DOM已经加载完成
- if (document.readyState === 'loading') {
- // DOM还在加载中,等待DOMContentLoaded
- } else {
- // DOM已经加载完成,立即执行
- setTimeout(() => {
- const scripts = document.querySelectorAll('script[src]');
- const links = document.querySelectorAll('link[href][rel="stylesheet"]');
- clientProgress.total = scripts.length + links.length;
-
- setupPreloadMonitoring();
- updateProgressBar();
- }, 0);
- }
- }
- `,
- injectTo: 'body'
- }
- ]
- }
- }
- }
- }
- }
|