Explorar o código

✨ feat(progress): 增强编译进度跟踪功能

- 添加进度状态显示面板,显示加载百分比和资源计数
- 优化进度计算算法,服务端进度权重70%,客户端资源权重30%
- 实现动态资源总数估算,提高进度准确性
- 改进进度条样式,添加完成时的淡出动画
- 增强资源监控范围,包括脚本、样式表和预加载资源
- 添加详细的资源加载日志,便于调试
- 优化HMR更新时的进度跟踪逻辑
- 修复资源计数不准确的问题
yourname hai 7 meses
pai
achega
7d996aae98
Modificáronse 1 ficheiros con 255 adicións e 194 borrados
  1. 255 194
      vite-plugin-compile-progress.js

+ 255 - 194
vite-plugin-compile-progress.js

@@ -1,209 +1,270 @@
-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 };  
+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 ease;  
+                  z-index: 9999;  
+                  opacity: 1;  
+                }  
+                #vite-progress-bar.complete {  
+                  opacity: 0;  
+                  transition: opacity 0.5s ease;  
+                }  
+                #vite-progress-status {  
+                  position: fixed;  
+                  top: 10px;  
+                  right: 10px;  
+                  background: rgba(0, 0, 0, 0.8);  
+                  color: white;  
+                  padding: 8px 12px;  
+                  border-radius: 4px;  
+                  font-size: 12px;  
+                  font-family: monospace;  
+                  z-index: 10000;  
+                  display: none;  
+                }  
+              `,  
+              injectTo: 'head'  
+            },  
+            {  
+              tag: 'div',  
+              attrs: { id: 'vite-progress-bar' },  
+              injectTo: 'body-prepend'  
+            },  
+            {  
+              tag: 'div',  
+              attrs: { id: 'vite-progress-status' },  
+              children: 'Loading...',  
+              injectTo: 'body-prepend'  
+            },  
+            {  
+              tag: 'script',  
+              attrs: { type: 'module' },  
+              children: `  
+                if (import.meta.hot) {  
+                  // 进度追踪状态  
+                  let serverProgress = 0;  
+                  let resourcesCompleted = 0;  
+                  let estimatedTotal = 0;  
+                  let isLoading = true;  
+  
+                  // DOM 元素引用  
+                  const progressBar = document.getElementById('vite-progress-bar');  
+                  const statusDisplay = document.getElementById('vite-progress-status');  
+  
+                  // 预估资源总数  
+                  function estimateResourceCount() {  
+                    const scripts = document.querySelectorAll('script[src]').length;  
+                    const links = document.querySelectorAll('link[href]').length;  
+                    const styleSheets = document.querySelectorAll('link[rel="stylesheet"]').length;  
+                    const preloadLinks = document.querySelectorAll('link[rel="preload"], link[rel="modulepreload"]').length;  
                       
                       
-                    // 更新进度条的统一函数  
-                    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;  
-
-                      console.log(clientProgress.loaded , clientProgress.total)
-                      console.log(server,client,dynamic,preload)
-                        
-                      const totalProgress = (server + client + dynamic + preload) * 100;  
-                      bar.style.width = Math.min(totalProgress, 100) + '%';  
-                        
-                      if (totalProgress >= 100) {  
-                        setTimeout(() => bar.style.display = 'none', 1000);  
-                      }  
-                    }  
+                    // 基于现有资源数量和经验值估算  
+                    const baseEstimate = scripts + links + styleSheets + preloadLinks;  
+                    const dynamicEstimate = Math.max(baseEstimate * 1.5, 10); // 至少10个资源  
                       
                       
-                    // 1. 监控服务端编译进度  
-                    import.meta.hot.on('progress:update', (data) => {  
-                      serverProgress = data.total > 0 ? data.processed / data.total : 0;  
-                      updateProgressBar();  
-                    });  
+                    return Math.floor(dynamicEstimate);  
+                  }  
+  
+                  // 更新进度条和状态显示  
+                  function updateProgress() {  
+                    if (!progressBar || !statusDisplay) return;  
+  
+                    // 服务端进度权重70%,客户端资源进度权重30%  
+                    const serverWeight = 0.7;  
+                    const clientWeight = 0.3;  
                       
                       
-                    // 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;  
-                        }  
-                      };  
-                    }  
+                    const serverPart = serverProgress * serverWeight;  
+                    const clientPart = estimatedTotal > 0 ?   
+                      (resourcesCompleted / estimatedTotal) * clientWeight : 0;  
+                      
+                    const totalProgress = Math.min((serverPart + clientPart) * 100, 100);  
                       
                       
-                    // 3. 监控预加载资源  
-                    function setupPreloadMonitoring() {  
-                      const preloadLinks = document.querySelectorAll('link[rel="preload"], link[rel="modulepreload"]');  
-                      preloadProgress.total = preloadLinks.length;  
+                    // 更新进度条  
+                    progressBar.style.width = totalProgress + '%';  
+                      
+                    // 更新状态显示  
+                    if (isLoading && totalProgress < 100) {  
+                      statusDisplay.style.display = 'block';  
+                      statusDisplay.textContent =   
+                        \`Loading... \${Math.round(totalProgress)}% (\${resourcesCompleted}/\${estimatedTotal} resources)\`;  
+                    } else if (totalProgress >= 100) {  
+                      isLoading = false;  
+                      statusDisplay.style.display = 'none';  
+                      progressBar.classList.add('complete');  
                         
                         
-                      preloadLinks.forEach(link => {  
-                        // 检查是否已经加载完成  
-                        if (link.sheet || link.complete) {  
-                          preloadProgress.loaded++;  
-                        } else {  
-                          link.addEventListener('load', () => {  
-                            preloadProgress.loaded++;  
-                            updateProgressBar();  
-                          });  
-                          link.addEventListener('error', () => {  
-                            preloadProgress.loaded++;  
-                            updateProgressBar();  
-                          });  
-                        }  
-                      });  
-                      updateProgressBar();  
+                      // 1秒后隐藏进度条  
+                      setTimeout(() => {  
+                        progressBar.style.display = 'none';  
+                      }, 1000);  
                     }  
                     }  
                       
                       
-                    // 4. 监控客户端资源加载 (通过Performance API)
-                    if (window.PerformanceObserver) {
-                      const loadedResources = new Set(); // 避免重复计数
+                    console.log(\`Progress: Server \${Math.round(serverProgress * 100)}%, Resources \${resourcesCompleted}/\${estimatedTotal}, Total \${Math.round(totalProgress)}%\`);  
+                  }  
+  
+                  // 监听服务端编译进度  
+                  import.meta.hot.on('progress:update', (data) => {  
+                    serverProgress = data.total > 0 ? data.processed / data.total : 0;  
+                    updateProgress();  
+                  });  
+  
+                  // 使用 PerformanceObserver 监控资源加载完成  
+                  if (window.PerformanceObserver) {  
+                    const completedResources = new Set();  
                       
                       
-                      const observer = new PerformanceObserver((list) => {
-                        for (const entry of list.getEntries()) {
-                          if (entry.entryType === 'resource' && entry.initiatorType === 'script' ) {
-                            if (!loadedResources.has(entry.name)) {
-                              console.log('entry.name', entry.name)
-                              loadedResources.add(entry.name);
-                              clientProgress.loaded++;
+                    const observer = new PerformanceObserver((list) => {  
+                      for (const entry of list.getEntries()) {  
+                        if (entry.entryType === 'resource') {  
+                          const isRelevantResource =   
+                            entry.initiatorType === 'script' ||  
+                            entry.initiatorType === 'link' ||  
+                            entry.initiatorType === 'css' ||  
+                            entry.name.includes('.js') ||  
+                            entry.name.includes('.css') ||  
+                            entry.name.includes('.ts');  
+                              
+                          if (isRelevantResource && !completedResources.has(entry.name)) {  
+                            completedResources.add(entry.name);  
+                            resourcesCompleted++;  
                               
                               
-                              // 动态调整总数 - 当发现新资源时增加总数
-                              if (clientProgress.loaded > clientProgress.total) {
-                                clientProgress.total = clientProgress.loaded;
-                              }
+                            // 动态调整预估总数  
+                            if (resourcesCompleted > estimatedTotal * 0.8) {  
+                              estimatedTotal = Math.max(estimatedTotal, resourcesCompleted + 5);  
+                            }  
                               
                               
-                              updateProgressBar();
-                            }
-                          }
-                        }
-                      });
-                      observer.observe({ entryTypes: ['resource'] });
-                    }
+                            console.log(\`Resource completed: \${entry.name} (type: \${entry.initiatorType})\`);  
+                            updateProgress();  
+                          }  
+                        }  
+                      }  
+                    });  
                       
                       
-                    // 初始化时统计需要加载的资源  
-                    document.addEventListener('DOMContentLoaded', () => {  
-                      const scripts = document.querySelectorAll('script[src]');  
-                      const links = document.querySelectorAll('link[href][rel="stylesheet"]');  
-                      clientProgress.total = scripts.length + links.length;  
+                    observer.observe({ entryTypes: ['resource'] });  
+                  }  
+  
+                  // 监控动态导入  
+                  const originalImport = window.import;  
+                  if (originalImport) {  
+                    window.import = async function(specifier) {  
+                      console.log(\`Dynamic import started: \${specifier}\`);  
                         
                         
-                      setupPreloadMonitoring();  
-                      updateProgressBar();  
-                    });  
+                      try {  
+                        const result = await originalImport.call(this, specifier);  
+                        console.log(\`Dynamic import completed: \${specifier}\`);  
+                        return result;  
+                      } catch (error) {  
+                        console.log(\`Dynamic import failed: \${specifier}\`);  
+                        throw error;  
+                      }  
+                    };  
+                  }  
+  
+                  // 初始化  
+                  function initialize() {  
+                    estimatedTotal = estimateResourceCount();  
+                    console.log(\`Estimated total resources: \${estimatedTotal}\`);  
+                      
+                    // 显示初始状态  
+                    if (statusDisplay) {  
+                      statusDisplay.style.display = 'block';  
+                      statusDisplay.textContent = \`Initializing... (0/\${estimatedTotal} resources)\`;  
+                    }  
                       
                       
-                    // 如果DOM已经加载完成  
-                    if (document.readyState === 'loading') {  
-                      // DOM还在加载中,等待DOMContentLoaded  
+                    updateProgress();  
+                  }  
+  
+                  // 页面加载完成后的处理  
+                  function handlePageLoad() {  
+                    // 给一些时间让所有资源完成加载  
+                    setTimeout(() => {  
+                      if (resourcesCompleted < estimatedTotal * 0.5) {  
+                        // 如果完成的资源太少,调整预估值  
+                        estimatedTotal = Math.max(resourcesCompleted + 2, 5);  
+                        console.log(\`Adjusted estimated total to: \${estimatedTotal}\`);  
+                      }  
+                      updateProgress();  
+                    }, 1000);  
+                  }  
+  
+                  // 根据文档状态初始化  
+                  if (document.readyState === 'loading') {  
+                    document.addEventListener('DOMContentLoaded', initialize);  
+                    document.addEventListener('load', handlePageLoad);  
+                  } else {  
+                    setTimeout(initialize, 0);  
+                    if (document.readyState === 'complete') {  
+                      setTimeout(handlePageLoad, 100);  
                     } else {  
                     } 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);  
+                      document.addEventListener('load', handlePageLoad);  
                     }  
                     }  
-                  }    
-                `,    
-                injectTo: 'body'    
-              }    
-            ]    
-          }    
-        }    
-      }    
-    }    
-  }
+                  }  
+  
+                  // 错误处理  
+                  window.addEventListener('error', (event) => {  
+                    console.log(\`Resource load error: \${event.filename || 'unknown'}\`);  
+                  });  
+  
+                  // HMR 更新时重置状态  
+                  import.meta.hot.on('vite:beforeUpdate', () => {  
+                    console.log('HMR update detected, maintaining progress tracking...');  
+                  });  
+                }  
+              `,  
+              injectTo: 'body'  
+            }  
+          ]  
+        }  
+      }  
+    }  
+  }  
+}