Browse Source

✨ feat(plugin): enhance compilation progress tracking with multi-dimensional monitoring

- add comprehensive progress tracking including server compilation, client resources, dynamic imports and preloading
- implement weighted progress calculation (server:40%, client:30%, dynamic imports:15%, preload:15%)
- add state management for different progress types and unified update function
- optimize progress bar update logic with minimum value check to prevent exceeding 100%
- add DOMContentLoaded event handling and fallback for already loaded state
- implement monitoring for script, stylesheet and preload resources loading status
yourname 7 tháng trước cách đây
mục cha
commit
42ad76f5d9
1 tập tin đã thay đổi với 193 bổ sung90 xóa
  1. 193 90
      vite-plugin-compile-progress.js

+ 193 - 90
vite-plugin-compile-progress.js

@@ -1,93 +1,196 @@
-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', // 在 Vite 内部转换之前执行  
-        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' }, // 关键:添加 type="module"  
-                children: `  
-                  if (import.meta.hot) {  
-                    import.meta.hot.on('progress:update', (data) => {  
+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) {  
-                        const percentage = (data.processed / data.total) * 100;  
-                        bar.style.width = percentage + '%';  
-                        if (percentage >= 100) {  
-                          setTimeout(() => bar.style.display = 'none', 1000);  
-                        }  
+                      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();  
                     });  
-                  }  
-                `,  
-                injectTo: 'body'  
-              }  
-            ]  
-          }  
-        }  
-      }  
-    }  
-  }
+                      
+                    // 如果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'    
+              }    
+            ]    
+          }    
+        }    
+      }    
+    }    
+  }