vite-plugin-preloader 1.0.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -87
- package/dist/index.d.mts +0 -16
- package/dist/index.d.ts +0 -16
- package/dist/index.js +209 -157
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +209 -157
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2,153 +2,198 @@
|
|
|
2
2
|
|
|
3
3
|
// src/runtime.ts
|
|
4
4
|
var runtimeTemplate = `// \u{1F680} Auto-generated by vite-plugin-preloader
|
|
5
|
-
|
|
5
|
+
(function() {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
// \u{1F3AF} \u9884\u52A0\u8F7D\u914D\u7F6E\uFF08\u6784\u5EFA\u65F6\u6CE8\u5165\uFF09
|
|
9
|
+
const PRELOAD_ROUTES = __PRELOAD_ROUTES__
|
|
10
|
+
const PRELOAD_OPTIONS = __PRELOAD_OPTIONS__
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
class PreloaderManager {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.preloadedRoutes = new Set()
|
|
15
|
+
this.isPreloading = false
|
|
16
|
+
this.stats = {
|
|
17
|
+
total: 0, completed: 0, failed: 0, startTime: 0, endTime: 0
|
|
18
|
+
}
|
|
19
|
+
this.statusElement = null
|
|
20
|
+
}
|
|
13
21
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
completed: number
|
|
17
|
-
failed: number
|
|
18
|
-
startTime: number
|
|
19
|
-
endTime: number
|
|
20
|
-
}
|
|
22
|
+
async start() {
|
|
23
|
+
if (this.isPreloading) return
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
this.isPreloading = true
|
|
26
|
+
this.stats = {
|
|
27
|
+
total: PRELOAD_ROUTES.length,
|
|
28
|
+
completed: 0, failed: 0,
|
|
29
|
+
startTime: Date.now(), endTime: 0
|
|
30
|
+
}
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
private stats = ref({
|
|
30
|
-
total: 0, completed: 0, failed: 0, startTime: 0, endTime: 0
|
|
31
|
-
})
|
|
32
|
+
if (PRELOAD_OPTIONS.debug) {
|
|
33
|
+
console.log(\`\u{1F680} [\u9884\u52A0\u8F7D] \u5F00\u59CB\u9884\u52A0\u8F7D \${PRELOAD_ROUTES.length} \u4E2A\u9875\u9762\`)
|
|
34
|
+
}
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
// \u663E\u793A\u72B6\u6001\u6307\u793A\u5668
|
|
37
|
+
this.showStatus()
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
const sortedRoutes = [...PRELOAD_ROUTES].sort((a, b) => a.priority - b.priority)
|
|
40
|
+
|
|
41
|
+
for (const route of sortedRoutes) {
|
|
42
|
+
await this.preloadSingle(route)
|
|
43
|
+
this.updateStatus()
|
|
44
|
+
await this.sleep(100)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.stats.endTime = Date.now()
|
|
48
|
+
this.isPreloading = false
|
|
49
|
+
|
|
50
|
+
if (PRELOAD_OPTIONS.debug) {
|
|
51
|
+
console.log(\`\u{1F389} [\u9884\u52A0\u8F7D] \u5B8C\u6210! \u8017\u65F6 \${this.stats.endTime - this.stats.startTime}ms\`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// \u9690\u85CF\u72B6\u6001\u6307\u793A\u5668
|
|
55
|
+
this.hideStatus()
|
|
41
56
|
}
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
async preloadSingle(route) {
|
|
59
|
+
if (this.preloadedRoutes.has(route.path)) return
|
|
44
60
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
try {
|
|
62
|
+
const startTime = Date.now()
|
|
63
|
+
let componentPath = route.component
|
|
64
|
+
|
|
65
|
+
// \u5728\u5F00\u53D1\u73AF\u5883\u4E2D\uFF0CVite \u4F1A\u5904\u7406\u6A21\u5757\u89E3\u6790
|
|
66
|
+
// \u6211\u4EEC\u9700\u8981\u4F7F\u7528\u6B63\u786E\u7684\u6A21\u5757 ID
|
|
67
|
+
if (componentPath.startsWith('@/')) {
|
|
68
|
+
// \u5BF9\u4E8E Vite\uFF0C@ \u522B\u540D\u5E94\u8BE5\u5728\u6784\u5EFA\u65F6\u5C31\u88AB\u89E3\u6790
|
|
69
|
+
// \u4F46\u5728\u8FD0\u884C\u65F6\u6211\u4EEC\u9700\u8981\u4F7F\u7528\u5B9E\u9645\u7684\u8DEF\u5F84
|
|
70
|
+
componentPath = componentPath.replace('@/', '/src/')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// \u786E\u4FDD\u8DEF\u5F84\u4EE5 / \u5F00\u5934\uFF08\u76F8\u5BF9\u4E8E\u9879\u76EE\u6839\u76EE\u5F55\uFF09
|
|
74
|
+
if (!componentPath.startsWith('/') && !componentPath.startsWith('./')) {
|
|
75
|
+
componentPath = '/' + componentPath
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (PRELOAD_OPTIONS.debug) {
|
|
79
|
+
console.log(\`\u{1F50D} [\u9884\u52A0\u8F7D] \u5C1D\u8BD5\u52A0\u8F7D: \${componentPath}\`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const module = await import(/* @vite-ignore */ componentPath)
|
|
83
|
+
const loadTime = Date.now() - startTime
|
|
84
|
+
|
|
85
|
+
this.preloadedRoutes.add(route.path)
|
|
86
|
+
this.stats.completed++
|
|
87
|
+
|
|
88
|
+
if (PRELOAD_OPTIONS.debug) {
|
|
89
|
+
console.log(\`\u2705 [\u9884\u52A0\u8F7D] \${route.path} (\${loadTime}ms) - \${route.reason}\`)
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
this.stats.failed++
|
|
93
|
+
if (PRELOAD_OPTIONS.debug) {
|
|
94
|
+
console.error(\`\u274C [\u9884\u52A0\u8F7D] \${route.path} \u5931\u8D25:\`, error)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
50
97
|
}
|
|
51
98
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
console.log(\`\u{1F389} [\u9884\u52A0\u8F7D] \u5B8C\u6210! \u8017\u65F6 \${this.stats.value.endTime - this.stats.value.startTime}ms\`)
|
|
56
|
-
}
|
|
99
|
+
showStatus() {
|
|
100
|
+
if (!PRELOAD_OPTIONS.showStatus || !document.body) return
|
|
57
101
|
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
// \u6DFB\u52A0\u6837\u5F0F
|
|
103
|
+
if (!document.getElementById('preloader-styles')) {
|
|
104
|
+
const style = document.createElement('style')
|
|
105
|
+
style.id = 'preloader-styles'
|
|
106
|
+
const position = PRELOAD_OPTIONS.statusPosition.replace('-', ': 20px; ') + ': 20px;'
|
|
107
|
+
style.textContent = \`
|
|
108
|
+
.preloader-status {
|
|
109
|
+
position: fixed; \${position}
|
|
110
|
+
background: rgba(0,0,0,0.8); color: white; padding: 8px 16px;
|
|
111
|
+
border-radius: 6px; font-size: 12px; z-index: 9999;
|
|
112
|
+
pointer-events: none; font-family: system-ui;
|
|
113
|
+
transition: opacity 0.3s ease;
|
|
114
|
+
}
|
|
115
|
+
.preloader-status.fade-out {
|
|
116
|
+
opacity: 0;
|
|
117
|
+
}
|
|
118
|
+
\`
|
|
119
|
+
document.head.appendChild(style)
|
|
120
|
+
}
|
|
60
121
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.preloadedRoutes.add(route.path)
|
|
67
|
-
this.stats.value.completed++
|
|
68
|
-
console.log(\`\u2705 [\u9884\u52A0\u8F7D] \${route.path} (\${loadTime}ms) - \${route.reason}\`)
|
|
69
|
-
} catch (error) {
|
|
70
|
-
this.stats.value.failed++
|
|
71
|
-
console.error(\`\u274C [\u9884\u52A0\u8F7D] \${route.path} \u5931\u8D25:\`, error)
|
|
122
|
+
// \u521B\u5EFA\u72B6\u6001\u5143\u7D20
|
|
123
|
+
this.statusElement = document.createElement('div')
|
|
124
|
+
this.statusElement.className = 'preloader-status'
|
|
125
|
+
this.updateStatus()
|
|
126
|
+
document.body.appendChild(this.statusElement)
|
|
72
127
|
}
|
|
73
|
-
}
|
|
74
128
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
129
|
+
updateStatus() {
|
|
130
|
+
if (!this.statusElement) return
|
|
131
|
+
this.statusElement.textContent = \`\u{1F504} \u6B63\u5728\u4F18\u5316\u9875\u9762... \${this.stats.completed}/\${this.stats.total}\`
|
|
132
|
+
}
|
|
78
133
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
134
|
+
hideStatus() {
|
|
135
|
+
if (!this.statusElement) return
|
|
136
|
+
this.statusElement.classList.add('fade-out')
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
if (this.statusElement && this.statusElement.parentNode) {
|
|
139
|
+
this.statusElement.parentNode.removeChild(this.statusElement)
|
|
140
|
+
}
|
|
141
|
+
}, 300)
|
|
142
|
+
}
|
|
82
143
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
...this.stats.value,
|
|
86
|
-
preloadedPaths: Array.from(this.preloadedRoutes),
|
|
87
|
-
isPreloading: this.isPreloading.value
|
|
144
|
+
sleep(ms) {
|
|
145
|
+
return new Promise(resolve => setTimeout(resolve, ms))
|
|
88
146
|
}
|
|
89
|
-
}
|
|
90
147
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
name: 'PreloadStatus',
|
|
95
|
-
setup() {
|
|
96
|
-
onMounted(() => {
|
|
97
|
-
if (!document.getElementById('preloader-styles')) {
|
|
98
|
-
const style = document.createElement('style')
|
|
99
|
-
style.id = 'preloader-styles'
|
|
100
|
-
const position = PRELOAD_OPTIONS.statusPosition.replace('-', ': 20px; ') + ': 20px;'
|
|
101
|
-
style.textContent = \`
|
|
102
|
-
.preloader-status {
|
|
103
|
-
position: fixed; \${position}
|
|
104
|
-
background: rgba(0,0,0,0.8); color: white; padding: 8px 16px;
|
|
105
|
-
border-radius: 6px; font-size: 12px; z-index: 9999;
|
|
106
|
-
pointer-events: none; font-family: system-ui;
|
|
107
|
-
}
|
|
108
|
-
\`
|
|
109
|
-
document.head.appendChild(style)
|
|
110
|
-
}
|
|
111
|
-
})
|
|
148
|
+
isPreloaded(path) {
|
|
149
|
+
return this.preloadedRoutes.has(path)
|
|
150
|
+
}
|
|
112
151
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
'\u{1F504} \u6B63\u5728\u4F18\u5316\u9875\u9762... ',
|
|
119
|
-
\`\${self.stats.value.completed}/\${self.stats.value.total}\`
|
|
120
|
-
])
|
|
121
|
-
}
|
|
152
|
+
getStats() {
|
|
153
|
+
return {
|
|
154
|
+
...this.stats,
|
|
155
|
+
preloadedPaths: Array.from(this.preloadedRoutes),
|
|
156
|
+
isPreloading: this.isPreloading
|
|
122
157
|
}
|
|
123
|
-
}
|
|
158
|
+
}
|
|
124
159
|
}
|
|
125
|
-
}
|
|
126
160
|
|
|
127
|
-
// \u{1F680} \u5168\u5C40\u5B9E\u4F8B
|
|
128
|
-
const preloader = new PreloaderManager()
|
|
161
|
+
// \u{1F680} \u5168\u5C40\u5B9E\u4F8B
|
|
162
|
+
const preloader = new PreloaderManager()
|
|
163
|
+
|
|
164
|
+
// \u{1F6E0}\uFE0F \u5F00\u53D1\u73AF\u5883\u8C03\u8BD5\u5DE5\u5177
|
|
165
|
+
if (PRELOAD_OPTIONS.debug) {
|
|
166
|
+
window.preloaderDebug = {
|
|
167
|
+
stats: () => preloader.getStats(),
|
|
168
|
+
restart: () => preloader.start(),
|
|
169
|
+
check: (path) => preloader.isPreloaded(path),
|
|
170
|
+
help: () => console.log('\u{1F6E0}\uFE0F \u9884\u52A0\u8F7D\u8C03\u8BD5: stats() | restart() | check(path)')
|
|
171
|
+
}
|
|
172
|
+
console.log('\u{1F6E0}\uFE0F \u9884\u52A0\u8F7D\u8C03\u8BD5\u5DE5\u5177: window.preloaderDebug')
|
|
173
|
+
}
|
|
129
174
|
|
|
130
|
-
// \u{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
175
|
+
// \u{1F680} \u81EA\u52A8\u542F\u52A8 - \u7B49\u5F85 DOM \u52A0\u8F7D\u5B8C\u6210
|
|
176
|
+
function autoStart() {
|
|
177
|
+
if (document.readyState === 'loading') {
|
|
178
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
179
|
+
setTimeout(() => preloader.start(), PRELOAD_OPTIONS.delay)
|
|
180
|
+
})
|
|
181
|
+
} else {
|
|
182
|
+
setTimeout(() => preloader.start(), PRELOAD_OPTIONS.delay)
|
|
183
|
+
}
|
|
137
184
|
}
|
|
138
|
-
console.log('\u{1F6E0}\uFE0F \u9884\u52A0\u8F7D\u8C03\u8BD5\u5DE5\u5177: window.preloaderDebug')
|
|
139
|
-
}
|
|
140
185
|
|
|
141
|
-
// \
|
|
142
|
-
|
|
143
|
-
start: () => preloader.start(),
|
|
144
|
-
isPreloaded: (path) => preloader.isPreloaded(path),
|
|
145
|
-
StatusComponent: preloader.createStatusComponent()
|
|
146
|
-
})
|
|
186
|
+
// \u7ACB\u5373\u6267\u884C\u81EA\u52A8\u542F\u52A8
|
|
187
|
+
autoStart()
|
|
147
188
|
|
|
148
|
-
// \
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
189
|
+
// \u5BFC\u51FA\u5230\u5168\u5C40\uFF08\u53EF\u9009\u4F7F\u7528\uFF09
|
|
190
|
+
window.usePreloader = () => ({
|
|
191
|
+
start: () => preloader.start(),
|
|
192
|
+
isPreloaded: (path) => preloader.isPreloaded(path),
|
|
193
|
+
getStats: () => preloader.getStats()
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
})();`;
|
|
152
197
|
|
|
153
198
|
// src/generator.ts
|
|
154
199
|
var CodeGenerator = class {
|
|
@@ -172,7 +217,7 @@ var CodeGenerator = class {
|
|
|
172
217
|
const componentPath2 = this.inferComponentPath(route);
|
|
173
218
|
return {
|
|
174
219
|
path: route,
|
|
175
|
-
component:
|
|
220
|
+
component: componentPath2,
|
|
176
221
|
reason: "\u81EA\u52A8\u63A8\u65AD\u7684\u9884\u52A0\u8F7D\u9875\u9762",
|
|
177
222
|
priority: 2
|
|
178
223
|
};
|
|
@@ -180,7 +225,7 @@ var CodeGenerator = class {
|
|
|
180
225
|
const componentPath = route.component || this.inferComponentPath(route.path);
|
|
181
226
|
return {
|
|
182
227
|
path: route.path,
|
|
183
|
-
component:
|
|
228
|
+
component: componentPath,
|
|
184
229
|
reason: route.reason || "\u7528\u6237\u914D\u7F6E\u7684\u9884\u52A0\u8F7D\u9875\u9762",
|
|
185
230
|
priority: route.priority || 2
|
|
186
231
|
};
|
|
@@ -190,70 +235,77 @@ var CodeGenerator = class {
|
|
|
190
235
|
* 处理选项配置
|
|
191
236
|
*/
|
|
192
237
|
processOptions() {
|
|
238
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
193
239
|
return {
|
|
194
|
-
delay: this.options.delay
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
240
|
+
delay: this.options.delay ?? 2e3,
|
|
241
|
+
// 默认2秒
|
|
242
|
+
showStatus: this.options.showStatus ?? true,
|
|
243
|
+
// 默认显示状态
|
|
244
|
+
statusPosition: this.options.statusPosition ?? "bottom-right",
|
|
245
|
+
// 默认右下角
|
|
246
|
+
debug: this.options.debug ?? isDev
|
|
247
|
+
// 开发环境默认开启调试,生产环境默认关闭
|
|
198
248
|
};
|
|
199
249
|
}
|
|
200
250
|
/**
|
|
201
|
-
* 推断组件路径
|
|
251
|
+
* 推断组件路径 - 使用 Vite 别名格式
|
|
202
252
|
*/
|
|
203
253
|
inferComponentPath(routePath) {
|
|
204
|
-
const cleanPath = routePath.replace(/^\//, "")
|
|
205
|
-
|
|
254
|
+
const cleanPath = routePath.replace(/^\//, "");
|
|
255
|
+
if (cleanPath.startsWith("demo/")) {
|
|
256
|
+
return `@/views/${cleanPath}/index.vue`;
|
|
257
|
+
}
|
|
258
|
+
const pathSegments = cleanPath.split("/");
|
|
259
|
+
return `@/views/${pathSegments.join("/")}/index.vue`;
|
|
206
260
|
}
|
|
207
261
|
/**
|
|
208
|
-
*
|
|
262
|
+
* 生成注入到 HTML 头部的脚本
|
|
209
263
|
*/
|
|
210
264
|
generateHtmlInject() {
|
|
211
|
-
|
|
212
|
-
|
|
265
|
+
return `<script type="module">
|
|
266
|
+
${this.generateRuntime()}
|
|
267
|
+
</script>`;
|
|
213
268
|
}
|
|
214
269
|
};
|
|
215
270
|
|
|
216
271
|
// src/index.ts
|
|
217
|
-
var VIRTUAL_MODULE_ID = "virtual:preloader";
|
|
218
|
-
var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
|
|
219
272
|
function preloaderPlugin(options) {
|
|
220
273
|
let generator;
|
|
274
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
275
|
+
const finalOptions = {
|
|
276
|
+
debug: isDev,
|
|
277
|
+
// 开发环境默认开启调试
|
|
278
|
+
delay: 2e3,
|
|
279
|
+
// 默认2秒
|
|
280
|
+
showStatus: true,
|
|
281
|
+
// 默认显示状态
|
|
282
|
+
statusPosition: "bottom-right",
|
|
283
|
+
// 默认右下角
|
|
284
|
+
...options
|
|
285
|
+
// 用户配置覆盖默认配置
|
|
286
|
+
};
|
|
221
287
|
return {
|
|
222
288
|
name: "vite-plugin-preloader",
|
|
223
289
|
// 🎯 设置插件执行顺序
|
|
224
290
|
enforce: "post",
|
|
225
291
|
configResolved() {
|
|
226
|
-
generator = new CodeGenerator(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
resolveId(id) {
|
|
230
|
-
if (id === VIRTUAL_MODULE_ID) {
|
|
231
|
-
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
232
|
-
}
|
|
233
|
-
return null;
|
|
234
|
-
},
|
|
235
|
-
load(id) {
|
|
236
|
-
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
|
|
237
|
-
return generator.generateRuntime();
|
|
292
|
+
generator = new CodeGenerator(finalOptions);
|
|
293
|
+
if (finalOptions.debug) {
|
|
294
|
+
console.log(`\u{1F680} [\u9884\u52A0\u8F7D\u63D2\u4EF6] \u5DF2\u542F\u7528\uFF0C\u9884\u52A0\u8F7D ${finalOptions.routes.length} \u4E2A\u9875\u9762\uFF0C\u8BE6\u60C5\u8BF7\u67E5\u770B\u6D4F\u89C8\u5668\u63A7\u5236\u53F0`);
|
|
238
295
|
}
|
|
239
|
-
return null;
|
|
240
296
|
},
|
|
241
|
-
// 🎨 HTML
|
|
297
|
+
// 🎨 HTML 转换 - 直接注入脚本到 HTML
|
|
242
298
|
transformIndexHtml(html) {
|
|
243
299
|
const inject = generator.generateHtmlInject();
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
'<div id="app">',
|
|
247
|
-
`<div id="app">
|
|
248
|
-
${inject}`
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
return html;
|
|
300
|
+
return html.replace("</head>", `${inject}
|
|
301
|
+
</head>`);
|
|
252
302
|
},
|
|
253
303
|
// 🔥 HMR 支持
|
|
254
304
|
handleHotUpdate(ctx) {
|
|
255
305
|
if (ctx.file.includes("vite.config")) {
|
|
256
|
-
|
|
306
|
+
if (finalOptions.debug) {
|
|
307
|
+
console.log("\u{1F504} [\u9884\u52A0\u8F7D\u63D2\u4EF6] \u914D\u7F6E\u5DF2\u66F4\u65B0");
|
|
308
|
+
}
|
|
257
309
|
ctx.server.ws.send({
|
|
258
310
|
type: "full-reload"
|
|
259
311
|
});
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime.ts","../src/generator.ts","../src/index.ts"],"sourcesContent":["// ============================================================================\r\n// ⚡ src/runtime.ts - 运行时代码模板(字符串)\r\n// ============================================================================\r\n\r\nexport const runtimeTemplate = `// 🚀 Auto-generated by vite-plugin-preloader\r\nimport { ref, defineComponent, h, onMounted } from 'vue'\r\n\r\ninterface PreloadRoute {\r\n path: string\r\n component: () => Promise<any>\r\n reason: string\r\n priority: number\r\n}\r\n\r\ninterface PreloadStats {\r\n total: number\r\n completed: number\r\n failed: number\r\n startTime: number\r\n endTime: number\r\n}\r\n\r\n// 🎯 预加载配置(构建时注入)\r\nconst PRELOAD_ROUTES = __PRELOAD_ROUTES__\r\nconst PRELOAD_OPTIONS = __PRELOAD_OPTIONS__\r\n\r\nclass PreloaderManager {\r\n private preloadedRoutes = new Set()\r\n private isPreloading = ref(false)\r\n private stats = ref({\r\n total: 0, completed: 0, failed: 0, startTime: 0, endTime: 0\r\n })\r\n\r\n async start() {\r\n if (this.isPreloading.value) return\r\n\r\n this.isPreloading.value = true\r\n this.stats.value = {\r\n total: PRELOAD_ROUTES.length,\r\n completed: 0, failed: 0,\r\n startTime: Date.now(), endTime: 0\r\n }\r\n\r\n console.log(\\`🚀 [预加载] 开始预加载 \\${PRELOAD_ROUTES.length} 个页面\\`)\r\n\r\n const sortedRoutes = [...PRELOAD_ROUTES].sort((a, b) => a.priority - b.priority)\r\n \r\n for (const route of sortedRoutes) {\r\n await this.preloadSingle(route)\r\n await this.sleep(100)\r\n }\r\n\r\n this.stats.value.endTime = Date.now()\r\n this.isPreloading.value = false\r\n \r\n console.log(\\`🎉 [预加载] 完成! 耗时 \\${this.stats.value.endTime - this.stats.value.startTime}ms\\`)\r\n }\r\n\r\n async preloadSingle(route) {\r\n if (this.preloadedRoutes.has(route.path)) return\r\n\r\n try {\r\n const startTime = Date.now()\r\n await route.component()\r\n const loadTime = Date.now() - startTime\r\n \r\n this.preloadedRoutes.add(route.path)\r\n this.stats.value.completed++\r\n console.log(\\`✅ [预加载] \\${route.path} (\\${loadTime}ms) - \\${route.reason}\\`)\r\n } catch (error) {\r\n this.stats.value.failed++\r\n console.error(\\`❌ [预加载] \\${route.path} 失败:\\`, error)\r\n }\r\n }\r\n\r\n sleep(ms) {\r\n return new Promise(resolve => setTimeout(resolve, ms))\r\n }\r\n\r\n isPreloaded(path) {\r\n return this.preloadedRoutes.has(path)\r\n }\r\n\r\n getStats() {\r\n return {\r\n ...this.stats.value,\r\n preloadedPaths: Array.from(this.preloadedRoutes),\r\n isPreloading: this.isPreloading.value\r\n }\r\n }\r\n\r\n createStatusComponent() {\r\n const self = this\r\n return defineComponent({\r\n name: 'PreloadStatus',\r\n setup() {\r\n onMounted(() => {\r\n if (!document.getElementById('preloader-styles')) {\r\n const style = document.createElement('style')\r\n style.id = 'preloader-styles'\r\n const position = PRELOAD_OPTIONS.statusPosition.replace('-', ': 20px; ') + ': 20px;'\r\n style.textContent = \\`\r\n .preloader-status {\r\n position: fixed; \\${position}\r\n background: rgba(0,0,0,0.8); color: white; padding: 8px 16px;\r\n border-radius: 6px; font-size: 12px; z-index: 9999;\r\n pointer-events: none; font-family: system-ui;\r\n }\r\n \\`\r\n document.head.appendChild(style)\r\n }\r\n })\r\n\r\n return () => {\r\n if (!self.isPreloading.value || !import.meta.env.DEV || !PRELOAD_OPTIONS.showStatus) {\r\n return null\r\n }\r\n return h('div', { class: 'preloader-status' }, [\r\n '🔄 正在优化页面... ',\r\n \\`\\${self.stats.value.completed}/\\${self.stats.value.total}\\`\r\n ])\r\n }\r\n }\r\n })\r\n }\r\n}\r\n\r\n// 🚀 全局实例\r\nconst preloader = new PreloaderManager()\r\n\r\n// 🛠️ 开发环境调试工具\r\nif (import.meta.env.DEV && PRELOAD_OPTIONS.debug) {\r\n window.preloaderDebug = {\r\n stats: () => preloader.getStats(),\r\n restart: () => preloader.start(),\r\n check: (path) => preloader.isPreloaded(path),\r\n help: () => console.log('🛠️ 预加载调试: stats() | restart() | check(path)')\r\n }\r\n console.log('🛠️ 预加载调试工具: window.preloaderDebug')\r\n}\r\n\r\n// 🎯 导出\r\nexport const usePreloader = () => ({\r\n start: () => preloader.start(),\r\n isPreloaded: (path) => preloader.isPreloaded(path),\r\n StatusComponent: preloader.createStatusComponent()\r\n})\r\n\r\n// 🚀 自动启动\r\nif (typeof window !== 'undefined') {\r\n setTimeout(() => preloader.start(), PRELOAD_OPTIONS.delay || 2000)\r\n}`","// ============================================================================\r\n// 🛠️ src/generator.ts - 代码生成器\r\n// ============================================================================\r\n\r\nimport type { PreloaderOptions } from './types'\r\nimport { runtimeTemplate } from './runtime'\r\n\r\nexport class CodeGenerator {\r\n constructor(private options: PreloaderOptions) {}\r\n\r\n /**\r\n * 生成运行时代码\r\n */\r\n generateRuntime(): string {\r\n const routes = this.processRoutes()\r\n const options = this.processOptions()\r\n\r\n return runtimeTemplate\r\n .replace('__PRELOAD_ROUTES__', JSON.stringify(routes, null, 2))\r\n .replace('__PRELOAD_OPTIONS__', JSON.stringify(options, null, 2))\r\n }\r\n\r\n /**\r\n * 处理路由配置\r\n */\r\n private processRoutes(): any[] {\r\n return this.options.routes.map(route => {\r\n // 处理字符串输入\r\n if (typeof route === 'string') {\r\n const componentPath = this.inferComponentPath(route)\r\n return {\r\n path: route,\r\n component: `() => import('${componentPath}')`,\r\n reason: '自动推断的预加载页面',\r\n priority: 2\r\n }\r\n }\r\n \r\n // 处理对象输入\r\n const componentPath = route.component || this.inferComponentPath(route.path)\r\n return {\r\n path: route.path,\r\n component: `() => import('${componentPath}')`,\r\n reason: route.reason || '用户配置的预加载页面',\r\n priority: route.priority || 2\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * 处理选项配置\r\n */\r\n private processOptions() {\r\n return {\r\n delay: this.options.delay || 2000,\r\n showStatus: this.options.showStatus !== false,\r\n statusPosition: this.options.statusPosition || 'bottom-right',\r\n debug: this.options.debug || false\r\n }\r\n }\r\n\r\n /**\r\n * 推断组件路径\r\n */\r\n private inferComponentPath(routePath: string): string {\r\n const cleanPath = routePath.replace(/^\\//, '').replace(/\\//g, '-')\r\n return `@/views/${cleanPath}/index.vue`\r\n }\r\n\r\n /**\r\n * 生成HTML注入代码\r\n */\r\n generateHtmlInject(): string {\r\n if (this.options.showStatus === false) return ''\r\n \r\n return '<preloader-status></preloader-status>'\r\n }\r\n}","// ============================================================================\r\n// 🚀 src/index.ts - 主插件文件\r\n// ============================================================================\r\n\r\nimport type { Plugin } from 'vite'\r\nimport type { PreloaderOptions } from './types'\r\nimport { CodeGenerator } from './generator'\r\n\r\nconst VIRTUAL_MODULE_ID = 'virtual:preloader'\r\nconst RESOLVED_VIRTUAL_MODULE_ID = '\\0' + VIRTUAL_MODULE_ID\r\n\r\nexport default function preloaderPlugin(options: PreloaderOptions): Plugin {\r\n let generator: CodeGenerator\r\n\r\n return {\r\n name: 'vite-plugin-preloader',\r\n \r\n // 🎯 设置插件执行顺序\r\n enforce: 'post',\r\n \r\n configResolved() {\r\n generator = new CodeGenerator(options)\r\n console.log(`🚀 预加载插件已启用,配置了 ${options.routes.length} 个路由`)\r\n },\r\n\r\n resolveId(id) {\r\n if (id === VIRTUAL_MODULE_ID) {\r\n return RESOLVED_VIRTUAL_MODULE_ID\r\n }\r\n return null // 🔧 修复:明确返回 null\r\n },\r\n\r\n load(id) {\r\n if (id === RESOLVED_VIRTUAL_MODULE_ID) {\r\n return generator.generateRuntime()\r\n }\r\n return null // 🔧 修复:明确返回 null\r\n },\r\n\r\n // 🎨 HTML 转换(修复类型错误)\r\n transformIndexHtml(html) {\r\n const inject = generator.generateHtmlInject()\r\n if (inject) {\r\n return html.replace(\r\n '<div id=\"app\">',\r\n `<div id=\"app\">\\n ${inject}`\r\n )\r\n }\r\n return html // 🔧 修复:确保总是返回 html\r\n },\r\n\r\n // 🔥 HMR 支持\r\n handleHotUpdate(ctx) {\r\n if (ctx.file.includes('vite.config')) {\r\n console.log('🔄 预加载配置已更新')\r\n ctx.server.ws.send({\r\n type: 'full-reload'\r\n })\r\n return []\r\n }\r\n return undefined // 🔧 修复:明确返回 undefined\r\n }\r\n }\r\n}\r\n\r\n// 命名导出,支持多种导入方式\r\nexport { type PreloaderOptions, type PreloadRoute } from './types'"],"mappings":"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","names":["componentPath"]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts","../src/generator.ts","../src/index.ts"],"sourcesContent":["// ============================================================================\r\n// ⚡ src/runtime.ts - 运行时代码模板(字符串)\r\n// ============================================================================\r\nexport const runtimeTemplate = `// 🚀 Auto-generated by vite-plugin-preloader\r\n(function() {\r\n 'use strict';\r\n \r\n // 🎯 预加载配置(构建时注入)\r\n const PRELOAD_ROUTES = __PRELOAD_ROUTES__\r\n const PRELOAD_OPTIONS = __PRELOAD_OPTIONS__\r\n\r\n class PreloaderManager {\r\n constructor() {\r\n this.preloadedRoutes = new Set()\r\n this.isPreloading = false\r\n this.stats = {\r\n total: 0, completed: 0, failed: 0, startTime: 0, endTime: 0\r\n }\r\n this.statusElement = null\r\n }\r\n\r\n async start() {\r\n if (this.isPreloading) return\r\n\r\n this.isPreloading = true\r\n this.stats = {\r\n total: PRELOAD_ROUTES.length,\r\n completed: 0, failed: 0,\r\n startTime: Date.now(), endTime: 0\r\n }\r\n\r\n if (PRELOAD_OPTIONS.debug) {\r\n console.log(\\`🚀 [预加载] 开始预加载 \\${PRELOAD_ROUTES.length} 个页面\\`)\r\n }\r\n\r\n // 显示状态指示器\r\n this.showStatus()\r\n\r\n const sortedRoutes = [...PRELOAD_ROUTES].sort((a, b) => a.priority - b.priority)\r\n \r\n for (const route of sortedRoutes) {\r\n await this.preloadSingle(route)\r\n this.updateStatus()\r\n await this.sleep(100)\r\n }\r\n\r\n this.stats.endTime = Date.now()\r\n this.isPreloading = false\r\n \r\n if (PRELOAD_OPTIONS.debug) {\r\n console.log(\\`🎉 [预加载] 完成! 耗时 \\${this.stats.endTime - this.stats.startTime}ms\\`)\r\n }\r\n\r\n // 隐藏状态指示器\r\n this.hideStatus()\r\n }\r\n\r\n async preloadSingle(route) {\r\n if (this.preloadedRoutes.has(route.path)) return\r\n\r\n try {\r\n const startTime = Date.now()\r\n let componentPath = route.component\r\n \r\n // 在开发环境中,Vite 会处理模块解析\r\n // 我们需要使用正确的模块 ID\r\n if (componentPath.startsWith('@/')) {\r\n // 对于 Vite,@ 别名应该在构建时就被解析\r\n // 但在运行时我们需要使用实际的路径\r\n componentPath = componentPath.replace('@/', '/src/')\r\n }\r\n \r\n // 确保路径以 / 开头(相对于项目根目录)\r\n if (!componentPath.startsWith('/') && !componentPath.startsWith('./')) {\r\n componentPath = '/' + componentPath\r\n }\r\n \r\n if (PRELOAD_OPTIONS.debug) {\r\n console.log(\\`🔍 [预加载] 尝试加载: \\${componentPath}\\`)\r\n }\r\n \r\n const module = await import(/* @vite-ignore */ componentPath)\r\n const loadTime = Date.now() - startTime\r\n \r\n this.preloadedRoutes.add(route.path)\r\n this.stats.completed++\r\n \r\n if (PRELOAD_OPTIONS.debug) {\r\n console.log(\\`✅ [预加载] \\${route.path} (\\${loadTime}ms) - \\${route.reason}\\`)\r\n }\r\n } catch (error) {\r\n this.stats.failed++\r\n if (PRELOAD_OPTIONS.debug) {\r\n console.error(\\`❌ [预加载] \\${route.path} 失败:\\`, error)\r\n }\r\n }\r\n }\r\n\r\n showStatus() {\r\n if (!PRELOAD_OPTIONS.showStatus || !document.body) return\r\n\r\n // 添加样式\r\n if (!document.getElementById('preloader-styles')) {\r\n const style = document.createElement('style')\r\n style.id = 'preloader-styles'\r\n const position = PRELOAD_OPTIONS.statusPosition.replace('-', ': 20px; ') + ': 20px;'\r\n style.textContent = \\`\r\n .preloader-status {\r\n position: fixed; \\${position}\r\n background: rgba(0,0,0,0.8); color: white; padding: 8px 16px;\r\n border-radius: 6px; font-size: 12px; z-index: 9999;\r\n pointer-events: none; font-family: system-ui;\r\n transition: opacity 0.3s ease;\r\n }\r\n .preloader-status.fade-out {\r\n opacity: 0;\r\n }\r\n \\`\r\n document.head.appendChild(style)\r\n }\r\n\r\n // 创建状态元素\r\n this.statusElement = document.createElement('div')\r\n this.statusElement.className = 'preloader-status'\r\n this.updateStatus()\r\n document.body.appendChild(this.statusElement)\r\n }\r\n\r\n updateStatus() {\r\n if (!this.statusElement) return\r\n this.statusElement.textContent = \\`🔄 正在优化页面... \\${this.stats.completed}/\\${this.stats.total}\\`\r\n }\r\n\r\n hideStatus() {\r\n if (!this.statusElement) return\r\n this.statusElement.classList.add('fade-out')\r\n setTimeout(() => {\r\n if (this.statusElement && this.statusElement.parentNode) {\r\n this.statusElement.parentNode.removeChild(this.statusElement)\r\n }\r\n }, 300)\r\n }\r\n\r\n sleep(ms) {\r\n return new Promise(resolve => setTimeout(resolve, ms))\r\n }\r\n\r\n isPreloaded(path) {\r\n return this.preloadedRoutes.has(path)\r\n }\r\n\r\n getStats() {\r\n return {\r\n ...this.stats,\r\n preloadedPaths: Array.from(this.preloadedRoutes),\r\n isPreloading: this.isPreloading\r\n }\r\n }\r\n }\r\n\r\n // 🚀 全局实例\r\n const preloader = new PreloaderManager()\r\n\r\n // 🛠️ 开发环境调试工具\r\n if (PRELOAD_OPTIONS.debug) {\r\n window.preloaderDebug = {\r\n stats: () => preloader.getStats(),\r\n restart: () => preloader.start(),\r\n check: (path) => preloader.isPreloaded(path),\r\n help: () => console.log('🛠️ 预加载调试: stats() | restart() | check(path)')\r\n }\r\n console.log('🛠️ 预加载调试工具: window.preloaderDebug')\r\n }\r\n\r\n // 🚀 自动启动 - 等待 DOM 加载完成\r\n function autoStart() {\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', () => {\r\n setTimeout(() => preloader.start(), PRELOAD_OPTIONS.delay)\r\n })\r\n } else {\r\n setTimeout(() => preloader.start(), PRELOAD_OPTIONS.delay)\r\n }\r\n }\r\n\r\n // 立即执行自动启动\r\n autoStart()\r\n\r\n // 导出到全局(可选使用)\r\n window.usePreloader = () => ({\r\n start: () => preloader.start(),\r\n isPreloaded: (path) => preloader.isPreloaded(path),\r\n getStats: () => preloader.getStats()\r\n })\r\n\r\n})();`","// ============================================================================\r\n// 🛠️ src/generator.ts - 代码生成器\r\n// ============================================================================\r\nimport type { PreloaderOptions } from './types'\r\nimport { runtimeTemplate } from './runtime'\r\n\r\nexport class CodeGenerator {\r\n constructor(private options: PreloaderOptions) {}\r\n\r\n /**\r\n * 生成运行时代码\r\n */\r\n generateRuntime(): string {\r\n const routes = this.processRoutes();\r\n const options = this.processOptions();\r\n\r\n return runtimeTemplate\r\n .replace(\"__PRELOAD_ROUTES__\", JSON.stringify(routes, null, 2))\r\n .replace(\"__PRELOAD_OPTIONS__\", JSON.stringify(options, null, 2));\r\n }\r\n\r\n /**\r\n * 处理路由配置\r\n */\r\n private processRoutes(): any[] {\r\n return this.options.routes.map((route) => {\r\n // 处理字符串输入\r\n if (typeof route === \"string\") {\r\n const componentPath = this.inferComponentPath(route);\r\n return {\r\n path: route,\r\n component: componentPath,\r\n reason: \"自动推断的预加载页面\",\r\n priority: 2,\r\n };\r\n }\r\n\r\n // 处理对象输入\r\n const componentPath =\r\n route.component || this.inferComponentPath(route.path);\r\n return {\r\n path: route.path,\r\n component: componentPath,\r\n reason: route.reason || \"用户配置的预加载页面\",\r\n priority: route.priority || 2,\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * 处理选项配置\r\n */\r\n private processOptions() {\r\n // 智能默认配置\r\n const isDev = process.env.NODE_ENV !== \"production\";\r\n\r\n return {\r\n delay: this.options.delay ?? 2000, // 默认2秒\r\n showStatus: this.options.showStatus ?? true, // 默认显示状态\r\n statusPosition: this.options.statusPosition ?? \"bottom-right\", // 默认右下角\r\n debug: this.options.debug ?? isDev, // 开发环境默认开启调试,生产环境默认关闭\r\n };\r\n }\r\n\r\n /**\r\n * 推断组件路径 - 使用 Vite 别名格式\r\n */\r\n private inferComponentPath(routePath: string): string {\r\n const cleanPath = routePath.replace(/^\\//, \"\");\r\n\r\n // 直接使用 @ 别名,这在 Vite 构建后会被正确解析\r\n if (cleanPath.startsWith(\"demo/\")) {\r\n // /demo/13-calendar -> @/views/demo/13-calendar/index.vue\r\n return `@/views/${cleanPath}/index.vue`;\r\n }\r\n\r\n // 其他路径的处理\r\n const pathSegments = cleanPath.split(\"/\");\r\n return `@/views/${pathSegments.join(\"/\")}/index.vue`;\r\n }\r\n\r\n /**\r\n * 生成注入到 HTML 头部的脚本\r\n */\r\n generateHtmlInject(): string {\r\n return `<script type=\"module\">\r\n${this.generateRuntime()}\r\n</script>`;\r\n }\r\n}","import type { Plugin } from 'vite'\r\nimport type { PreloaderOptions } from './types'\r\nimport { CodeGenerator } from './generator'\r\n\r\nexport default function preloaderPlugin(options: PreloaderOptions): Plugin {\r\n let generator: CodeGenerator\r\n const isDev = process.env.NODE_ENV !== 'production'\r\n \r\n // 智能默认配置\r\n const finalOptions = {\r\n debug: isDev, // 开发环境默认开启调试\r\n delay: 2000, // 默认2秒\r\n showStatus: true, // 默认显示状态\r\n statusPosition: 'bottom-right' as const, // 默认右下角\r\n ...options // 用户配置覆盖默认配置\r\n }\r\n\r\n return {\r\n name: 'vite-plugin-preloader',\r\n \r\n // 🎯 设置插件执行顺序\r\n enforce: 'post',\r\n \r\n configResolved() {\r\n generator = new CodeGenerator(finalOptions)\r\n \r\n if (finalOptions.debug) {\r\n console.log(`🚀 [预加载插件] 已启用,预加载 ${finalOptions.routes.length} 个页面,详情请查看浏览器控制台`)\r\n }\r\n },\r\n\r\n // 🎨 HTML 转换 - 直接注入脚本到 HTML\r\n transformIndexHtml(html) {\r\n const inject = generator.generateHtmlInject()\r\n \r\n // 注入到 head 标签末尾\r\n return html.replace('</head>', `${inject}\\n</head>`)\r\n },\r\n\r\n // 🔥 HMR 支持\r\n handleHotUpdate(ctx) {\r\n if (ctx.file.includes('vite.config')) {\r\n if (finalOptions.debug) {\r\n console.log('🔄 [预加载插件] 配置已更新')\r\n }\r\n ctx.server.ws.send({\r\n type: 'full-reload'\r\n })\r\n return []\r\n }\r\n return undefined\r\n }\r\n }\r\n}\r\n\r\n// 命名导出,支持多种导入方式\r\nexport { type PreloaderOptions, type PreloadRoute } from './types'"],"mappings":"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","names":["componentPath"]}
|