vite-add-cdn-script 0.0.8 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +5 -5
- package/dist/index.js +436 -225
- package/dist/index.umd.cjs +5 -5
- package/package.json +9 -4
package/README.md
CHANGED
@@ -77,13 +77,13 @@ export default defineConfig({
|
|
77
77
|
|
78
78
|
options
|
79
79
|
|
80
|
-
| 参数 | 解析 | 类型 | 默认值
|
81
|
-
| ------------ | ------------------- | --------------------------- |
|
82
|
-
| customScript | 自定义 cdn 脚本 | { [*key*: string]: string } | 无
|
83
|
-
| retryTimes |
|
80
|
+
| 参数 | 解析 | 类型 | 默认值 |
|
81
|
+
| ------------ | ------------------- | --------------------------- | --------------------------------------- |
|
82
|
+
| customScript | 自定义 cdn 脚本 | { [*key*: string]: string } | 无 |
|
83
|
+
| retryTimes | 换源重试次数 | number | defaultCdns.length - 1 |
|
84
84
|
| defaultCdns | 默认使用 cdn 的顺序 | string[] | ["jsdelivr", "unpkg"] |
|
85
85
|
|
86
86
|
## 注意事项
|
87
87
|
|
88
88
|
- 接入了各大 cdn 的 api 接口进行请求,默认会保存一份 cdn 的缓存在你的根目录中`.cdn-cache.json`。如果发现缓存的资源有问题可以删除该文件,然后重新执行打包流程。
|
89
|
-
- 按顺序添加cdn,如react-router-dom需要依赖react、@remix-run/router、react-router,因此需要放在最后。
|
89
|
+
- 按顺序添加 cdn,如 react-router-dom 需要依赖 react、@remix-run/router、react-router,因此需要放在最后。
|
package/dist/index.js
CHANGED
@@ -1,22 +1,23 @@
|
|
1
|
-
var
|
2
|
-
var
|
3
|
-
var
|
1
|
+
var G = Object.defineProperty;
|
2
|
+
var B = (r, t, e) => t in r ? G(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
|
3
|
+
var m = (r, t, e) => (B(r, typeof t != "symbol" ? t + "" : t, e), e);
|
4
4
|
import O from "node:path";
|
5
|
-
import
|
6
|
-
import
|
7
|
-
|
5
|
+
import U from "node:fs";
|
6
|
+
import V from "node-fetch";
|
7
|
+
import J from "semver";
|
8
|
+
class z {
|
8
9
|
constructor() {
|
9
|
-
|
10
|
-
|
10
|
+
m(this, "cdnCache", {});
|
11
|
+
m(this, "cdnCachePath", "");
|
11
12
|
this.cdnCachePath = O.resolve(process.cwd(), "./.cdn-cache.json");
|
12
13
|
}
|
13
14
|
// 初始化cdn缓存
|
14
15
|
async init() {
|
15
16
|
try {
|
16
|
-
const t = await
|
17
|
+
const t = await U.readFileSync(this.cdnCachePath, "utf-8");
|
17
18
|
this.cdnCache = JSON.parse(t);
|
18
19
|
} catch {
|
19
|
-
console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await
|
20
|
+
console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await U.writeFileSync(this.cdnCachePath, "", "utf-8");
|
20
21
|
}
|
21
22
|
}
|
22
23
|
/**
|
@@ -25,8 +26,8 @@ class E {
|
|
25
26
|
* @param version 版本
|
26
27
|
*/
|
27
28
|
getCdnCache(t, e) {
|
28
|
-
var
|
29
|
-
return (
|
29
|
+
var s;
|
30
|
+
return (s = this.cdnCache[t]) == null ? void 0 : s[e];
|
30
31
|
}
|
31
32
|
/**
|
32
33
|
* 设置cdn缓存
|
@@ -34,144 +35,279 @@ class E {
|
|
34
35
|
* @param version 版本
|
35
36
|
* @param urls 地址列表
|
36
37
|
*/
|
37
|
-
setCdnCache(t, e,
|
38
|
-
this.cdnCache[t] ? this.cdnCache[t][e] =
|
39
|
-
[e]:
|
38
|
+
setCdnCache(t, e, s) {
|
39
|
+
this.cdnCache[t] ? this.cdnCache[t][e] = s : this.cdnCache[t] = {
|
40
|
+
[e]: s
|
40
41
|
};
|
41
42
|
}
|
42
43
|
/**
|
43
44
|
* 更新cdn缓存
|
44
45
|
*/
|
45
46
|
async save() {
|
46
|
-
await
|
47
|
+
await U.writeFileSync(this.cdnCachePath, JSON.stringify(this.cdnCache), "utf-8");
|
47
48
|
}
|
48
49
|
}
|
49
|
-
let
|
50
|
-
const
|
50
|
+
let b;
|
51
|
+
const K = async () => (b || (b = new z(), await b.init()), b);
|
52
|
+
class u extends Error {
|
53
|
+
constructor(t) {
|
54
|
+
super(t), this.name = "NetworkError";
|
55
|
+
}
|
56
|
+
}
|
57
|
+
class C extends u {
|
58
|
+
constructor({ packageName: t, version: e, cdn: s }) {
|
59
|
+
super(`${s} ${t}@${e} 网络请求失败`), this.name = "PackageNetworkError";
|
60
|
+
}
|
61
|
+
}
|
62
|
+
class $ extends Error {
|
63
|
+
constructor({ packageName: t, version: e, cdn: s }) {
|
64
|
+
super(`${s}上没有${t}@${e}的版本`), this.name = "NoVersionError";
|
65
|
+
}
|
66
|
+
}
|
67
|
+
class W extends Error {
|
68
|
+
constructor({ packageName: t, version: e, cdn: s }) {
|
69
|
+
super(`在 ${s} 中找不到 ${t}@${e} 文件,请检查包名或版本号`), this.name = "GetFileListError";
|
70
|
+
}
|
71
|
+
}
|
72
|
+
class X {
|
73
|
+
constructor(t) {
|
74
|
+
m(this, "_max");
|
75
|
+
m(this, "_count");
|
76
|
+
m(this, "_taskQueue");
|
77
|
+
this._max = t || 5, this._count = 0, this._taskQueue = [];
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* 请求封装
|
81
|
+
* @param caller 请求函数
|
82
|
+
* @param args 请求参数
|
83
|
+
* @returns {Promise<any>} 返回一个promise
|
84
|
+
*/
|
85
|
+
call(t, ...e) {
|
86
|
+
return new Promise((s, n) => {
|
87
|
+
const o = this._createTask(t, e, s, n);
|
88
|
+
this._count >= this._max ? this._taskQueue.push(o) : o();
|
89
|
+
});
|
90
|
+
}
|
91
|
+
/**
|
92
|
+
* 创建一个任务
|
93
|
+
* @param caller 实际执行的函数
|
94
|
+
* @param args 执行函数的参数
|
95
|
+
* @param resolve
|
96
|
+
* @param reject
|
97
|
+
* @returns {Function} 返回一个任务函数
|
98
|
+
* @private
|
99
|
+
*/
|
100
|
+
_createTask(t, e, s, n) {
|
101
|
+
return () => {
|
102
|
+
t(...e).then(s).catch(n).finally(() => {
|
103
|
+
this._count--, this._taskQueue.length && this._taskQueue.shift()();
|
104
|
+
}), this._count++;
|
105
|
+
};
|
106
|
+
}
|
107
|
+
}
|
108
|
+
const D = new X(5), M = async (r) => {
|
109
|
+
try {
|
110
|
+
const t = await V(r, { method: "HEAD", redirect: "manual" });
|
111
|
+
return t.status >= 300 && t.status < 400 ? await M(t.headers.get("location") || "") : r;
|
112
|
+
} catch (t) {
|
113
|
+
throw Promise.reject(new u(t.message));
|
114
|
+
}
|
115
|
+
}, Y = {
|
51
116
|
//get请求封装
|
52
|
-
get:
|
117
|
+
get: async (r) => {
|
53
118
|
try {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
119
|
+
const t = await V(r);
|
120
|
+
if (t.ok) {
|
121
|
+
const e = t.headers.get("content-type"), s = await t.text();
|
122
|
+
return e && e.includes("application/json") ? JSON.parse(s) : s;
|
123
|
+
} else
|
124
|
+
throw new u(`请求失败,状态码:${t.status}`);
|
125
|
+
} catch (t) {
|
126
|
+
throw new u(t.message);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}, y = {
|
130
|
+
get: D.call.bind(D, Y.get)
|
131
|
+
}, Z = async (r, t) => {
|
132
|
+
try {
|
133
|
+
const e = await y.get(`https://api.bootcdn.cn/libraries/${r}`);
|
134
|
+
if (e.length === 0)
|
135
|
+
throw new $({
|
136
|
+
packageName: r,
|
137
|
+
version: t,
|
138
|
+
cdn: "bootcdn"
|
139
|
+
});
|
140
|
+
const s = e[0], o = s.assets.reverse().find((c) => {
|
141
|
+
if (J.satisfies(c.version, t))
|
142
|
+
return !0;
|
143
|
+
});
|
144
|
+
if (!o)
|
145
|
+
throw new $({
|
146
|
+
packageName: r,
|
147
|
+
version: t,
|
148
|
+
cdn: "bootcdn"
|
149
|
+
});
|
150
|
+
return { fileList: o.files.map((c) => ({
|
151
|
+
name: "/" + c
|
152
|
+
})), recommendFileName: s.filename, version: o.version };
|
153
|
+
} catch (e) {
|
154
|
+
throw e instanceof u ? new C({
|
155
|
+
packageName: r,
|
156
|
+
version: t,
|
157
|
+
cdn: "unpkg"
|
158
|
+
}) : e;
|
159
|
+
}
|
160
|
+
}, N = (r, t, e) => `https://cdn.bootcdn.net/ajax/libs/${r}/${t}${e}`, tt = {
|
161
|
+
getFileList: Z,
|
162
|
+
getUrl: N
|
163
|
+
};
|
164
|
+
async function I(r, t, e = !1) {
|
165
|
+
try {
|
166
|
+
if (!e && t.match(/^\D/)) {
|
167
|
+
const n = await rt(r, t);
|
168
|
+
for (let o of n)
|
169
|
+
if (J.satisfies(o, t))
|
170
|
+
return I(r, o, !0);
|
171
|
+
throw new $({
|
172
|
+
packageName: r,
|
173
|
+
version: t,
|
174
|
+
cdn: "cdnjs"
|
61
175
|
});
|
62
|
-
} catch (c) {
|
63
|
-
e == null || e(c), s(c);
|
64
176
|
}
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
(
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
177
|
+
const s = await y.get(`https://api.cdnjs.com/libraries/${r}/${t}`);
|
178
|
+
if (s.error)
|
179
|
+
throw new $({
|
180
|
+
packageName: r,
|
181
|
+
version: t,
|
182
|
+
cdn: "cdnjs"
|
183
|
+
});
|
184
|
+
return {
|
185
|
+
fileList: s.rawFiles.map((n) => ({
|
186
|
+
name: "/" + n
|
187
|
+
})),
|
188
|
+
version: t
|
189
|
+
};
|
190
|
+
} catch (s) {
|
191
|
+
throw s instanceof u ? new C({
|
192
|
+
packageName: r,
|
193
|
+
version: t,
|
194
|
+
cdn: "unpkg"
|
195
|
+
}) : s;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
const et = (r, t, e) => `https://cdnjs.cloudflare.com/ajax/libs/${r}/${t}${e}`, rt = async (r, t) => {
|
199
|
+
try {
|
200
|
+
return (await y.get(`https://api.cdnjs.com/libraries/${r}?fields=versions`)).versions;
|
201
|
+
} catch (e) {
|
202
|
+
throw e instanceof u ? new C({
|
203
|
+
packageName: r,
|
204
|
+
version: t,
|
205
|
+
cdn: "unpkg"
|
206
|
+
}) : e;
|
207
|
+
}
|
208
|
+
}, st = {
|
209
|
+
getFileList: I,
|
210
|
+
getUrl: et
|
211
|
+
}, T = (r, t = "") => r.reduce((e, s) => (s.type === "file" ? e.push({ name: `${t}/${s.name}` }) : s.files && e.push(...T(s.files, `${t}/${s.name}`)), e), []);
|
212
|
+
async function Q(r, t, e = !1) {
|
213
|
+
try {
|
214
|
+
if (!e && t.match(/^\D/)) {
|
215
|
+
const n = await ot(r, t);
|
216
|
+
if (typeof n == "string")
|
217
|
+
return Q(r, n, !0);
|
218
|
+
throw new $({
|
219
|
+
packageName: r,
|
220
|
+
version: t,
|
221
|
+
cdn: "jsdelivr"
|
222
|
+
});
|
223
|
+
}
|
224
|
+
const s = await y.get(`https://data.jsdelivr.com/v1/packages/npm/${r}@${t}`);
|
225
|
+
if (s.status)
|
226
|
+
throw new $({
|
227
|
+
packageName: r,
|
228
|
+
version: t,
|
229
|
+
cdn: "jsdelivr"
|
230
|
+
});
|
231
|
+
return { fileList: T(s.files), version: t };
|
232
|
+
} catch (s) {
|
233
|
+
throw s instanceof u ? new C({
|
234
|
+
packageName: r,
|
235
|
+
version: t,
|
236
|
+
cdn: "unpkg"
|
237
|
+
}) : s;
|
238
|
+
}
|
239
|
+
}
|
240
|
+
const nt = (r, t, e) => `https://cdn.jsdelivr.net/npm/${r}@${t}${e}`, ot = async (r, t) => {
|
241
|
+
try {
|
242
|
+
return (await y.get(
|
243
|
+
`https://data.jsdelivr.com/v1/packages/npm/${r}/resolved?specifier=${t}`
|
244
|
+
)).version;
|
245
|
+
} catch (e) {
|
246
|
+
throw e instanceof u ? new C({
|
247
|
+
packageName: r,
|
248
|
+
version: t,
|
249
|
+
cdn: "unpkg"
|
250
|
+
}) : e;
|
251
|
+
}
|
252
|
+
}, ct = {
|
253
|
+
getFileList: Q,
|
254
|
+
// 拼接url
|
255
|
+
getUrl: nt
|
256
|
+
}, H = (r) => r.reduce((t, e) => (e.type === "file" ? t.push({ name: e.path }) : e.files && t.push(...H(e.files)), t), []);
|
257
|
+
async function it(r, t) {
|
258
|
+
var e;
|
259
|
+
try {
|
260
|
+
const n = (e = (await M(`https://unpkg.com/${r}@${t}/?meta`)).match(new RegExp("(?<=@)\\d+\\.\\d+\\.\\d+(?=\\/\\?meta)"))) == null ? void 0 : e[0];
|
261
|
+
if (n) {
|
262
|
+
const o = await y.get(`https://unpkg.com/${r}@${n}/?meta`);
|
263
|
+
return { fileList: H(o.files || []), version: n };
|
264
|
+
} else
|
265
|
+
throw new $({
|
266
|
+
packageName: r,
|
267
|
+
version: t,
|
268
|
+
cdn: "unpkg"
|
269
|
+
});
|
270
|
+
} catch (s) {
|
271
|
+
throw s instanceof u ? new C({
|
272
|
+
packageName: r,
|
273
|
+
version: t,
|
274
|
+
cdn: "unpkg"
|
275
|
+
}) : s;
|
276
|
+
}
|
277
|
+
}
|
278
|
+
function at(r, t, e) {
|
279
|
+
return `https://unpkg.com/${r}@${t}${e}`;
|
280
|
+
}
|
281
|
+
const lt = {
|
282
|
+
getFileList: it,
|
283
|
+
getUrl: at
|
284
|
+
}, ut = async (r) => {
|
285
|
+
try {
|
286
|
+
const t = /^(https?:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;
|
287
|
+
if (t.test(r)) {
|
288
|
+
const e = r.replace(t, (s, n) => `${n}package.json`);
|
289
|
+
return await y.get(e);
|
290
|
+
} else
|
291
|
+
throw new Error(`${r} 不是正确的url`);
|
292
|
+
} catch (t) {
|
293
|
+
throw t;
|
161
294
|
}
|
162
|
-
},
|
163
|
-
var
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
295
|
+
}, dt = (r, t) => {
|
296
|
+
var e, s;
|
297
|
+
return ((e = r.dependencies) == null ? void 0 : e[t]) || ((s = r.devDependencies) == null ? void 0 : s[t]);
|
298
|
+
}, ht = async (r, t, e) => {
|
299
|
+
if (!t.match(/\d+(.\d+)?(.\d+)?/))
|
300
|
+
throw new Error(`${r} version ${t} is not valid`);
|
301
|
+
const n = await R[e].getFileList(r, t), o = ft(n, r);
|
302
|
+
if (!o)
|
303
|
+
throw new W({
|
304
|
+
packageName: r,
|
305
|
+
version: t,
|
306
|
+
cdn: e
|
307
|
+
});
|
308
|
+
return R[e].getUrl(r, n.version, o);
|
309
|
+
}, ft = ({ fileList: r }, t) => {
|
310
|
+
var o, a;
|
175
311
|
let e = [
|
176
312
|
`umd/${t}.production.min.js`,
|
177
313
|
/umd\/.+?\.production\.min\.js$/,
|
@@ -189,137 +325,211 @@ const L = async () => (C || (C = new E(), await C.init()), C), $ = {
|
|
189
325
|
/\.min\.js$/,
|
190
326
|
/\.js$/
|
191
327
|
];
|
192
|
-
const
|
193
|
-
let
|
194
|
-
for (let
|
195
|
-
if (
|
328
|
+
const s = ["runtime", "compiler", ".esm", ".cjs", "development"].filter((c) => !t.includes(c));
|
329
|
+
let n = "";
|
330
|
+
for (let c of e)
|
331
|
+
if (c instanceof RegExp ? n = ((o = r.find((i) => c.test(i.name) && !s.some((l) => i.name.includes(l)))) == null ? void 0 : o.name) || "" : n = ((a = r.find((i) => i.name.includes(c) && !s.some((l) => i.name.includes(l)))) == null ? void 0 : a.name) || "", n)
|
196
332
|
break;
|
197
|
-
return
|
333
|
+
return n;
|
334
|
+
}, R = {
|
335
|
+
jsdelivr: ct,
|
336
|
+
bootcdn: tt,
|
337
|
+
cdnjs: st,
|
338
|
+
unpkg: lt
|
198
339
|
};
|
199
|
-
function
|
200
|
-
const e =
|
201
|
-
for (; e.length <
|
340
|
+
function pt(r, t) {
|
341
|
+
const e = r.replace(/^\D/, "").split("."), s = t.replace(/^\D/, "").split("."), n = Math.max(e.length, s.length);
|
342
|
+
for (; e.length < n; )
|
202
343
|
e.push("0");
|
203
|
-
for (;
|
204
|
-
|
205
|
-
for (let
|
206
|
-
const
|
207
|
-
if (
|
344
|
+
for (; s.length < n; )
|
345
|
+
s.push("0");
|
346
|
+
for (let o = 0; o < n; o++) {
|
347
|
+
const a = parseInt(e[o], 10), c = parseInt(s[o], 10);
|
348
|
+
if (a > c)
|
208
349
|
return 1;
|
209
|
-
if (
|
350
|
+
if (a < c)
|
210
351
|
return -1;
|
211
352
|
}
|
212
353
|
return 0;
|
213
354
|
}
|
214
|
-
function
|
355
|
+
function wt(r, t) {
|
215
356
|
for (let e in t)
|
216
|
-
Object.prototype.hasOwnProperty.call(t, e) && (
|
217
|
-
return
|
357
|
+
Object.prototype.hasOwnProperty.call(t, e) && (r[e] ? pt(r[e], t[e]) === -1 && (r[e] = t[e]) : r[e] = t[e]);
|
358
|
+
return r;
|
359
|
+
}
|
360
|
+
class gt {
|
361
|
+
constructor() {
|
362
|
+
// 打印记录
|
363
|
+
m(this, "logList", []);
|
364
|
+
}
|
365
|
+
// 打印方法
|
366
|
+
log(t) {
|
367
|
+
this.logList.push({
|
368
|
+
type: "log",
|
369
|
+
message: t
|
370
|
+
});
|
371
|
+
}
|
372
|
+
warn(t) {
|
373
|
+
this.logList.push({
|
374
|
+
type: "warn",
|
375
|
+
message: t
|
376
|
+
});
|
377
|
+
}
|
378
|
+
error(t) {
|
379
|
+
this.logList.push({
|
380
|
+
type: "error",
|
381
|
+
message: t
|
382
|
+
});
|
383
|
+
}
|
384
|
+
info(t) {
|
385
|
+
this.logList.push({
|
386
|
+
type: "info",
|
387
|
+
message: t
|
388
|
+
});
|
389
|
+
}
|
390
|
+
// 打印全部
|
391
|
+
consoleAll() {
|
392
|
+
this.logList.forEach((t) => {
|
393
|
+
console[t.type](`${q} ${t.message}`);
|
394
|
+
});
|
395
|
+
}
|
396
|
+
// 清除打印记录
|
397
|
+
clear() {
|
398
|
+
this.logList = [];
|
399
|
+
}
|
218
400
|
}
|
219
|
-
|
220
|
-
|
221
|
-
|
401
|
+
const q = "vite-add-cdn-script", S = new gt();
|
402
|
+
async function A({
|
403
|
+
external: r,
|
404
|
+
packageData: t,
|
405
|
+
customScript: e,
|
406
|
+
defaultCdns: s
|
407
|
+
}) {
|
408
|
+
let n = [], o = !1;
|
409
|
+
const a = await K();
|
222
410
|
return await Promise.all(
|
223
|
-
|
224
|
-
const
|
225
|
-
if (e[
|
411
|
+
r.map(async (c) => {
|
412
|
+
const i = dt(t, c);
|
413
|
+
if (e[c])
|
226
414
|
return {
|
227
415
|
urls: [],
|
228
|
-
key:
|
416
|
+
key: c
|
229
417
|
};
|
230
|
-
if (!
|
231
|
-
return
|
418
|
+
if (!i)
|
419
|
+
return n.push(c), {
|
232
420
|
urls: [],
|
233
|
-
key:
|
421
|
+
key: c
|
234
422
|
};
|
235
|
-
const l =
|
423
|
+
const l = a.getCdnCache(c, i);
|
236
424
|
if (l)
|
237
425
|
return {
|
238
426
|
urls: l,
|
239
|
-
key:
|
427
|
+
key: c
|
240
428
|
};
|
241
429
|
{
|
242
|
-
|
430
|
+
o = !0, console.log(`从网络获取${c}${i}的cdn地址`);
|
431
|
+
const L = await Promise.allSettled(
|
432
|
+
s.map(async (w) => await ht(c, i, w))
|
433
|
+
).then((w) => w.filter((f) => {
|
434
|
+
if (f.status === "fulfilled")
|
435
|
+
return f.value, !0;
|
436
|
+
S.warn(f.reason.toString());
|
437
|
+
}).map((f) => f.value));
|
438
|
+
if (L.length === 0)
|
439
|
+
throw new Error(`获取${c} ${i}的cdn地址失败`);
|
243
440
|
const d = {
|
244
|
-
urls:
|
245
|
-
|
246
|
-
),
|
247
|
-
key: i
|
441
|
+
urls: L,
|
442
|
+
key: c
|
248
443
|
};
|
249
|
-
return
|
444
|
+
return a.setCdnCache(c, i, d.urls), d;
|
250
445
|
}
|
251
446
|
})
|
252
|
-
).then((
|
253
|
-
urls:
|
254
|
-
noVersionPackages:
|
447
|
+
).then((c) => (o && a.save(), {
|
448
|
+
urls: c,
|
449
|
+
noVersionPackages: n
|
255
450
|
}));
|
256
451
|
}
|
257
|
-
function
|
258
|
-
const { customScript: t = {}, retryTimes: e = 1, defaultCdns:
|
259
|
-
let
|
452
|
+
function Pt(r) {
|
453
|
+
const { customScript: t = {}, retryTimes: e = 1, defaultCdns: s = ["jsdelivr", "unpkg"] } = r;
|
454
|
+
let n;
|
260
455
|
return {
|
261
|
-
name:
|
456
|
+
name: q,
|
262
457
|
enforce: "pre",
|
263
458
|
apply: "build",
|
264
|
-
config(
|
265
|
-
|
459
|
+
config(o) {
|
460
|
+
n = o;
|
266
461
|
},
|
267
|
-
async transformIndexHtml(
|
268
|
-
|
462
|
+
async transformIndexHtml(o) {
|
463
|
+
var c, i;
|
464
|
+
if (!s || s.length === 0)
|
269
465
|
throw new Error("defaultCdns不能为空");
|
270
|
-
const
|
466
|
+
const a = O.resolve(process.cwd(), "package.json");
|
271
467
|
try {
|
272
|
-
const
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
468
|
+
const l = U.readFileSync(a, "utf-8"), L = JSON.parse(l), d = (i = (c = n.build) == null ? void 0 : c.rollupOptions) == null ? void 0 : i.external;
|
469
|
+
if (!d)
|
470
|
+
return o;
|
471
|
+
let w = [];
|
472
|
+
if (typeof d == "string")
|
473
|
+
w = [d];
|
474
|
+
else if (Array.isArray(d))
|
475
|
+
w = d.filter((g) => typeof g == "string");
|
476
|
+
else if (typeof d == "object")
|
477
|
+
return o;
|
478
|
+
const f = {};
|
479
|
+
let k = "";
|
480
|
+
const { urls: v, noVersionPackages: _ } = await A({
|
481
|
+
external: w,
|
482
|
+
packageData: L,
|
277
483
|
customScript: t,
|
278
|
-
defaultCdns:
|
484
|
+
defaultCdns: s
|
279
485
|
});
|
280
|
-
if (
|
281
|
-
const
|
282
|
-
await Promise.
|
283
|
-
|
284
|
-
if (!
|
486
|
+
if (_.length > 0) {
|
487
|
+
const g = { dependencies: {} };
|
488
|
+
await Promise.allSettled(
|
489
|
+
v.map(async (h) => {
|
490
|
+
if (!h)
|
285
491
|
return;
|
286
|
-
const { key: j, urls:
|
287
|
-
if (!
|
492
|
+
const { key: j, urls: F } = h, P = t[j] || F[0];
|
493
|
+
if (!P)
|
288
494
|
return;
|
289
|
-
const
|
290
|
-
|
495
|
+
const x = await ut(P);
|
496
|
+
wt(g.dependencies, x.dependencies);
|
291
497
|
})
|
292
|
-
)
|
293
|
-
|
294
|
-
|
295
|
-
|
498
|
+
).then((h) => {
|
499
|
+
h.forEach((j) => {
|
500
|
+
j.status === "rejected" && S.warn(j.reason.toString());
|
501
|
+
});
|
502
|
+
});
|
503
|
+
const { urls: E, noVersionPackages: p } = await A({
|
504
|
+
external: _,
|
505
|
+
packageData: g,
|
296
506
|
customScript: t,
|
297
|
-
defaultCdns:
|
507
|
+
defaultCdns: s
|
298
508
|
});
|
299
|
-
if (
|
300
|
-
var
|
301
|
-
if (!
|
509
|
+
if (E.map((h) => {
|
510
|
+
var P;
|
511
|
+
if (!h)
|
302
512
|
return;
|
303
|
-
const { urls: j, key:
|
304
|
-
(
|
305
|
-
}),
|
306
|
-
throw console.error(`找不到${
|
513
|
+
const { urls: j, key: F } = h;
|
514
|
+
(P = v.find((x) => (x == null ? void 0 : x.key) === F)) == null || P.urls.push(...j);
|
515
|
+
}), p.length > 0)
|
516
|
+
throw console.error(`找不到${p.join(",")}的版本`), new Error(`找不到${p.join(",")}的版本`);
|
307
517
|
}
|
308
|
-
return
|
309
|
-
if (!
|
518
|
+
return S.consoleAll(), v.forEach((g) => {
|
519
|
+
if (!g)
|
310
520
|
return;
|
311
|
-
const { urls:
|
312
|
-
if (t[
|
313
|
-
|
521
|
+
const { urls: E, key: p } = g;
|
522
|
+
if (t[p])
|
523
|
+
k += t[p];
|
314
524
|
else {
|
315
|
-
|
316
|
-
const
|
317
|
-
|
525
|
+
f[p] = E;
|
526
|
+
const h = E[0];
|
527
|
+
k += `<script src="${h}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${p}"><\/script>
|
318
528
|
`;
|
319
529
|
}
|
320
|
-
}),
|
530
|
+
}), k = `<script>
|
321
531
|
function errorCDN(e) {
|
322
|
-
const packNameUrl = JSON.parse('${JSON.stringify(
|
532
|
+
const packNameUrl = JSON.parse('${JSON.stringify(f)}');
|
323
533
|
const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
|
324
534
|
if(nextCur>${e}){return;}
|
325
535
|
|
@@ -339,13 +549,14 @@ function q(n) {
|
|
339
549
|
document.head.appendChild(cdnDOM);
|
340
550
|
e.remove();
|
341
551
|
}
|
342
|
-
<\/script>` +
|
343
|
-
} catch (
|
344
|
-
console.error("
|
552
|
+
<\/script>` + k, o = o.replace("</head>", `${k}</head>`), o;
|
553
|
+
} catch (l) {
|
554
|
+
S.consoleAll(), console.error("vite-add-cdn-script error:", l.message), process.exit(1);
|
345
555
|
}
|
346
556
|
}
|
347
557
|
};
|
348
558
|
}
|
349
559
|
export {
|
350
|
-
|
560
|
+
Pt as default,
|
561
|
+
q as libName
|
351
562
|
};
|
package/dist/index.umd.cjs
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
(function(
|
2
|
-
`}}),
|
1
|
+
(function(c,l){typeof exports=="object"&&typeof module<"u"?l(exports,require("node:path"),require("node:fs"),require("node-fetch"),require("semver")):typeof define=="function"&&define.amd?define(["exports","node:path","node:fs","node-fetch","semver"],l):(c=typeof globalThis<"u"?globalThis:c||self,l(c.index={},c.path,c.fs,c.fetch,c.semver))})(this,function(c,l,d,R,A){"use strict";var wt=Object.defineProperty;var gt=(c,l,d)=>l in c?wt(c,l,{enumerable:!0,configurable:!0,writable:!0,value:d}):c[l]=d;var k=(c,l,d)=>(gt(c,typeof l!="symbol"?l+"":l,d),d);class B{constructor(){k(this,"cdnCache",{});k(this,"cdnCachePath","");this.cdnCachePath=l.resolve(process.cwd(),"./.cdn-cache.json")}async init(){try{const t=await d.readFileSync(this.cdnCachePath,"utf-8");this.cdnCache=JSON.parse(t)}catch{console.log("cdn缓存文件不存在,创建缓存文件"),this.cdnCache={},await d.writeFileSync(this.cdnCachePath,"","utf-8")}}getCdnCache(t,e){var n;return(n=this.cdnCache[t])==null?void 0:n[e]}setCdnCache(t,e,n){this.cdnCache[t]?this.cdnCache[t][e]=n:this.cdnCache[t]={[e]:n}}async save(){await d.writeFileSync(this.cdnCachePath,JSON.stringify(this.cdnCache),"utf-8")}}let b;const z=async()=>(b||(b=new B,await b.init()),b);class h extends Error{constructor(t){super(t),this.name="NetworkError"}}class P extends h{constructor({packageName:t,version:e,cdn:n}){super(`${n} ${t}@${e} 网络请求失败`),this.name="PackageNetworkError"}}class $ extends Error{constructor({packageName:t,version:e,cdn:n}){super(`${n}上没有${t}@${e}的版本`),this.name="NoVersionError"}}class K extends Error{constructor({packageName:t,version:e,cdn:n}){super(`在 ${n} 中找不到 ${t}@${e} 文件,请检查包名或版本号`),this.name="GetFileListError"}}class W{constructor(t){k(this,"_max");k(this,"_count");k(this,"_taskQueue");this._max=t||5,this._count=0,this._taskQueue=[]}call(t,...e){return new Promise((n,s)=>{const i=this._createTask(t,e,n,s);this._count>=this._max?this._taskQueue.push(i):i()})}_createTask(t,e,n,s){return()=>{t(...e).then(n).catch(s).finally(()=>{this._count--,this._taskQueue.length&&this._taskQueue.shift()()}),this._count++}}}const V=new W(5),J=async r=>{try{const t=await R(r,{method:"HEAD",redirect:"manual"});return t.status>=300&&t.status<400?await J(t.headers.get("location")||""):r}catch(t){throw Promise.reject(new h(t.message))}},X={get:async r=>{try{const t=await R(r);if(t.ok){const e=t.headers.get("content-type"),n=await t.text();return e&&e.includes("application/json")?JSON.parse(n):n}else throw new h(`请求失败,状态码:${t.status}`)}catch(t){throw new h(t.message)}}},y={get:V.call.bind(V,X.get)},Y={getFileList:async(r,t)=>{try{const e=await y.get(`https://api.bootcdn.cn/libraries/${r}`);if(e.length===0)throw new $({packageName:r,version:t,cdn:"bootcdn"});const n=e[0],i=n.assets.reverse().find(o=>{if(A.satisfies(o.version,t))return!0});if(!i)throw new $({packageName:r,version:t,cdn:"bootcdn"});return{fileList:i.files.map(o=>({name:"/"+o})),recommendFileName:n.filename,version:i.version}}catch(e){throw e instanceof h?new P({packageName:r,version:t,cdn:"unpkg"}):e}},getUrl:(r,t,e)=>`https://cdn.bootcdn.net/ajax/libs/${r}/${t}${e}`};async function M(r,t,e=!1){try{if(!e&&t.match(/^\D/)){const s=await N(r,t);for(let i of s)if(A.satisfies(i,t))return M(r,i,!0);throw new $({packageName:r,version:t,cdn:"cdnjs"})}const n=await y.get(`https://api.cdnjs.com/libraries/${r}/${t}`);if(n.error)throw new $({packageName:r,version:t,cdn:"cdnjs"});return{fileList:n.rawFiles.map(s=>({name:"/"+s})),version:t}}catch(n){throw n instanceof h?new P({packageName:r,version:t,cdn:"unpkg"}):n}}const Z=(r,t,e)=>`https://cdnjs.cloudflare.com/ajax/libs/${r}/${t}${e}`,N=async(r,t)=>{try{return(await y.get(`https://api.cdnjs.com/libraries/${r}?fields=versions`)).versions}catch(e){throw e instanceof h?new P({packageName:r,version:t,cdn:"unpkg"}):e}},tt={getFileList:M,getUrl:Z},T=(r,t="")=>r.reduce((e,n)=>(n.type==="file"?e.push({name:`${t}/${n.name}`}):n.files&&e.push(...T(n.files,`${t}/${n.name}`)),e),[]);async function I(r,t,e=!1){try{if(!e&&t.match(/^\D/)){const s=await rt(r,t);if(typeof s=="string")return I(r,s,!0);throw new $({packageName:r,version:t,cdn:"jsdelivr"})}const n=await y.get(`https://data.jsdelivr.com/v1/packages/npm/${r}@${t}`);if(n.status)throw new $({packageName:r,version:t,cdn:"jsdelivr"});return{fileList:T(n.files),version:t}}catch(n){throw n instanceof h?new P({packageName:r,version:t,cdn:"unpkg"}):n}}const et=(r,t,e)=>`https://cdn.jsdelivr.net/npm/${r}@${t}${e}`,rt=async(r,t)=>{try{return(await y.get(`https://data.jsdelivr.com/v1/packages/npm/${r}/resolved?specifier=${t}`)).version}catch(e){throw e instanceof h?new P({packageName:r,version:t,cdn:"unpkg"}):e}},nt={getFileList:I,getUrl:et},q=r=>r.reduce((t,e)=>(e.type==="file"?t.push({name:e.path}):e.files&&t.push(...q(e.files)),t),[]);async function st(r,t){var e;try{const s=(e=(await J(`https://unpkg.com/${r}@${t}/?meta`)).match(new RegExp("(?<=@)\\d+\\.\\d+\\.\\d+(?=\\/\\?meta)")))==null?void 0:e[0];if(s){const i=await y.get(`https://unpkg.com/${r}@${s}/?meta`);return{fileList:q(i.files||[]),version:s}}else throw new $({packageName:r,version:t,cdn:"unpkg"})}catch(n){throw n instanceof h?new P({packageName:r,version:t,cdn:"unpkg"}):n}}function it(r,t,e){return`https://unpkg.com/${r}@${t}${e}`}const ot={getFileList:st,getUrl:it},ct=async r=>{try{const t=/^(https?:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;if(t.test(r)){const e=r.replace(t,(n,s)=>`${s}package.json`);return await y.get(e)}else throw new Error(`${r} 不是正确的url`)}catch(t){throw t}},at=(r,t)=>{var e,n;return((e=r.dependencies)==null?void 0:e[t])||((n=r.devDependencies)==null?void 0:n[t])},lt=async(r,t,e)=>{if(!t.match(/\d+(.\d+)?(.\d+)?/))throw new Error(`${r} version ${t} is not valid`);const s=await Q[e].getFileList(r,t),i=ut(s,r);if(!i)throw new K({packageName:r,version:t,cdn:e});return Q[e].getUrl(r,s.version,i)},ut=({fileList:r},t)=>{var i,u;let e=[`umd/${t}.production.min.js`,/umd\/.+?\.production\.min\.js$/,/dist\/.+?\.production\.min\.js$/,/dist\/.+?\.umd\.min\.js$/,`dist/${t}.prod.min.js`,/dist\/.+?\.global.prod.min.js/,`dist/${t}.min.js`,/.+?\.global.prod.min.js/,/.+?.global.prod.js/,/lib\/.+?\.min\.js$/,/dist\/.+?\.min\.js$/,/index\.min\.js$/,/index\.js$/,/\.min\.js$/,/\.js$/];const n=["runtime","compiler",".esm",".cjs","development"].filter(o=>!t.includes(o));let s="";for(let o of e)if(o instanceof RegExp?s=((i=r.find(a=>o.test(a.name)&&!n.some(f=>a.name.includes(f))))==null?void 0:i.name)||"":s=((u=r.find(a=>a.name.includes(o)&&!n.some(f=>a.name.includes(f))))==null?void 0:u.name)||"",s)break;return s},Q={jsdelivr:nt,bootcdn:Y,cdnjs:tt,unpkg:ot};function dt(r,t){const e=r.replace(/^\D/,"").split("."),n=t.replace(/^\D/,"").split("."),s=Math.max(e.length,n.length);for(;e.length<s;)e.push("0");for(;n.length<s;)n.push("0");for(let i=0;i<s;i++){const u=parseInt(e[i],10),o=parseInt(n[i],10);if(u>o)return 1;if(u<o)return-1}return 0}function ht(r,t){for(let e in t)Object.prototype.hasOwnProperty.call(t,e)&&(r[e]?dt(r[e],t[e])===-1&&(r[e]=t[e]):r[e]=t[e]);return r}class ft{constructor(){k(this,"logList",[])}log(t){this.logList.push({type:"log",message:t})}warn(t){this.logList.push({type:"warn",message:t})}error(t){this.logList.push({type:"error",message:t})}info(t){this.logList.push({type:"info",message:t})}consoleAll(){this.logList.forEach(t=>{console[t.type](`${F} ${t.message}`)})}clear(){this.logList=[]}}const F="vite-add-cdn-script",v=new ft;async function H({external:r,packageData:t,customScript:e,defaultCdns:n}){let s=[],i=!1;const u=await z();return await Promise.all(r.map(async o=>{const a=at(t,o);if(e[o])return{urls:[],key:o};if(!a)return s.push(o),{urls:[],key:o};const f=u.getCdnCache(o,a);if(f)return{urls:f,key:o};{i=!0,console.log(`从网络获取${o}${a}的cdn地址`);const S=await Promise.allSettled(n.map(async j=>await lt(o,a,j))).then(j=>j.filter(g=>{if(g.status==="fulfilled")return g.value,!0;v.warn(g.reason.toString())}).map(g=>g.value));if(S.length===0)throw new Error(`获取${o} ${a}的cdn地址失败`);const p={urls:S,key:o};return u.setCdnCache(o,a,p.urls),p}})).then(o=>(i&&u.save(),{urls:o,noVersionPackages:s}))}function pt(r){const{customScript:t={},retryTimes:e=1,defaultCdns:n=["jsdelivr","unpkg"]}=r;let s;return{name:F,enforce:"pre",apply:"build",config(i){s=i},async transformIndexHtml(i){var o,a;if(!n||n.length===0)throw new Error("defaultCdns不能为空");const u=l.resolve(process.cwd(),"package.json");try{const f=d.readFileSync(u,"utf-8"),S=JSON.parse(f),p=(a=(o=s.build)==null?void 0:o.rollupOptions)==null?void 0:a.external;if(!p)return i;let j=[];if(typeof p=="string")j=[p];else if(Array.isArray(p))j=p.filter(C=>typeof C=="string");else if(typeof p=="object")return i;const g={};let L="";const{urls:D,noVersionPackages:G}=await H({external:j,packageData:S,customScript:t,defaultCdns:n});if(G.length>0){const C={dependencies:{}};await Promise.allSettled(D.map(async w=>{if(!w)return;const{key:x,urls:O}=w,E=t[x]||O[0];if(!E)return;const U=await ct(E);ht(C.dependencies,U.dependencies)})).then(w=>{w.forEach(x=>{x.status==="rejected"&&v.warn(x.reason.toString())})});const{urls:_,noVersionPackages:m}=await H({external:G,packageData:C,customScript:t,defaultCdns:n});if(_.map(w=>{var E;if(!w)return;const{urls:x,key:O}=w;(E=D.find(U=>(U==null?void 0:U.key)===O))==null||E.urls.push(...x)}),m.length>0)throw console.error(`找不到${m.join(",")}的版本`),new Error(`找不到${m.join(",")}的版本`)}return v.consoleAll(),D.forEach(C=>{if(!C)return;const{urls:_,key:m}=C;if(t[m])L+=t[m];else{g[m]=_;const w=_[0];L+=`<script src="${w}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${m}"><\/script>
|
2
|
+
`}}),L=`<script>
|
3
3
|
function errorCDN(e) {
|
4
|
-
const packNameUrl = JSON.parse('${JSON.stringify(
|
4
|
+
const packNameUrl = JSON.parse('${JSON.stringify(g)}');
|
5
5
|
const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
|
6
|
-
if(nextCur>${
|
6
|
+
if(nextCur>${e}){return;}
|
7
7
|
|
8
8
|
const key = e.getAttribute("data-key");
|
9
9
|
if(nextCur>=packNameUrl[key].length){return;}
|
@@ -21,4 +21,4 @@
|
|
21
21
|
document.head.appendChild(cdnDOM);
|
22
22
|
e.remove();
|
23
23
|
}
|
24
|
-
<\/script>`+
|
24
|
+
<\/script>`+L,i=i.replace("</head>",`${L}</head>`),i}catch(f){v.consoleAll(),console.error("vite-add-cdn-script error:",f.message),process.exit(1)}}}}c.default=pt,c.libName=F,Object.defineProperties(c,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "vite-add-cdn-script",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.10",
|
4
4
|
"keywords": [
|
5
5
|
"vite",
|
6
6
|
"cdn",
|
@@ -37,13 +37,15 @@
|
|
37
37
|
"devDependencies": {
|
38
38
|
"@jest/globals": "^29.7.0",
|
39
39
|
"@types/node": "^20.12.11",
|
40
|
+
"@types/node-fetch": "2",
|
40
41
|
"@types/react": "^18.3.2",
|
41
42
|
"@types/react-dom": "^18.3.0",
|
43
|
+
"@types/semver": "^7.5.8",
|
42
44
|
"@vitejs/plugin-react": "^4.2.1",
|
43
45
|
"cross-env": "^7.0.3",
|
44
46
|
"jest": "^29.7.0",
|
45
|
-
"react": "^18.
|
46
|
-
"react-dom": "^18.
|
47
|
+
"react": "^18.2.0",
|
48
|
+
"react-dom": "^18.2.0",
|
47
49
|
"react-router-dom": "^6.23.1",
|
48
50
|
"rollup-plugin-external-globals": "^0.10.0",
|
49
51
|
"rollup-plugin-node-externals": "^7.1.2",
|
@@ -55,5 +57,8 @@
|
|
55
57
|
"publishConfig": {
|
56
58
|
"registry": "https://registry.npmjs.org/"
|
57
59
|
},
|
58
|
-
"dependencies": {
|
60
|
+
"dependencies": {
|
61
|
+
"node-fetch": "2",
|
62
|
+
"semver": "^7.6.2"
|
63
|
+
}
|
59
64
|
}
|