vite-add-cdn-script 1.0.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -1,681 +1,37 @@
1
- var X = Object.defineProperty;
2
- var Y = (s, e, t) => e in s ? X(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
- var f = (s, e, t) => (Y(s, typeof e != "symbol" ? e + "" : e, t), t);
4
- import M from "node:path";
5
- import P from "node:fs";
6
- import O from "node-fetch";
7
- import V from "semver";
8
- var L = /* @__PURE__ */ ((s) => (s.noFound = "noFound", s.NetworkError = "networkError", s))(L || {});
9
- class Z {
10
- constructor() {
11
- f(this, "cdnCache", {
12
- packageDependencies: {},
13
- cdnsUrl: {}
14
- });
15
- f(this, "cdnCachePath", "");
16
- this.cdnCachePath = M.resolve(process.cwd(), "./.cdn-cache.json");
17
- }
18
- // 初始化cdn缓存
19
- async init() {
20
- try {
21
- const e = await P.readFileSync(this.cdnCachePath, "utf-8");
22
- this.cdnCache = JSON.parse(e);
23
- } catch {
24
- console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {
25
- packageDependencies: {},
26
- cdnsUrl: {}
27
- }, await P.writeFileSync(this.cdnCachePath, "", "utf-8");
28
- }
29
- }
30
- /**
31
- * 获取cdn缓存
32
- * @param packageName 包名
33
- * @param version 版本
34
- */
35
- getCdnCache(e, t) {
36
- var r;
37
- return (r = this.cdnCache.cdnsUrl[e]) == null ? void 0 : r[t];
38
- }
39
- /**
40
- * 设置cdn缓存
41
- * @param packageName 包名
42
- * @param version 版本
43
- * @param urls 地址列表
44
- */
45
- setCdnCache(e, t, r) {
46
- this.cdnCache.cdnsUrl[e] ? this.cdnCache.cdnsUrl[e][t] = r : this.cdnCache.cdnsUrl[e] = {
47
- [t]: r
48
- };
49
- }
50
- /**
51
- * 更新cdn缓存
52
- */
53
- async save() {
54
- await P.writeFileSync(this.cdnCachePath, JSON.stringify(this.cdnCache), "utf-8");
55
- }
56
- /**
57
- * 获取依赖包的package.json
58
- * @param packageName 包名
59
- * @param identification 版本号或者url
60
- */
61
- getPackageDependencies(e, t) {
62
- var r;
63
- return (r = this.cdnCache.packageDependencies[e]) == null ? void 0 : r[t];
64
- }
65
- /**
66
- * 设置依赖包的package.json
67
- * @param packageName 包名
68
- * @param identification 版本号或者url
69
- * @param dependencies 依赖
70
- */
71
- setPackageDependencies(e, t, r) {
72
- this.cdnCache.packageDependencies[e] ? this.cdnCache.packageDependencies[e][t] = r : this.cdnCache.packageDependencies[e] = {
73
- [t]: r
74
- };
75
- }
76
- }
77
- let C;
78
- const A = async () => (C || (C = new Z(), await C.init()), C);
79
- class g extends Error {
80
- constructor(e) {
81
- super(e), this.name = "NetworkError";
82
- }
83
- }
84
- class y extends g {
85
- constructor({ packageName: t, version: r, cdn: n }) {
86
- super(`${n} ${t}@${r} 网络请求失败`);
87
- f(this, "cdn");
88
- f(this, "packageName");
89
- f(this, "version");
90
- this.name = "PackageNetworkError", this.cdn = n, this.packageName = t, this.version = r;
91
- }
92
- getErrorInfo() {
93
- return {
94
- cdn: this.cdn,
95
- packageName: this.packageName,
96
- version: this.version
97
- };
98
- }
99
- }
100
- class k extends Error {
101
- constructor({ packageName: t, version: r, cdn: n }) {
102
- super(`${n}上没有${t}@${r}的版本`);
103
- f(this, "cdn");
104
- f(this, "packageName");
105
- f(this, "version");
106
- this.name = "NoVersionError", this.cdn = n, this.packageName = t, this.version = r;
107
- }
108
- getErrorInfo() {
109
- return {
110
- cdn: this.cdn,
111
- packageName: this.packageName,
112
- version: this.version
113
- };
114
- }
115
- }
116
- class ee extends Error {
117
- constructor({ packageName: e, version: t, cdn: r }) {
118
- super(`在 ${r} 中找不到 ${e}@${t} 文件,请检查包名或版本号`), this.name = "GetFileListError";
119
- }
120
- }
121
- class te {
122
- constructor(e) {
123
- f(this, "_max");
124
- f(this, "_count");
125
- f(this, "_taskQueue");
126
- this._max = e || 5, this._count = 0, this._taskQueue = [];
127
- }
128
- /**
129
- * 请求封装
130
- * @param caller 请求函数
131
- * @param args 请求参数
132
- * @returns {Promise<any>} 返回一个promise
133
- */
134
- call(e, ...t) {
135
- return new Promise((r, n) => {
136
- const c = this._createTask(e, t, r, n);
137
- this._count >= this._max ? this._taskQueue.push(c) : c();
138
- });
139
- }
140
- /**
141
- * 创建一个任务
142
- * @param caller 实际执行的函数
143
- * @param args 执行函数的参数
144
- * @param resolve
145
- * @param reject
146
- * @returns {Function} 返回一个任务函数
147
- * @private
148
- */
149
- _createTask(e, t, r, n) {
150
- return () => {
151
- e(...t).then(r).catch(n).finally(() => {
152
- this._count--, this._taskQueue.length && this._taskQueue.shift()();
153
- }), this._count++;
154
- };
155
- }
156
- }
157
- const b = new te(5), J = async (s) => {
158
- try {
159
- const e = await O(s, { method: "HEAD", redirect: "manual" });
160
- return e.status >= 300 && e.status < 400 ? await J(e.headers.get("location") || "") : s;
161
- } catch (e) {
162
- throw new g(e.message);
163
- }
164
- }, se = {
165
- //get请求封装
166
- get: async (s) => {
167
- try {
168
- const e = await O(s);
169
- if (e.ok) {
170
- const t = e.headers.get("content-type"), r = await e.text();
171
- return t && t.includes("application/json") ? JSON.parse(r) : r;
172
- } else
173
- throw new g(`请求失败,状态码:${e.status}`);
174
- } catch (e) {
175
- throw new g(e.message);
176
- }
177
- }
178
- }, j = {
179
- get: b.call.bind(b, se.get)
180
- }, re = async (s, e) => {
181
- try {
182
- const t = await j.get(`https://api.bootcdn.cn/libraries/${s}`);
183
- if (t.length === 0)
184
- throw new k({
185
- packageName: s,
186
- version: e,
187
- cdn: "bootcdn"
188
- });
189
- const r = t[0], c = r.assets.reverse().find((i) => {
190
- if (V.satisfies(i.version, e))
191
- return !0;
192
- });
193
- if (!c)
194
- throw new k({
195
- packageName: s,
196
- version: e,
197
- cdn: "bootcdn"
198
- });
199
- return { fileList: c.files.map((i) => ({
200
- name: "/" + i
201
- })), recommendFileName: r.filename, version: c.version };
202
- } catch (t) {
203
- throw t instanceof g ? new y({
204
- packageName: s,
205
- version: e,
206
- cdn: "bootcdn"
207
- }) : t;
208
- }
209
- }, ne = (s, e, t) => `https://cdn.bootcdn.net/ajax/libs/${s}/${e}${t}`, ce = {
210
- getFileList: re,
211
- getUrl: ne
212
- };
213
- async function I(s, e, t = !1) {
214
- try {
215
- if (!t && e.match(/^\D/)) {
216
- const n = await ie(s, e);
217
- for (let c of n)
218
- if (V.satisfies(c, e))
219
- return I(s, c, !0);
220
- throw new k({
221
- packageName: s,
222
- version: e,
223
- cdn: "cdnjs"
224
- });
225
- }
226
- const r = await j.get(`https://api.cdnjs.com/libraries/${s}/${e}`);
227
- if (r.error)
228
- throw new k({
229
- packageName: s,
230
- version: e,
231
- cdn: "cdnjs"
232
- });
233
- return {
234
- fileList: r.rawFiles.map((n) => ({
235
- name: "/" + n
236
- })),
237
- version: e
238
- };
239
- } catch (r) {
240
- throw r instanceof g ? new y({
241
- packageName: s,
242
- version: e,
243
- cdn: "cdnjs"
244
- }) : r;
245
- }
246
- }
247
- const oe = (s, e, t) => `https://cdnjs.cloudflare.com/ajax/libs/${s}/${e}${t}`, ie = async (s, e) => {
248
- try {
249
- return (await j.get(`https://api.cdnjs.com/libraries/${s}?fields=versions`)).versions;
250
- } catch (t) {
251
- throw t instanceof g ? new y({
252
- packageName: s,
253
- version: e,
254
- cdn: "cdnjs"
255
- }) : t;
256
- }
257
- }, ae = {
258
- getFileList: I,
259
- getUrl: oe
260
- }, N = (s, e = "") => s.reduce((t, r) => (r.type === "file" ? t.push({ name: `${e}/${r.name}` }) : r.files && t.push(...N(r.files, `${e}/${r.name}`)), t), []);
261
- async function Q(s, e, t = !1) {
262
- try {
263
- if (!t && e.match(/^\D/)) {
264
- const n = await de(s, e);
265
- if (typeof n == "string")
266
- return Q(s, n, !0);
267
- throw new k({
268
- packageName: s,
269
- version: e,
270
- cdn: "jsdelivr"
271
- });
272
- }
273
- const r = await j.get(`https://data.jsdelivr.com/v1/packages/npm/${s}@${e}`);
274
- if (r.status)
275
- throw new k({
276
- packageName: s,
277
- version: e,
278
- cdn: "jsdelivr"
279
- });
280
- return { fileList: N(r.files), version: e };
281
- } catch (r) {
282
- throw r instanceof g ? new y({
283
- packageName: s,
284
- version: e,
285
- cdn: "jsdelivr"
286
- }) : r;
287
- }
288
- }
289
- const le = (s, e, t) => `https://cdn.jsdelivr.net/npm/${s}@${e}${t}`, de = async (s, e) => {
290
- try {
291
- return (await j.get(
292
- `https://data.jsdelivr.com/v1/packages/npm/${s}/resolved?specifier=${e}`
293
- )).version;
294
- } catch (t) {
295
- throw t instanceof g ? new y({
296
- packageName: s,
297
- version: e,
298
- cdn: "jsdelivr"
299
- }) : t;
300
- }
301
- }, ue = {
302
- getFileList: Q,
303
- // 拼接url
304
- getUrl: le
305
- }, T = (s) => s.reduce((e, t) => (t.type === "file" ? e.push({ name: t.path }) : t.files && e.push(...T(t.files)), e), []);
306
- async function he(s, e) {
307
- var t;
308
- try {
309
- const n = (t = (await J(`https://unpkg.com/${s}@${e}/?meta`)).match(new RegExp("(?<=@)\\d+\\.\\d+\\.\\d+(?=\\/\\?meta)"))) == null ? void 0 : t[0];
310
- if (n) {
311
- const c = await j.get(`https://unpkg.com/${s}@${n}/?meta`);
312
- return { fileList: T(c.files || []), version: n };
313
- } else
314
- throw new k({
315
- packageName: s,
316
- version: e,
317
- cdn: "unpkg"
318
- });
319
- } catch (r) {
320
- throw r instanceof g ? new y({
321
- packageName: s,
322
- version: e,
323
- cdn: "unpkg"
324
- }) : r;
325
- }
326
- }
327
- function fe(s, e, t) {
328
- return `https://unpkg.com/${s}@${e}${t}`;
329
- }
330
- const pe = {
331
- getFileList: he,
332
- getUrl: fe
333
- }, ge = async (s) => {
334
- try {
335
- const e = /^(https?:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;
336
- if (e.test(s)) {
337
- const t = s.replace(e, (r, n) => `${n}package.json`);
338
- return await j.get(t);
339
- } else
340
- throw new Error(`${s} 不是正确的url`);
341
- } catch (e) {
342
- throw e;
343
- }
344
- }, we = (s, e) => {
345
- var t, r;
346
- return ((t = s.dependencies) == null ? void 0 : t[e]) || ((r = s.devDependencies) == null ? void 0 : r[e]);
347
- }, F = async (s, e, t) => {
348
- if (!e.match(/\d+(.\d+)?(.\d+)?/))
349
- throw new Error(`${s} version ${e} is not valid`);
350
- const n = await S[t].getFileList(s, e), c = me(n, s);
351
- if (!c)
352
- throw new ee({
353
- packageName: s,
354
- version: e,
355
- cdn: t
356
- });
357
- return S[t].getUrl(s, n.version, c);
358
- }, me = ({ fileList: s }, e) => {
359
- var c, d;
360
- let t = [
361
- `umd/${e}.production.min.js`,
362
- /umd\/.+?\.production\.min\.js$/,
363
- /dist\/.+?\.production\.min\.js$/,
364
- /dist\/.+?\.umd\.min\.js$/,
365
- `dist/${e}.prod.min.js`,
366
- /dist\/.+?\.global.prod.min.js/,
367
- `dist/${e}.min.js`,
368
- /.+?\.global.prod.min.js/,
369
- /.+?.global.prod.js/,
370
- /lib\/.+?\.min\.js$/,
371
- /dist\/.+?\.min\.js$/,
372
- /index\.min\.js$/,
373
- /index\.js$/,
374
- /\.min\.js$/,
375
- /\.js$/
376
- ];
377
- const r = ["runtime", "compiler", ".esm", ".cjs", "development"].filter((i) => !e.includes(i));
378
- let n = "";
379
- for (let i of t)
380
- if (i instanceof RegExp ? n = ((c = s.find((o) => i.test(o.name) && !r.some((u) => o.name.includes(u)))) == null ? void 0 : c.name) || "" : n = ((d = s.find((o) => o.name.includes(i) && !r.some((u) => o.name.includes(u)))) == null ? void 0 : d.name) || "", n)
381
- break;
382
- return n;
383
- }, S = {
384
- jsdelivr: ue,
385
- bootcdn: ce,
386
- cdnjs: ae,
387
- unpkg: pe
388
- };
389
- function $e(s, e) {
390
- const t = s.replace(/^\D/, "").split("."), r = e.replace(/^\D/, "").split("."), n = Math.max(t.length, r.length);
391
- for (; t.length < n; )
392
- t.push("0");
393
- for (; r.length < n; )
394
- r.push("0");
395
- for (let c = 0; c < n; c++) {
396
- const d = parseInt(t[c], 10), i = parseInt(r[c], 10);
397
- if (d > i)
398
- return 1;
399
- if (d < i)
400
- return -1;
401
- }
402
- return 0;
403
- }
404
- function _(s, e) {
405
- for (let t in e)
406
- Object.prototype.hasOwnProperty.call(e, t) && (s[t] ? $e(s[t], e[t]) === -1 && (s[t] = e[t]) : s[t] = e[t]);
407
- return s;
408
- }
409
- async function R({
410
- external: s,
411
- packageData: e,
412
- customScript: t,
413
- defaultCdns: r
414
- }) {
415
- let n = [], c = !1, d = [];
416
- const i = await A();
417
- return await Promise.all(
418
- s.map(async (o) => {
419
- const u = we(e, o);
420
- if (t[o])
421
- return {
422
- urls: [t[o]],
423
- key: o
424
- };
425
- if (!u)
426
- return n.push(o), {
427
- urls: [],
428
- key: o
429
- };
430
- const p = i.getCdnCache(o, u);
431
- if (p) {
432
- const h = new Set(r), w = /* @__PURE__ */ new Map(), m = p.filter((a, l) => {
433
- if (h.has(a.cdnName) && a.success)
434
- return h.delete(a.cdnName), !0;
435
- !a.success && a.error === L.noFound ? h.delete(a.cdnName) : w.set(a.cdnName, l);
436
- }).map((a) => a.url);
437
- if (h.size > 0) {
438
- const a = await Promise.allSettled(
439
- [...h].map(async (l) => ({
440
- cdnName: l,
441
- success: !0,
442
- url: await F(o, u, l)
443
- }))
444
- ).then((l) => l.filter(($) => {
445
- if ($.status === "fulfilled")
446
- return m.push($.value.url), !0;
447
- d.push($.reason);
448
- }));
449
- a.length > 0 && (a.forEach((l) => {
450
- const $ = w.get(l.value.cdnName);
451
- $ !== void 0 ? p[$] = l.value : p.push(l.value);
452
- }), i.setCdnCache(o, u, p), c = !0);
453
- }
454
- return {
455
- urls: m,
456
- version: u,
457
- key: o
458
- };
459
- } else {
460
- c = !0, console.log(`从网络获取${o}${u}的cdn地址`);
461
- const h = await Promise.allSettled(
462
- r.map(async (a) => ({
463
- cdnName: a,
464
- success: !0,
465
- url: await F(o, u, a)
466
- }))
467
- ).then((a) => a.map((l) => {
468
- if (l.status === "fulfilled")
469
- return l.value;
470
- if (d.push(l.reason), l.reason instanceof y || l.reason instanceof k)
471
- return {
472
- cdnName: l.reason.cdn,
473
- success: !1,
474
- error: l.reason instanceof y ? L.NetworkError : L.noFound
475
- };
476
- }).filter((l) => !!l)), w = h.filter((a) => a.success).map(
477
- (a) => a.url
478
- );
479
- if (w.length === 0)
480
- throw new Error(`
481
- ${d.map((a) => a.message).join(`
482
- `)}获取${o} ${u}的cdn地址失败`);
483
- const m = {
484
- urls: w,
485
- version: u,
486
- key: o
487
- };
488
- return i.setCdnCache(o, u, h), m;
489
- }
490
- })
491
- ).then((o) => (c && i.save(), {
492
- urls: o,
493
- noVersionPackages: n,
494
- errorList: d
495
- }));
496
- }
497
- const ye = async ({
498
- packageVersionInfo: s
499
- }) => {
500
- const e = { dependencies: {} };
501
- let t = !1;
502
- const r = await A(), n = [];
503
- return await Promise.allSettled(
504
- s.map(async (c) => {
505
- if (!c)
506
- return;
507
- const { urls: d } = c, i = d[0];
508
- if (!i)
509
- return;
510
- const o = c.version || i, u = r.getPackageDependencies(c.key, o);
511
- if (u)
512
- return _(e.dependencies, u.dependencies);
513
- const p = await ge(i);
514
- r.setPackageDependencies(c.key, o, {
515
- dependencies: p.dependencies
516
- }), t = !0, _(e.dependencies, p.dependencies);
517
- })
518
- ).then((c) => (t && r.save(), c.forEach((d) => {
519
- d.status === "rejected" && n.push(d.reason);
520
- }), {
521
- urlPackageJsonRes: e,
522
- errorList: n
523
- }));
524
- }, H = "vite-add-cdn-script";
525
- class ke {
526
- constructor() {
527
- // 打印记录
528
- f(this, "logList", []);
529
- }
530
- // 打印方法
531
- log(e) {
532
- this.logList.push({
533
- type: "log",
534
- message: e
535
- });
536
- }
537
- warn(e) {
538
- this.logList.push({
539
- type: "warn",
540
- message: e
541
- });
542
- }
543
- error(e) {
544
- this.logList.push({
545
- type: "error",
546
- message: e
547
- });
548
- }
549
- info(e) {
550
- this.logList.push({
551
- type: "info",
552
- message: e
553
- });
554
- }
555
- // 打印全部
556
- consoleAll() {
557
- console.log(""), this.logList.forEach((e) => {
558
- console[e.type](`${H} ${e.message}`);
559
- });
560
- }
561
- addMessageList(e, t) {
562
- t.forEach((r) => {
563
- this.logList.push({
564
- type: e,
565
- message: r.toString()
566
- });
567
- });
568
- }
569
- // 清除打印记录
570
- clear() {
571
- this.logList = [];
572
- }
573
- }
574
- var q = /* @__PURE__ */ ((s) => (s.PRE = "pre", s.POST = "post", s))(q || {});
575
- function je(s) {
576
- let e = "";
577
- const t = {};
578
- return s.forEach((n) => {
579
- if (!n)
580
- return;
581
- const { urls: c, key: d } = n;
582
- t[d] = c;
583
- const i = c[0];
584
- e += `<script src="${i}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${d}"><\/script>
585
- `;
586
- }), e = `<script>
587
- function errorCDN(e) {
588
- const packNameUrl = JSON.parse('${JSON.stringify(t)}');
589
- const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
590
- const key = e.getAttribute("data-key");
591
- const curPackNameUrl = packNameUrl[key]
592
- if(nextCur>=curPackNameUrl.length){return;}
593
- // 新的cdn链接
594
- const url = curPackNameUrl[nextCur]
595
- // 克隆原标签
596
- const tagName = e.tagName
597
- const cdnDOM = document.createElement(tagName);
598
- cdnDOM.setAttribute(tagName === 'SCRIPT' ?'src' : 'href', url);
599
- Object.keys(e.dataset).forEach(_key => {
600
- cdnDOM.setAttribute('data-'+_key, e.dataset[_key]);
601
- })
602
- cdnDOM.setAttribute("data-cur", nextCur.toString());
603
- cdnDOM.setAttribute("onerror", "errorCDN(this)");
604
- document.head.appendChild(cdnDOM);
605
- e.remove();
606
- }
607
- <\/script>`.replace(/^\s*\/\/.*?$/gm, "") + e, e;
608
- }
609
- function De(s) {
610
- const { customScript: e = {}, defaultCdns: t = ["jsdelivr", "unpkg"] } = s;
611
- let r;
1
+ import l from "cdn-script-core";
2
+ var d = /* @__PURE__ */ ((e) => (e.PRE = "pre", e.POST = "post", e))(d || {});
3
+ const s = "vite-add-cdn-script";
4
+ function f(e) {
5
+ const { customScript: p = {}, defaultCdns: t = ["jsdelivr", "unpkg"] } = e;
6
+ let o;
612
7
  return {
613
- name: H,
614
- enforce: q.PRE,
8
+ name: s,
9
+ enforce: d.PRE,
615
10
  apply: "build",
616
- config(n) {
617
- r = n;
11
+ config(r) {
12
+ o = r;
618
13
  },
619
- async transformIndexHtml(n) {
620
- var i, o;
14
+ async transformIndexHtml(r) {
15
+ var c, i;
621
16
  if (!t || t.length === 0)
622
17
  throw new Error("defaultCdns不能为空");
623
- let c = new ke();
624
- const d = M.resolve(process.cwd(), "package.json");
18
+ const a = (i = (c = o.build) == null ? void 0 : c.rollupOptions) == null ? void 0 : i.external;
19
+ if (!a)
20
+ return r;
625
21
  try {
626
- const u = P.readFileSync(d, "utf-8"), p = JSON.parse(u), h = (o = (i = r.build) == null ? void 0 : i.rollupOptions) == null ? void 0 : o.external;
627
- if (!h)
628
- return n;
629
- let w = [];
630
- if (typeof h == "string")
631
- w = [h];
632
- else if (Array.isArray(h))
633
- w = h.filter((v) => typeof v == "string");
634
- else if (typeof h == "object")
635
- return n;
636
- const {
637
- urls: m,
638
- noVersionPackages: a,
639
- errorList: l
640
- } = await R({
641
- external: w,
642
- packageData: p,
643
- customScript: e,
22
+ const n = await l({
23
+ libName: s,
24
+ customScript: p,
25
+ external: a,
644
26
  defaultCdns: t
645
27
  });
646
- if (c.addMessageList("warn", l), a.length > 0) {
647
- const { urlPackageJsonRes: v, errorList: G } = await ye({
648
- packageVersionInfo: m
649
- });
650
- c.addMessageList("warn", G);
651
- const {
652
- urls: z,
653
- noVersionPackages: U,
654
- errorList: B
655
- } = await R({
656
- external: a,
657
- packageData: v,
658
- customScript: e,
659
- defaultCdns: t
660
- });
661
- if (c.addMessageList("warn", B), z.map((x) => {
662
- var E;
663
- if (!x)
664
- return;
665
- const { urls: K, key: W } = x;
666
- (E = m.find((D) => (D == null ? void 0 : D.key) === W)) == null || E.urls.push(...K);
667
- }), U.length > 0)
668
- throw console.error(`找不到${U.join(",")}的版本`), new Error(`找不到${U.join(",")}的版本`);
669
- }
670
- c.consoleAll();
671
- const $ = je(m);
672
- return n = n.replace("</head>", `${$}</head>`), n;
673
- } catch (u) {
674
- c.consoleAll(), console.error("vite-add-cdn-script error:", u.message), process.exit(1);
28
+ return r = r.replace("</head>", `${n}</head>`), r;
29
+ } catch (n) {
30
+ console.error("vite-add-cdn-script error:", n.message), process.exit(1);
675
31
  }
676
32
  }
677
33
  };
678
34
  }
679
35
  export {
680
- De as default
36
+ f as default
681
37
  };
@@ -1,25 +1 @@
1
- (function(h,f){typeof exports=="object"&&typeof module<"u"?module.exports=f(require("node:path"),require("node:fs"),require("node-fetch"),require("semver")):typeof define=="function"&&define.amd?define(["node:path","node:fs","node-fetch","semver"],f):(h=typeof globalThis<"u"?globalThis:h||self,h.index=f(h.path,h.fs,h.fetch,h.semver))})(this,function(h,f,y,F){"use strict";var ye=Object.defineProperty;var ke=(h,f,y)=>f in h?ye(h,f,{enumerable:!0,configurable:!0,writable:!0,value:y}):h[f]=y;var g=(h,f,y)=>(ke(h,typeof f!="symbol"?f+"":f,y),y);var v=(s=>(s.noFound="noFound",s.NetworkError="networkError",s))(v||{});class G{constructor(){g(this,"cdnCache",{packageDependencies:{},cdnsUrl:{}});g(this,"cdnCachePath","");this.cdnCachePath=h.resolve(process.cwd(),"./.cdn-cache.json")}async init(){try{const e=await f.readFileSync(this.cdnCachePath,"utf-8");this.cdnCache=JSON.parse(e)}catch{console.log("cdn缓存文件不存在,创建缓存文件"),this.cdnCache={packageDependencies:{},cdnsUrl:{}},await f.writeFileSync(this.cdnCachePath,"","utf-8")}}getCdnCache(e,t){var n;return(n=this.cdnCache.cdnsUrl[e])==null?void 0:n[t]}setCdnCache(e,t,n){this.cdnCache.cdnsUrl[e]?this.cdnCache.cdnsUrl[e][t]=n:this.cdnCache.cdnsUrl[e]={[t]:n}}async save(){await f.writeFileSync(this.cdnCachePath,JSON.stringify(this.cdnCache),"utf-8")}getPackageDependencies(e,t){var n;return(n=this.cdnCache.packageDependencies[e])==null?void 0:n[t]}setPackageDependencies(e,t,n){this.cdnCache.packageDependencies[e]?this.cdnCache.packageDependencies[e][t]=n:this.cdnCache.packageDependencies[e]={[t]:n}}}let U;const S=async()=>(U||(U=new G,await U.init()),U);class w extends Error{constructor(e){super(e),this.name="NetworkError"}}class k extends w{constructor({packageName:t,version:n,cdn:r}){super(`${r} ${t}@${n} 网络请求失败`);g(this,"cdn");g(this,"packageName");g(this,"version");this.name="PackageNetworkError",this.cdn=r,this.packageName=t,this.version=n}getErrorInfo(){return{cdn:this.cdn,packageName:this.packageName,version:this.version}}}class j extends Error{constructor({packageName:t,version:n,cdn:r}){super(`${r}上没有${t}@${n}的版本`);g(this,"cdn");g(this,"packageName");g(this,"version");this.name="NoVersionError",this.cdn=r,this.packageName=t,this.version=n}getErrorInfo(){return{cdn:this.cdn,packageName:this.packageName,version:this.version}}}class z extends Error{constructor({packageName:e,version:t,cdn:n}){super(`在 ${n} 中找不到 ${e}@${t} 文件,请检查包名或版本号`),this.name="GetFileListError"}}class B{constructor(e){g(this,"_max");g(this,"_count");g(this,"_taskQueue");this._max=e||5,this._count=0,this._taskQueue=[]}call(e,...t){return new Promise((n,r)=>{const c=this._createTask(e,t,n,r);this._count>=this._max?this._taskQueue.push(c):c()})}_createTask(e,t,n,r){return()=>{e(...t).then(n).catch(r).finally(()=>{this._count--,this._taskQueue.length&&this._taskQueue.shift()()}),this._count++}}}const b=new B(5),_=async s=>{try{const e=await y(s,{method:"HEAD",redirect:"manual"});return e.status>=300&&e.status<400?await _(e.headers.get("location")||""):s}catch(e){throw new w(e.message)}},K={get:async s=>{try{const e=await y(s);if(e.ok){const t=e.headers.get("content-type"),n=await e.text();return t&&t.includes("application/json")?JSON.parse(n):n}else throw new w(`请求失败,状态码:${e.status}`)}catch(e){throw new w(e.message)}}},L={get:b.call.bind(b,K.get)},W={getFileList:async(s,e)=>{try{const t=await L.get(`https://api.bootcdn.cn/libraries/${s}`);if(t.length===0)throw new j({packageName:s,version:e,cdn:"bootcdn"});const n=t[0],c=n.assets.reverse().find(i=>{if(F.satisfies(i.version,e))return!0});if(!c)throw new j({packageName:s,version:e,cdn:"bootcdn"});return{fileList:c.files.map(i=>({name:"/"+i})),recommendFileName:n.filename,version:c.version}}catch(t){throw t instanceof w?new k({packageName:s,version:e,cdn:"bootcdn"}):t}},getUrl:(s,e,t)=>`https://cdn.bootcdn.net/ajax/libs/${s}/${e}${t}`};async function R(s,e,t=!1){try{if(!t&&e.match(/^\D/)){const r=await Y(s,e);for(let c of r)if(F.satisfies(c,e))return R(s,c,!0);throw new j({packageName:s,version:e,cdn:"cdnjs"})}const n=await L.get(`https://api.cdnjs.com/libraries/${s}/${e}`);if(n.error)throw new j({packageName:s,version:e,cdn:"cdnjs"});return{fileList:n.rawFiles.map(r=>({name:"/"+r})),version:e}}catch(n){throw n instanceof w?new k({packageName:s,version:e,cdn:"cdnjs"}):n}}const X=(s,e,t)=>`https://cdnjs.cloudflare.com/ajax/libs/${s}/${e}${t}`,Y=async(s,e)=>{try{return(await L.get(`https://api.cdnjs.com/libraries/${s}?fields=versions`)).versions}catch(t){throw t instanceof w?new k({packageName:s,version:e,cdn:"cdnjs"}):t}},Z={getFileList:R,getUrl:X},M=(s,e="")=>s.reduce((t,n)=>(n.type==="file"?t.push({name:`${e}/${n.name}`}):n.files&&t.push(...M(n.files,`${e}/${n.name}`)),t),[]);async function O(s,e,t=!1){try{if(!t&&e.match(/^\D/)){const r=await te(s,e);if(typeof r=="string")return O(s,r,!0);throw new j({packageName:s,version:e,cdn:"jsdelivr"})}const n=await L.get(`https://data.jsdelivr.com/v1/packages/npm/${s}@${e}`);if(n.status)throw new j({packageName:s,version:e,cdn:"jsdelivr"});return{fileList:M(n.files),version:e}}catch(n){throw n instanceof w?new k({packageName:s,version:e,cdn:"jsdelivr"}):n}}const ee=(s,e,t)=>`https://cdn.jsdelivr.net/npm/${s}@${e}${t}`,te=async(s,e)=>{try{return(await L.get(`https://data.jsdelivr.com/v1/packages/npm/${s}/resolved?specifier=${e}`)).version}catch(t){throw t instanceof w?new k({packageName:s,version:e,cdn:"jsdelivr"}):t}},se={getFileList:O,getUrl:ee},V=s=>s.reduce((e,t)=>(t.type==="file"?e.push({name:t.path}):t.files&&e.push(...V(t.files)),e),[]);async function ne(s,e){var t;try{const r=(t=(await _(`https://unpkg.com/${s}@${e}/?meta`)).match(new RegExp("(?<=@)\\d+\\.\\d+\\.\\d+(?=\\/\\?meta)")))==null?void 0:t[0];if(r){const c=await L.get(`https://unpkg.com/${s}@${r}/?meta`);return{fileList:V(c.files||[]),version:r}}else throw new j({packageName:s,version:e,cdn:"unpkg"})}catch(n){throw n instanceof w?new k({packageName:s,version:e,cdn:"unpkg"}):n}}function re(s,e,t){return`https://unpkg.com/${s}@${e}${t}`}const ce={getFileList:ne,getUrl:re},oe=async s=>{try{const e=/^(https?:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;if(e.test(s)){const t=s.replace(e,(n,r)=>`${r}package.json`);return await L.get(t)}else throw new Error(`${s} 不是正确的url`)}catch(e){throw e}},ie=(s,e)=>{var t,n;return((t=s.dependencies)==null?void 0:t[e])||((n=s.devDependencies)==null?void 0:n[e])},A=async(s,e,t)=>{if(!e.match(/\d+(.\d+)?(.\d+)?/))throw new Error(`${s} version ${e} is not valid`);const r=await J[t].getFileList(s,e),c=ae(r,s);if(!c)throw new z({packageName:s,version:e,cdn:t});return J[t].getUrl(s,r.version,c)},ae=({fileList:s},e)=>{var c,d;let t=[`umd/${e}.production.min.js`,/umd\/.+?\.production\.min\.js$/,/dist\/.+?\.production\.min\.js$/,/dist\/.+?\.umd\.min\.js$/,`dist/${e}.prod.min.js`,/dist\/.+?\.global.prod.min.js/,`dist/${e}.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(i=>!e.includes(i));let r="";for(let i of t)if(i instanceof RegExp?r=((c=s.find(o=>i.test(o.name)&&!n.some(u=>o.name.includes(u))))==null?void 0:c.name)||"":r=((d=s.find(o=>o.name.includes(i)&&!n.some(u=>o.name.includes(u))))==null?void 0:d.name)||"",r)break;return r},J={jsdelivr:se,bootcdn:W,cdnjs:Z,unpkg:ce};function le(s,e){const t=s.replace(/^\D/,"").split("."),n=e.replace(/^\D/,"").split("."),r=Math.max(t.length,n.length);for(;t.length<r;)t.push("0");for(;n.length<r;)n.push("0");for(let c=0;c<r;c++){const d=parseInt(t[c],10),i=parseInt(n[c],10);if(d>i)return 1;if(d<i)return-1}return 0}function I(s,e){for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&(s[t]?le(s[t],e[t])===-1&&(s[t]=e[t]):s[t]=e[t]);return s}async function N({external:s,packageData:e,customScript:t,defaultCdns:n}){let r=[],c=!1,d=[];const i=await S();return await Promise.all(s.map(async o=>{const u=ie(e,o);if(t[o])return{urls:[t[o]],key:o};if(!u)return r.push(o),{urls:[],key:o};const $=i.getCdnCache(o,u);if($){const p=new Set(n),m=new Map,C=$.filter((a,l)=>{if(p.has(a.cdnName)&&a.success)return p.delete(a.cdnName),!0;!a.success&&a.error===v.noFound?p.delete(a.cdnName):m.set(a.cdnName,l)}).map(a=>a.url);if(p.size>0){const a=await Promise.allSettled([...p].map(async l=>({cdnName:l,success:!0,url:await A(o,u,l)}))).then(l=>l.filter(P=>{if(P.status==="fulfilled")return C.push(P.value.url),!0;d.push(P.reason)}));a.length>0&&(a.forEach(l=>{const P=m.get(l.value.cdnName);P!==void 0?$[P]=l.value:$.push(l.value)}),i.setCdnCache(o,u,$),c=!0)}return{urls:C,version:u,key:o}}else{c=!0,console.log(`从网络获取${o}${u}的cdn地址`);const p=await Promise.allSettled(n.map(async a=>({cdnName:a,success:!0,url:await A(o,u,a)}))).then(a=>a.map(l=>{if(l.status==="fulfilled")return l.value;if(d.push(l.reason),l.reason instanceof k||l.reason instanceof j)return{cdnName:l.reason.cdn,success:!1,error:l.reason instanceof k?v.NetworkError:v.noFound}}).filter(l=>!!l)),m=p.filter(a=>a.success).map(a=>a.url);if(m.length===0)throw new Error(`
2
- ${d.map(a=>a.message).join(`
3
- `)}获取${o} ${u}的cdn地址失败`);const C={urls:m,version:u,key:o};return i.setCdnCache(o,u,p),C}})).then(o=>(c&&i.save(),{urls:o,noVersionPackages:r,errorList:d}))}const de=async({packageVersionInfo:s})=>{const e={dependencies:{}};let t=!1;const n=await S(),r=[];return await Promise.allSettled(s.map(async c=>{if(!c)return;const{urls:d}=c,i=d[0];if(!i)return;const o=c.version||i,u=n.getPackageDependencies(c.key,o);if(u)return I(e.dependencies,u.dependencies);const $=await oe(i);n.setPackageDependencies(c.key,o,{dependencies:$.dependencies}),t=!0,I(e.dependencies,$.dependencies)})).then(c=>(t&&n.save(),c.forEach(d=>{d.status==="rejected"&&r.push(d.reason)}),{urlPackageJsonRes:e,errorList:r}))},q="vite-add-cdn-script";class ue{constructor(){g(this,"logList",[])}log(e){this.logList.push({type:"log",message:e})}warn(e){this.logList.push({type:"warn",message:e})}error(e){this.logList.push({type:"error",message:e})}info(e){this.logList.push({type:"info",message:e})}consoleAll(){console.log(""),this.logList.forEach(e=>{console[e.type](`${q} ${e.message}`)})}addMessageList(e,t){t.forEach(n=>{this.logList.push({type:e,message:n.toString()})})}clear(){this.logList=[]}}var T=(s=>(s.PRE="pre",s.POST="post",s))(T||{});function he(s){let e="";const t={};return s.forEach(r=>{if(!r)return;const{urls:c,key:d}=r;t[d]=c;const i=c[0];e+=`<script src="${i}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${d}"><\/script>
4
- `}),e=`<script>
5
- function errorCDN(e) {
6
- const packNameUrl = JSON.parse('${JSON.stringify(t)}');
7
- const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
8
- const key = e.getAttribute("data-key");
9
- const curPackNameUrl = packNameUrl[key]
10
- if(nextCur>=curPackNameUrl.length){return;}
11
- // 新的cdn链接
12
- const url = curPackNameUrl[nextCur]
13
- // 克隆原标签
14
- const tagName = e.tagName
15
- const cdnDOM = document.createElement(tagName);
16
- cdnDOM.setAttribute(tagName === 'SCRIPT' ?'src' : 'href', url);
17
- Object.keys(e.dataset).forEach(_key => {
18
- cdnDOM.setAttribute('data-'+_key, e.dataset[_key]);
19
- })
20
- cdnDOM.setAttribute("data-cur", nextCur.toString());
21
- cdnDOM.setAttribute("onerror", "errorCDN(this)");
22
- document.head.appendChild(cdnDOM);
23
- e.remove();
24
- }
25
- <\/script>`.replace(/^\s*\/\/.*?$/gm,"")+e,e}function fe(s){const{customScript:e={},defaultCdns:t=["jsdelivr","unpkg"]}=s;let n;return{name:q,enforce:T.PRE,apply:"build",config(r){n=r},async transformIndexHtml(r){var i,o;if(!t||t.length===0)throw new Error("defaultCdns不能为空");let c=new ue;const d=h.resolve(process.cwd(),"package.json");try{const u=f.readFileSync(d,"utf-8"),$=JSON.parse(u),p=(o=(i=n.build)==null?void 0:i.rollupOptions)==null?void 0:o.external;if(!p)return r;let m=[];if(typeof p=="string")m=[p];else if(Array.isArray(p))m=p.filter(x=>typeof x=="string");else if(typeof p=="object")return r;const{urls:C,noVersionPackages:a,errorList:l}=await N({external:m,packageData:$,customScript:e,defaultCdns:t});if(c.addMessageList("warn",l),a.length>0){const{urlPackageJsonRes:x,errorList:pe}=await de({packageVersionInfo:C});c.addMessageList("warn",pe);const{urls:ge,noVersionPackages:D,errorList:we}=await N({external:a,packageData:x,customScript:e,defaultCdns:t});if(c.addMessageList("warn",we),ge.map(Q=>{var H;if(!Q)return;const{urls:$e,key:me}=Q;(H=C.find(E=>(E==null?void 0:E.key)===me))==null||H.urls.push(...$e)}),D.length>0)throw console.error(`找不到${D.join(",")}的版本`),new Error(`找不到${D.join(",")}的版本`)}c.consoleAll();const P=he(C);return r=r.replace("</head>",`${P}</head>`),r}catch(u){c.consoleAll(),console.error("vite-add-cdn-script error:",u.message),process.exit(1)}}}}return fe});
1
+ (function(e,r){typeof exports=="object"&&typeof module<"u"?module.exports=r(require("cdn-script-core")):typeof define=="function"&&define.amd?define(["cdn-script-core"],r):(e=typeof globalThis<"u"?globalThis:e||self,e.index=r(e.getExternalScript))})(this,function(e){"use strict";var r=(n=>(n.PRE="pre",n.POST="post",n))(r||{});const c="vite-add-cdn-script";function f(n){const{customScript:a={},defaultCdns:i=["jsdelivr","unpkg"]}=n;let o;return{name:c,enforce:r.PRE,apply:"build",config(t){o=t},async transformIndexHtml(t){var p,u;if(!i||i.length===0)throw new Error("defaultCdns不能为空");const s=(u=(p=o.build)==null?void 0:p.rollupOptions)==null?void 0:u.external;if(!s)return t;try{const d=await e({libName:c,customScript:a,external:s,defaultCdns:i});return t=t.replace("</head>",`${d}</head>`),t}catch(d){console.error("vite-add-cdn-script error:",d.message),process.exit(1)}}}}return f});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-add-cdn-script",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "keywords": [
5
5
  "vite",
6
6
  "cdn",
@@ -26,7 +26,7 @@
26
26
  "exports": {
27
27
  "types": "./index.d.ts",
28
28
  "import": "./dist/index.js",
29
- "require": "./dist/index.js"
29
+ "require": "./dist/index.umd.cjs"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@jest/globals": "^29.7.0",
@@ -52,13 +52,12 @@
52
52
  "registry": "https://registry.npmjs.org/"
53
53
  },
54
54
  "dependencies": {
55
- "node-fetch": "2",
56
- "semver": "^7.6.2"
55
+ "cdn-script-core": "1.0.1"
57
56
  },
58
57
  "scripts": {
59
58
  "dev": "vite",
60
59
  "build:page": "tsc && cross-env BUILD_MODE=page vite build",
61
60
  "build": "tsc && cross-env BUILD_MODE=lib vite build",
62
- "test": "jest"
61
+ "test": ""
63
62
  }
64
63
  }