vite-plugin-build-version-file 0.1.18 → 0.2.0
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 +170 -24
- package/dist/client.cjs +32 -109
- package/dist/client.d.cts +7 -3
- package/dist/client.d.ts +7 -3
- package/dist/client.mjs +30 -108
- package/dist/index.cjs +250 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +250 -1
- package/package.json +9 -10
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,216 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { existsSync, readFileSync } from "fs";
|
|
3
3
|
import { dirname, join, resolve } from "path";
|
|
4
|
+
|
|
5
|
+
// src/loading.html
|
|
6
|
+
var loading_default = `<!doctype html>
|
|
7
|
+
<html lang="zh-CN">
|
|
8
|
+
<head>
|
|
9
|
+
<meta charset="UTF-8" />
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
11
|
+
<title>Loading</title>
|
|
12
|
+
<style>
|
|
13
|
+
html,
|
|
14
|
+
body {
|
|
15
|
+
margin: 0;
|
|
16
|
+
height: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#vite-build-version-loading {
|
|
20
|
+
position: fixed;
|
|
21
|
+
inset: 0;
|
|
22
|
+
z-index: 2147483647;
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
gap: 16px;
|
|
28
|
+
color: #333333;
|
|
29
|
+
font: 14px/1.5 sans-serif;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#vite-build-version-loading .spinner {
|
|
33
|
+
width: 36px;
|
|
34
|
+
height: 36px;
|
|
35
|
+
border: 3px solid rgba(0, 0, 0, 0.15);
|
|
36
|
+
border-top-color: rgba(0, 0, 0, 0.6);
|
|
37
|
+
border-radius: 50%;
|
|
38
|
+
animation: vite-build-version-loading 0.8s linear infinite;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@keyframes vite-build-version-loading {
|
|
42
|
+
to {
|
|
43
|
+
transform: rotate(360deg);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
</style>
|
|
47
|
+
</head>
|
|
48
|
+
<body>
|
|
49
|
+
<div id="vite-build-version-loading">
|
|
50
|
+
<div class="spinner"></div>
|
|
51
|
+
</div>
|
|
52
|
+
<script>
|
|
53
|
+
;(function () {
|
|
54
|
+
var IFRAME_ID = 'vite-plugin-build-version-file-cache-iframe'
|
|
55
|
+
var IFRAME_TIMEOUT = 5000
|
|
56
|
+
var DEFAULT_REFRESH_TIME = 5
|
|
57
|
+
var DEFAULT_CLEAR_TIMES = 2
|
|
58
|
+
|
|
59
|
+
var params = new URLSearchParams(window.location.search)
|
|
60
|
+
// \u53C2\u6570\u540D\u968F\u673A\u751F\u6210\uFF0Cloading \u9875\u6309\u503C\u89E3\u6790\uFF1A\u4EFB\u4F55\u503C\u662F JSON \u7684\u53C2\u6570\u90FD\u89C6\u4E3A\u6E05\u7406\u914D\u7F6E\u3002
|
|
61
|
+
var config = (function () {
|
|
62
|
+
var entries = Array.from(params.entries())
|
|
63
|
+
|
|
64
|
+
for (var i = 0; i < entries.length; i++) {
|
|
65
|
+
try {
|
|
66
|
+
var value = JSON.parse(entries[i][1])
|
|
67
|
+
|
|
68
|
+
if (value && typeof value === 'object' && Array.isArray(value.urls)) {
|
|
69
|
+
return value
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// \u975E JSON \u53C2\u6570\uFF08\u4F8B\u5982\u81EA\u5B9A\u4E49 query\uFF09\u76F4\u63A5\u8DF3\u8FC7\u3002
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {}
|
|
77
|
+
})()
|
|
78
|
+
// \u9ED8\u8BA4\u628A\u672C\u9875\u9762\u6240\u5728\u76EE\u5F55\u5F53\u4F5C\u5E94\u7528\u6839\u8DEF\u5F84\u3002
|
|
79
|
+
var directoryUrl = new URL('.', window.location.href).href
|
|
80
|
+
var urls = Array.isArray(config.urls)
|
|
81
|
+
? config.urls.filter(Boolean)
|
|
82
|
+
: []
|
|
83
|
+
var time = Number(config.time)
|
|
84
|
+
var times = Math.floor(Number(config.times))
|
|
85
|
+
var redirectUrl = config.redirectUrl || directoryUrl
|
|
86
|
+
var title = config.title
|
|
87
|
+
|
|
88
|
+
if (urls.length === 0) {
|
|
89
|
+
urls = [directoryUrl, new URL('index.html', directoryUrl).href]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!Number.isFinite(time) || time <= 0) {
|
|
93
|
+
time = DEFAULT_REFRESH_TIME
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!Number.isFinite(times) || times < 1) {
|
|
97
|
+
times = DEFAULT_CLEAR_TIMES
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (title) {
|
|
101
|
+
var titleElement = document.createElement('div')
|
|
102
|
+
titleElement.textContent = title
|
|
103
|
+
document.getElementById('vite-build-version-loading').appendChild(titleElement)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function createCacheBustKey() {
|
|
107
|
+
// \u53C2\u6570\u540D\u968F\u673A\uFF0C\u907F\u514D\u670D\u52A1\u5668\u6216 CDN \u9488\u5BF9\u56FA\u5B9A\u53C2\u6570\u540D\uFF08\u5982 _\u3001t\uFF09\u505A\u7F13\u5B58\u5904\u7406\u3002
|
|
108
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 8)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function createCacheBustedUrl(url) {
|
|
112
|
+
var targetUrl = new URL(url, window.location.href)
|
|
113
|
+
var hash = targetUrl.hash
|
|
114
|
+
|
|
115
|
+
// hash \u4E0D\u53C2\u4E0E HTTP \u8BF7\u6C42\uFF0C\u5148\u4FDD\u7559\u4E1A\u52A1\u8DEF\u7531\uFF0C\u518D\u5411\u771F\u5B9E\u8BF7\u6C42 URL \u5199\u5165\u7F13\u5B58\u6233\u3002
|
|
116
|
+
targetUrl.hash = ''
|
|
117
|
+
targetUrl.searchParams.set(
|
|
118
|
+
createCacheBustKey(),
|
|
119
|
+
Date.now() + '-' + Math.random().toString(36).slice(2)
|
|
120
|
+
)
|
|
121
|
+
targetUrl.hash = hash
|
|
122
|
+
|
|
123
|
+
return targetUrl.href
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function loadIframe(url) {
|
|
127
|
+
return new Promise(function (resolve) {
|
|
128
|
+
// \u540C\u4E00\u9875\u9762\u53EA\u4FDD\u7559\u4E00\u4E2A\u7F13\u5B58\u5237\u65B0 iframe\uFF0C\u521B\u5EFA\u524D\u5148\u9500\u6BC1\u65E7\u5B9E\u4F8B\u3002
|
|
129
|
+
var existing = document.getElementById(IFRAME_ID)
|
|
130
|
+
|
|
131
|
+
if (existing) {
|
|
132
|
+
existing.remove()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
var iframe = document.createElement('iframe')
|
|
136
|
+
var frameTimeout = 0
|
|
137
|
+
var completed = false
|
|
138
|
+
|
|
139
|
+
function complete() {
|
|
140
|
+
if (completed) {
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
completed = true
|
|
145
|
+
window.clearTimeout(frameTimeout)
|
|
146
|
+
resolve()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
frameTimeout = window.setTimeout(complete, IFRAME_TIMEOUT)
|
|
150
|
+
|
|
151
|
+
iframe.hidden = true
|
|
152
|
+
iframe.id = IFRAME_ID
|
|
153
|
+
iframe.addEventListener('load', complete, { once: true })
|
|
154
|
+
iframe.addEventListener('error', complete, { once: true })
|
|
155
|
+
iframe.src = url
|
|
156
|
+
document.documentElement.appendChild(iframe)
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function clearTargetUrlCache(url) {
|
|
161
|
+
var targetUrl = new URL(url, window.location.href).href
|
|
162
|
+
console.info('[vite-plugin-build-version] Clear cache for ' + targetUrl)
|
|
163
|
+
|
|
164
|
+
// \u968F\u673A URL \u7ED5\u8FC7\u65E7\u7F13\u5B58\uFF0C\u539F URL \u4F7F\u7528 reload \u6A21\u5F0F\u5237\u65B0\u5BF9\u5E94\u7F13\u5B58\u6761\u76EE\u3002
|
|
165
|
+
// \u7B49\u5F85\u54CD\u5E94\u4F53\u5B8C\u6574\u8BFB\u53D6\uFF0C\u907F\u514D\u540E\u7EED\u8DF3\u8F6C\u63D0\u524D\u53D6\u6D88\u7F13\u5B58\u5237\u65B0\u8BF7\u6C42\u3002
|
|
166
|
+
return Promise.allSettled([
|
|
167
|
+
fetch(createCacheBustedUrl(targetUrl), { cache: 'no-store' }).then(
|
|
168
|
+
function (response) {
|
|
169
|
+
return response.arrayBuffer()
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
fetch(targetUrl, { cache: 'reload' }).then(function (response) {
|
|
173
|
+
return response.arrayBuffer()
|
|
174
|
+
})
|
|
175
|
+
]).then(function () {
|
|
176
|
+
// iframe \u518D\u89E6\u53D1\u4E00\u6B21\u9875\u9762\u8D44\u6E90\u52A0\u8F7D\uFF0C\u8D85\u65F6\u6216\u5931\u8D25\u7531\u5916\u5C42\u7EE7\u7EED\u5904\u7406\u540E\u7EED URL\u3002
|
|
177
|
+
return loadIframe(createCacheBustedUrl(targetUrl))
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
var refreshTimeoutId = 0
|
|
182
|
+
var clearAllDone = (async function () {
|
|
183
|
+
// \u6574\u5957\u6E05\u7406\u64CD\u4F5C\u6309 times \u91CD\u590D\u6267\u884C\uFF0C\u9ED8\u8BA4 2 \u6B21\u3002
|
|
184
|
+
for (var round = 0; round < times; round++) {
|
|
185
|
+
for (var i = 0; i < urls.length; i++) {
|
|
186
|
+
try {
|
|
187
|
+
await clearTargetUrlCache(urls[i])
|
|
188
|
+
} catch (error) {
|
|
189
|
+
// \u5355\u7EC4\u5931\u8D25\u4E0D\u963B\u65AD\u540E\u7EED URL\uFF0C\u4FDD\u8BC1\u914D\u7F6E\u7684\u68C0\u6D4B\u7EC4\u90FD\u80FD\u6267\u884C\u3002
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
})()
|
|
194
|
+
var limitReached = new Promise(function (resolve) {
|
|
195
|
+
// \u5230\u8FBE\u603B\u7B49\u5F85\u65F6\u9650\u540E\u76F4\u63A5\u8DF3\u8F6C\uFF0C\u4E0D\u53D7\u7F13\u5B58\u8BF7\u6C42\u72B6\u6001\u5F71\u54CD\u3002
|
|
196
|
+
refreshTimeoutId = window.setTimeout(resolve, time * 1000)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
Promise.race([clearAllDone, limitReached]).then(function () {
|
|
200
|
+
window.clearTimeout(refreshTimeoutId)
|
|
201
|
+
// \u6700\u7EC8\u8DF3\u8F6C\u539F\u6837\u4F7F\u7528\u76EE\u6807\u5730\u5740\uFF0C\u4E0D\u9644\u52A0\u7F13\u5B58\u6233\u3002
|
|
202
|
+
window.location.replace(redirectUrl)
|
|
203
|
+
})
|
|
204
|
+
})()
|
|
205
|
+
</script>
|
|
206
|
+
</body>
|
|
207
|
+
</html>
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
// src/index.ts
|
|
4
211
|
var PLUGIN_NAME = "vite-plugin-build-version-file";
|
|
5
212
|
var DEFAULT_FILENAME = "version.json";
|
|
213
|
+
var DEFAULT_LOADING_PAGE = "loading";
|
|
6
214
|
var DEFAULT_GLOBAL_NAME = "__VERSION__";
|
|
7
215
|
var DEFAULT_DEFINE_NAME = "__VERSION__";
|
|
8
216
|
var DEFAULT_TIME_ZONE = "Asia/Shanghai";
|
|
@@ -40,6 +248,16 @@ function normalizeFileName(filename) {
|
|
|
40
248
|
}
|
|
41
249
|
return normalized;
|
|
42
250
|
}
|
|
251
|
+
function normalizeLoadingPage(loadingPage) {
|
|
252
|
+
if (loadingPage === false) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
const normalized = (loadingPage ?? DEFAULT_LOADING_PAGE).trim().replace(/^\/+/, "");
|
|
256
|
+
if (!normalized) {
|
|
257
|
+
throw new Error(`[${PLUGIN_NAME}] "loadingPage" cannot be empty.`);
|
|
258
|
+
}
|
|
259
|
+
return normalized.endsWith(".html") ? normalized : `${normalized}.html`;
|
|
260
|
+
}
|
|
43
261
|
function normalizeGlobalName(globalName) {
|
|
44
262
|
if (!globalName.trim()) {
|
|
45
263
|
throw new Error(`[${PLUGIN_NAME}] "globalName" cannot be empty.`);
|
|
@@ -142,6 +360,13 @@ function toRequestPath(base, fileName) {
|
|
|
142
360
|
const baseWithoutTrailingSlash = withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
143
361
|
return `${baseWithoutTrailingSlash}/${fileName}`.replace(/\/{2,}/g, "/");
|
|
144
362
|
}
|
|
363
|
+
function resolveNuxtFileName(config, fileName) {
|
|
364
|
+
if (config.appType !== "custom" || config.build.copyPublicDir !== false) {
|
|
365
|
+
return fileName;
|
|
366
|
+
}
|
|
367
|
+
const assetDir = normalizeFileName(config.build.assetsDir);
|
|
368
|
+
return assetDir === "." || fileName.startsWith(`${assetDir}/`) ? fileName : `${assetDir}/${fileName}`;
|
|
369
|
+
}
|
|
145
370
|
function resolveProjectRoot(root) {
|
|
146
371
|
return root ? resolve(process.cwd(), root) : process.cwd();
|
|
147
372
|
}
|
|
@@ -168,6 +393,7 @@ function createPayload(options, context, data, timeZone, packageInfo = {}) {
|
|
|
168
393
|
}
|
|
169
394
|
function buildVersionPlugin(options = {}) {
|
|
170
395
|
const fileName = normalizeFileName(options.filename ?? DEFAULT_FILENAME);
|
|
396
|
+
const loadingPage = normalizeLoadingPage(options.loadingPage);
|
|
171
397
|
const globalName = normalizeGlobalName(
|
|
172
398
|
options.globalName ?? DEFAULT_GLOBAL_NAME
|
|
173
399
|
);
|
|
@@ -179,6 +405,8 @@ function buildVersionPlugin(options = {}) {
|
|
|
179
405
|
const data = normalizeData(options.data);
|
|
180
406
|
let payload;
|
|
181
407
|
let skipBundleEmit = false;
|
|
408
|
+
let bundleFileName = fileName;
|
|
409
|
+
let bundleLoadingFileName = loadingPage;
|
|
182
410
|
const transformHtml = (code, ..._args) => {
|
|
183
411
|
if (!injectToHtml || !payload) {
|
|
184
412
|
return void 0;
|
|
@@ -213,6 +441,10 @@ function buildVersionPlugin(options = {}) {
|
|
|
213
441
|
},
|
|
214
442
|
configResolved(config) {
|
|
215
443
|
skipBundleEmit = Boolean(config.build.ssr) && !config.build.ssrEmitAssets;
|
|
444
|
+
bundleFileName = resolveNuxtFileName(config, fileName);
|
|
445
|
+
if (loadingPage) {
|
|
446
|
+
bundleLoadingFileName = resolveNuxtFileName(config, loadingPage);
|
|
447
|
+
}
|
|
216
448
|
if (payload) {
|
|
217
449
|
return;
|
|
218
450
|
}
|
|
@@ -225,11 +457,21 @@ function buildVersionPlugin(options = {}) {
|
|
|
225
457
|
},
|
|
226
458
|
configureServer(server) {
|
|
227
459
|
const requestPath = toRequestPath(server.config.base, fileName);
|
|
460
|
+
const loadingRequestPath = loadingPage ? toRequestPath(server.config.base, loadingPage) : void 0;
|
|
228
461
|
server.middlewares.use((request, response, next) => {
|
|
229
462
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
230
463
|
next();
|
|
231
464
|
return;
|
|
232
465
|
}
|
|
466
|
+
if (loadingRequestPath && parsePathname(request.url) === loadingRequestPath) {
|
|
467
|
+
response.statusCode = 200;
|
|
468
|
+
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
469
|
+
response.setHeader("Cache-Control", "no-cache");
|
|
470
|
+
response.end(
|
|
471
|
+
request.method === "HEAD" ? void 0 : loading_default
|
|
472
|
+
);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
233
475
|
if (parsePathname(request.url) !== requestPath || !payload) {
|
|
234
476
|
next();
|
|
235
477
|
return;
|
|
@@ -260,9 +502,16 @@ function buildVersionPlugin(options = {}) {
|
|
|
260
502
|
}
|
|
261
503
|
this.emitFile({
|
|
262
504
|
type: "asset",
|
|
263
|
-
fileName,
|
|
505
|
+
fileName: bundleFileName,
|
|
264
506
|
source: serializePayload(payload)
|
|
265
507
|
});
|
|
508
|
+
if (bundleLoadingFileName) {
|
|
509
|
+
this.emitFile({
|
|
510
|
+
type: "asset",
|
|
511
|
+
fileName: bundleLoadingFileName,
|
|
512
|
+
source: loading_default
|
|
513
|
+
});
|
|
514
|
+
}
|
|
266
515
|
if (options.log) {
|
|
267
516
|
console.log(options.log(payload));
|
|
268
517
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-build-version-file",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A Vite plugin that emits version.json and injects version metadata into HTML.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,14 +25,6 @@
|
|
|
25
25
|
"README.md",
|
|
26
26
|
"LICENSE"
|
|
27
27
|
],
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "tsup --config tsup.config.ts",
|
|
30
|
-
"build:fixture": "pnpm build && vite build --config debug/fixture-app/vite.config.ts",
|
|
31
|
-
"build:vitepress": "pnpm build && vitepress build debug/vitepress-app",
|
|
32
|
-
"dev:fixture": "pnpm build && vite --config debug/fixture-app/vite.config.ts",
|
|
33
|
-
"dev:vitepress": "pnpm build && vitepress dev debug/vitepress-app",
|
|
34
|
-
"prepublishOnly": "pnpm build:fixture"
|
|
35
|
-
},
|
|
36
28
|
"keywords": [
|
|
37
29
|
"vite",
|
|
38
30
|
"vite-plugin",
|
|
@@ -58,5 +50,12 @@
|
|
|
58
50
|
"vite": "^5.0.0",
|
|
59
51
|
"vitepress": "^1.6.4",
|
|
60
52
|
"vue": "^3.4.0"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup --config tsup.config.ts",
|
|
56
|
+
"build:fixture": "pnpm build && vite build --config debug/fixture-app/vite.config.ts",
|
|
57
|
+
"build:vitepress": "pnpm build && vitepress build debug/vitepress-app",
|
|
58
|
+
"dev:fixture": "pnpm build && vite --config debug/fixture-app/vite.config.ts",
|
|
59
|
+
"dev:vitepress": "pnpm build && vitepress dev debug/vitepress-app"
|
|
61
60
|
}
|
|
62
|
-
}
|
|
61
|
+
}
|