vite-plugin-compile-progress.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. export function progressTrackingPlugin() {
  2. let server
  3. const moduleStats = {
  4. total: 0,
  5. processed: 0,
  6. pending: new Set()
  7. }
  8. return {
  9. name: 'progress-tracking',
  10. apply: 'serve',
  11. enforce: 'pre',
  12. configureServer(_server) {
  13. server = _server
  14. },
  15. async transform(code, id) {
  16. if (server && id) {
  17. moduleStats.total++
  18. moduleStats.pending.add(id)
  19. // 发送进度更新到客户端
  20. server.ws.send('progress:update', {
  21. total: moduleStats.total,
  22. processed: moduleStats.processed,
  23. current: id
  24. })
  25. // 等待依赖处理完成
  26. await server.waitForRequestsIdle(id)
  27. moduleStats.processed++
  28. moduleStats.pending.delete(id)
  29. // 发送完成状态
  30. server.ws.send('progress:update', {
  31. total: moduleStats.total,
  32. processed: moduleStats.processed,
  33. current: null
  34. })
  35. }
  36. },
  37. transformIndexHtml: {
  38. order: 'pre', // 在 Vite 内部转换之前执行
  39. handler(html, ctx) {
  40. return {
  41. html,
  42. tags: [
  43. {
  44. tag: 'style',
  45. children: `
  46. #vite-progress-bar {
  47. position: fixed;
  48. top: 0;
  49. left: 0;
  50. width: 0%;
  51. height: 3px;
  52. background: #646cff;
  53. transition: width 0.3s;
  54. z-index: 9999;
  55. }
  56. `,
  57. injectTo: 'head'
  58. },
  59. {
  60. tag: 'div',
  61. attrs: { id: 'vite-progress-bar' },
  62. injectTo: 'body-prepend'
  63. },
  64. {
  65. tag: 'script',
  66. attrs: { type: 'module' }, // 关键:添加 type="module"
  67. children: `
  68. if (import.meta.hot) {
  69. import.meta.hot.on('progress:update', (data) => {
  70. const bar = document.getElementById('vite-progress-bar');
  71. if (bar) {
  72. const percentage = (data.processed / data.total) * 100;
  73. bar.style.width = percentage + '%';
  74. if (percentage >= 100) {
  75. setTimeout(() => bar.style.display = 'none', 1000);
  76. }
  77. }
  78. });
  79. }
  80. `,
  81. injectTo: 'body'
  82. }
  83. ]
  84. }
  85. }
  86. }
  87. }
  88. }