vite-add-cdn-script 0.0.11 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -1,562 +1,37 @@
1
- var q = Object.defineProperty;
2
- var G = (r, t, e) => t in r ? q(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
3
- var g = (r, t, e) => (G(r, typeof t != "symbol" ? t + "" : t, e), e);
4
- import A from "node:path";
5
- import E from "node:fs";
6
- import O from "node-fetch";
7
- import V from "semver";
8
- class B {
9
- constructor() {
10
- g(this, "cdnCache", {});
11
- g(this, "cdnCachePath", "");
12
- this.cdnCachePath = A.resolve(process.cwd(), "./.cdn-cache.json");
13
- }
14
- // 初始化cdn缓存
15
- async init() {
16
- try {
17
- const t = await E.readFileSync(this.cdnCachePath, "utf-8");
18
- this.cdnCache = JSON.parse(t);
19
- } catch {
20
- console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await E.writeFileSync(this.cdnCachePath, "", "utf-8");
21
- }
22
- }
23
- /**
24
- * 获取cdn缓存
25
- * @param packageName 包名
26
- * @param version 版本
27
- */
28
- getCdnCache(t, e) {
29
- var s;
30
- return (s = this.cdnCache[t]) == null ? void 0 : s[e];
31
- }
32
- /**
33
- * 设置cdn缓存
34
- * @param packageName 包名
35
- * @param version 版本
36
- * @param urls 地址列表
37
- */
38
- setCdnCache(t, e, s) {
39
- this.cdnCache[t] ? this.cdnCache[t][e] = s : this.cdnCache[t] = {
40
- [e]: s
41
- };
42
- }
43
- /**
44
- * 更新cdn缓存
45
- */
46
- async save() {
47
- await E.writeFileSync(this.cdnCachePath, JSON.stringify(this.cdnCache), "utf-8");
48
- }
49
- }
50
- let U;
51
- const z = async () => (U || (U = new B(), await U.init()), U);
52
- class u extends Error {
53
- constructor(t) {
54
- super(t), this.name = "NetworkError";
55
- }
56
- }
57
- class P extends u {
58
- constructor({ packageName: t, version: e, cdn: s }) {
59
- super(`${s} ${t}@${e} 网络请求失败`), this.name = "PackageNetworkError";
60
- }
61
- }
62
- class m extends Error {
63
- constructor({ packageName: t, version: e, cdn: s }) {
64
- super(`${s}上没有${t}@${e}的版本`), this.name = "NoVersionError";
65
- }
66
- }
67
- class K extends Error {
68
- constructor({ packageName: t, version: e, cdn: s }) {
69
- super(`在 ${s} 中找不到 ${t}@${e} 文件,请检查包名或版本号`), this.name = "GetFileListError";
70
- }
71
- }
72
- class N {
73
- constructor(t) {
74
- g(this, "_max");
75
- g(this, "_count");
76
- g(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 _ = new N(5), J = async (r) => {
109
- try {
110
- const t = await O(r, { method: "HEAD", redirect: "manual" });
111
- return t.status >= 300 && t.status < 400 ? await J(t.headers.get("location") || "") : r;
112
- } catch (t) {
113
- throw Promise.reject(new u(t.message));
114
- }
115
- }, W = {
116
- //get请求封装
117
- get: async (r) => {
118
- try {
119
- const t = await O(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
- }, $ = {
130
- get: _.call.bind(_, W.get)
131
- }, X = async (r, t) => {
132
- try {
133
- const e = await $.get(`https://api.bootcdn.cn/libraries/${r}`);
134
- if (e.length === 0)
135
- throw new m({
136
- packageName: r,
137
- version: t,
138
- cdn: "bootcdn"
139
- });
140
- const s = e[0], o = s.assets.reverse().find((c) => {
141
- if (V.satisfies(c.version, t))
142
- return !0;
143
- });
144
- if (!o)
145
- throw new m({
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 P({
155
- packageName: r,
156
- version: t,
157
- cdn: "unpkg"
158
- }) : e;
159
- }
160
- }, Y = (r, t, e) => `https://cdn.bootcdn.net/ajax/libs/${r}/${t}${e}`, Z = {
161
- getFileList: X,
162
- getUrl: Y
163
- };
164
- async function M(r, t, e = !1) {
165
- try {
166
- if (!e && t.match(/^\D/)) {
167
- const n = await et(r, t);
168
- for (let o of n)
169
- if (V.satisfies(o, t))
170
- return M(r, o, !0);
171
- throw new m({
172
- packageName: r,
173
- version: t,
174
- cdn: "cdnjs"
175
- });
176
- }
177
- const s = await $.get(`https://api.cdnjs.com/libraries/${r}/${t}`);
178
- if (s.error)
179
- throw new m({
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 P({
192
- packageName: r,
193
- version: t,
194
- cdn: "unpkg"
195
- }) : s;
196
- }
197
- }
198
- const tt = (r, t, e) => `https://cdnjs.cloudflare.com/ajax/libs/${r}/${t}${e}`, et = async (r, t) => {
199
- try {
200
- return (await $.get(`https://api.cdnjs.com/libraries/${r}?fields=versions`)).versions;
201
- } catch (e) {
202
- throw e instanceof u ? new P({
203
- packageName: r,
204
- version: t,
205
- cdn: "unpkg"
206
- }) : e;
207
- }
208
- }, rt = {
209
- getFileList: M,
210
- getUrl: tt
211
- }, I = (r, t = "") => r.reduce((e, s) => (s.type === "file" ? e.push({ name: `${t}/${s.name}` }) : s.files && e.push(...I(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 nt(r, t);
216
- if (typeof n == "string")
217
- return Q(r, n, !0);
218
- throw new m({
219
- packageName: r,
220
- version: t,
221
- cdn: "jsdelivr"
222
- });
223
- }
224
- const s = await $.get(`https://data.jsdelivr.com/v1/packages/npm/${r}@${t}`);
225
- if (s.status)
226
- throw new m({
227
- packageName: r,
228
- version: t,
229
- cdn: "jsdelivr"
230
- });
231
- return { fileList: I(s.files), version: t };
232
- } catch (s) {
233
- throw s instanceof u ? new P({
234
- packageName: r,
235
- version: t,
236
- cdn: "unpkg"
237
- }) : s;
238
- }
239
- }
240
- const st = (r, t, e) => `https://cdn.jsdelivr.net/npm/${r}@${t}${e}`, nt = async (r, t) => {
241
- try {
242
- return (await $.get(
243
- `https://data.jsdelivr.com/v1/packages/npm/${r}/resolved?specifier=${t}`
244
- )).version;
245
- } catch (e) {
246
- throw e instanceof u ? new P({
247
- packageName: r,
248
- version: t,
249
- cdn: "unpkg"
250
- }) : e;
251
- }
252
- }, ct = {
253
- getFileList: Q,
254
- // 拼接url
255
- getUrl: st
256
- }, T = (r) => r.reduce((t, e) => (e.type === "file" ? t.push({ name: e.path }) : e.files && t.push(...T(e.files)), t), []);
257
- async function ot(r, t) {
258
- var e;
259
- try {
260
- const n = (e = (await J(`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 $.get(`https://unpkg.com/${r}@${n}/?meta`);
263
- return { fileList: T(o.files || []), version: n };
264
- } else
265
- throw new m({
266
- packageName: r,
267
- version: t,
268
- cdn: "unpkg"
269
- });
270
- } catch (s) {
271
- throw s instanceof u ? new P({
272
- packageName: r,
273
- version: t,
274
- cdn: "unpkg"
275
- }) : s;
276
- }
277
- }
278
- function it(r, t, e) {
279
- return `https://unpkg.com/${r}@${t}${e}`;
280
- }
281
- const at = {
282
- getFileList: ot,
283
- getUrl: it
284
- }, lt = 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 $.get(e);
290
- } else
291
- throw new Error(`${r} 不是正确的url`);
292
- } catch (t) {
293
- throw t;
294
- }
295
- }, ut = (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
- }, dt = 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 D[e].getFileList(r, t), o = ht(n, r);
302
- if (!o)
303
- throw new K({
304
- packageName: r,
305
- version: t,
306
- cdn: e
307
- });
308
- return D[e].getUrl(r, n.version, o);
309
- }, ht = ({ fileList: r }, t) => {
310
- var o, a;
311
- let e = [
312
- `umd/${t}.production.min.js`,
313
- /umd\/.+?\.production\.min\.js$/,
314
- /dist\/.+?\.production\.min\.js$/,
315
- /dist\/.+?\.umd\.min\.js$/,
316
- `dist/${t}.prod.min.js`,
317
- /dist\/.+?\.global.prod.min.js/,
318
- `dist/${t}.min.js`,
319
- /.+?\.global.prod.min.js/,
320
- /.+?.global.prod.js/,
321
- /lib\/.+?\.min\.js$/,
322
- /dist\/.+?\.min\.js$/,
323
- /index\.min\.js$/,
324
- /index\.js$/,
325
- /\.min\.js$/,
326
- /\.js$/
327
- ];
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((f) => i.name.includes(f)))) == null ? void 0 : o.name) || "" : n = ((a = r.find((i) => i.name.includes(c) && !s.some((f) => i.name.includes(f)))) == null ? void 0 : a.name) || "", n)
332
- break;
333
- return n;
334
- }, D = {
335
- jsdelivr: ct,
336
- bootcdn: Z,
337
- cdnjs: rt,
338
- unpkg: at
339
- };
340
- function ft(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; )
343
- e.push("0");
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)
349
- return 1;
350
- if (a < c)
351
- return -1;
352
- }
353
- return 0;
354
- }
355
- function pt(r, t) {
356
- for (let e in t)
357
- Object.prototype.hasOwnProperty.call(t, e) && (r[e] ? ft(r[e], t[e]) === -1 && (r[e] = t[e]) : r[e] = t[e]);
358
- return r;
359
- }
360
- class wt {
361
- constructor() {
362
- // 打印记录
363
- g(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](`${H} ${t.message}`);
394
- });
395
- }
396
- // 清除打印记录
397
- clear() {
398
- this.logList = [];
399
- }
400
- }
401
- const H = "vite-add-cdn-script", b = new wt();
402
- async function R({
403
- external: r,
404
- packageData: t,
405
- customScript: e,
406
- defaultCdns: s
407
- }) {
408
- let n = [], o = !1;
409
- const a = await z();
410
- return await Promise.all(
411
- r.map(async (c) => {
412
- const i = ut(t, c);
413
- if (e[c])
414
- return {
415
- urls: [],
416
- key: c
417
- };
418
- if (!i)
419
- return n.push(c), {
420
- urls: [],
421
- key: c
422
- };
423
- const f = a.getCdnCache(c, i);
424
- if (f)
425
- return {
426
- urls: f,
427
- key: c
428
- };
429
- {
430
- o = !0, console.log(`从网络获取${c}${i}的cdn地址`);
431
- const d = await Promise.allSettled(
432
- s.map(async (j) => await dt(c, i, j))
433
- ).then((j) => j.filter((l) => {
434
- if (l.status === "fulfilled")
435
- return l.value, !0;
436
- b.warn(l.reason.toString());
437
- }).map((l) => l.value));
438
- if (d.length === 0)
439
- throw new Error(`获取${c} ${i}的cdn地址失败`);
440
- const y = {
441
- urls: d,
442
- key: c
443
- };
444
- return a.setCdnCache(c, i, y.urls), y;
445
- }
446
- })
447
- ).then((c) => (o && a.save(), {
448
- urls: c,
449
- noVersionPackages: n
450
- }));
451
- }
452
- function Pt(r) {
453
- const { customScript: t = {}, defaultCdns: e = ["jsdelivr", "unpkg"] } = r;
454
- let s;
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;
455
7
  return {
456
- name: H,
457
- enforce: "pre",
8
+ name: s,
9
+ enforce: d.PRE,
458
10
  apply: "build",
459
- config(n) {
460
- s = n;
11
+ config(r) {
12
+ o = r;
461
13
  },
462
- async transformIndexHtml(n) {
463
- var a, c;
464
- if (!e || e.length === 0)
14
+ async transformIndexHtml(r) {
15
+ var c, i;
16
+ if (!t || t.length === 0)
465
17
  throw new Error("defaultCdns不能为空");
466
- const o = A.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;
467
21
  try {
468
- const i = E.readFileSync(o, "utf-8"), f = JSON.parse(i), d = (c = (a = s.build) == null ? void 0 : a.rollupOptions) == null ? void 0 : c.external;
469
- if (!d)
470
- return n;
471
- let y = [];
472
- if (typeof d == "string")
473
- y = [d];
474
- else if (Array.isArray(d))
475
- y = d.filter((w) => typeof w == "string");
476
- else if (typeof d == "object")
477
- return n;
478
- const j = {};
479
- let l = "";
480
- const { urls: S, noVersionPackages: F } = await R({
481
- external: y,
482
- packageData: f,
483
- customScript: t,
484
- defaultCdns: e
22
+ const n = await l({
23
+ libName: s,
24
+ customScript: p,
25
+ external: a,
26
+ defaultCdns: t
485
27
  });
486
- if (F.length > 0) {
487
- const w = { dependencies: {} };
488
- await Promise.allSettled(
489
- S.map(async (h) => {
490
- if (!h)
491
- return;
492
- const { key: C, urls: v } = h, k = t[C] || v[0];
493
- if (!k)
494
- return;
495
- const x = await lt(k);
496
- pt(w.dependencies, x.dependencies);
497
- })
498
- ).then((h) => {
499
- h.forEach((C) => {
500
- C.status === "rejected" && b.warn(C.reason.toString());
501
- });
502
- });
503
- const { urls: L, noVersionPackages: p } = await R({
504
- external: F,
505
- packageData: w,
506
- customScript: t,
507
- defaultCdns: e
508
- });
509
- if (L.map((h) => {
510
- var k;
511
- if (!h)
512
- return;
513
- const { urls: C, key: v } = h;
514
- (k = S.find((x) => (x == null ? void 0 : x.key) === v)) == null || k.urls.push(...C);
515
- }), p.length > 0)
516
- throw console.error(`找不到${p.join(",")}的版本`), new Error(`找不到${p.join(",")}的版本`);
517
- }
518
- return b.consoleAll(), S.forEach((w) => {
519
- if (!w)
520
- return;
521
- const { urls: L, key: p } = w;
522
- if (t[p])
523
- l += t[p];
524
- else {
525
- j[p] = L;
526
- const h = L[0];
527
- l += `<script src="${h}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${p}"><\/script>
528
- `;
529
- }
530
- }), l = `<script>
531
- function errorCDN(e) {
532
- const packNameUrl = JSON.parse('${JSON.stringify(j)}');
533
- const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
534
-
535
- const key = e.getAttribute("data-key");
536
- const curPackNameUrl = packNameUrl[key]
537
- if(nextCur>=curPackNameUrl.length){return;}
538
- // 新的cdn链接
539
- const url = curPackNameUrl[nextCur]
540
- // 克隆原标签
541
- const tagName = e.tagName
542
- const cdnDOM = document.createElement(tagName);
543
- cdnDOM.setAttribute(tagName === 'SCRIPT' ?'src' : 'href', url);
544
- Object.keys(e.dataset).forEach(_key => {
545
- cdnDOM.setAttribute('data-'+_key, e.dataset[_key]);
546
- })
547
- cdnDOM.setAttribute("data-cur", nextCur.toString());
548
- cdnDOM.setAttribute("onerror", "errorCDN(this)");
549
- document.head.appendChild(cdnDOM);
550
- e.remove();
551
- }
552
- <\/script>` + l, n = n.replace("</head>", `${l}</head>`), n;
553
- } catch (i) {
554
- b.consoleAll(), console.error("vite-add-cdn-script error:", i.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);
555
31
  }
556
32
  }
557
33
  };
558
34
  }
559
35
  export {
560
- Pt as default,
561
- H as libName
36
+ f as default
562
37
  };
@@ -1,24 +1 @@
1
- (function(o,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):(o=typeof globalThis<"u"?globalThis:o||self,l(o.index={},o.path,o.fs,o.fetch,o.semver))})(this,function(o,l,h,O,R){"use strict";var pt=Object.defineProperty;var wt=(o,l,h)=>l in o?pt(o,l,{enumerable:!0,configurable:!0,writable:!0,value:h}):o[l]=h;var C=(o,l,h)=>(wt(o,typeof l!="symbol"?l+"":l,h),h);class G{constructor(){C(this,"cdnCache",{});C(this,"cdnCachePath","");this.cdnCachePath=l.resolve(process.cwd(),"./.cdn-cache.json")}async init(){try{const t=await h.readFileSync(this.cdnCachePath,"utf-8");this.cdnCache=JSON.parse(t)}catch{console.log("cdn缓存文件不存在,创建缓存文件"),this.cdnCache={},await h.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 h.writeFileSync(this.cdnCachePath,JSON.stringify(this.cdnCache),"utf-8")}}let b;const B=async()=>(b||(b=new G,await b.init()),b);class f extends Error{constructor(t){super(t),this.name="NetworkError"}}class P extends f{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 N extends Error{constructor({packageName:t,version:e,cdn:n}){super(`在 ${n} 中找不到 ${t}@${e} 文件,请检查包名或版本号`),this.name="GetFileListError"}}class z{constructor(t){C(this,"_max");C(this,"_count");C(this,"_taskQueue");this._max=t||5,this._count=0,this._taskQueue=[]}call(t,...e){return new Promise((n,s)=>{const c=this._createTask(t,e,n,s);this._count>=this._max?this._taskQueue.push(c):c()})}_createTask(t,e,n,s){return()=>{t(...e).then(n).catch(s).finally(()=>{this._count--,this._taskQueue.length&&this._taskQueue.shift()()}),this._count++}}}const A=new z(5),V=async r=>{try{const t=await O(r,{method:"HEAD",redirect:"manual"});return t.status>=300&&t.status<400?await V(t.headers.get("location")||""):r}catch(t){throw Promise.reject(new f(t.message))}},K={get:async r=>{try{const t=await O(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 f(`请求失败,状态码:${t.status}`)}catch(t){throw new f(t.message)}}},y={get:A.call.bind(A,K.get)},W={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],c=n.assets.reverse().find(i=>{if(R.satisfies(i.version,t))return!0});if(!c)throw new $({packageName:r,version:t,cdn:"bootcdn"});return{fileList:c.files.map(i=>({name:"/"+i})),recommendFileName:n.filename,version:c.version}}catch(e){throw e instanceof f?new P({packageName:r,version:t,cdn:"unpkg"}):e}},getUrl:(r,t,e)=>`https://cdn.bootcdn.net/ajax/libs/${r}/${t}${e}`};async function J(r,t,e=!1){try{if(!e&&t.match(/^\D/)){const s=await Y(r,t);for(let c of s)if(R.satisfies(c,t))return J(r,c,!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 f?new P({packageName:r,version:t,cdn:"unpkg"}):n}}const X=(r,t,e)=>`https://cdnjs.cloudflare.com/ajax/libs/${r}/${t}${e}`,Y=async(r,t)=>{try{return(await y.get(`https://api.cdnjs.com/libraries/${r}?fields=versions`)).versions}catch(e){throw e instanceof f?new P({packageName:r,version:t,cdn:"unpkg"}):e}},Z={getFileList:J,getUrl:X},M=(r,t="")=>r.reduce((e,n)=>(n.type==="file"?e.push({name:`${t}/${n.name}`}):n.files&&e.push(...M(n.files,`${t}/${n.name}`)),e),[]);async function I(r,t,e=!1){try{if(!e&&t.match(/^\D/)){const s=await et(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:M(n.files),version:t}}catch(n){throw n instanceof f?new P({packageName:r,version:t,cdn:"unpkg"}):n}}const tt=(r,t,e)=>`https://cdn.jsdelivr.net/npm/${r}@${t}${e}`,et=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 f?new P({packageName:r,version:t,cdn:"unpkg"}):e}},rt={getFileList:I,getUrl:tt},T=r=>r.reduce((t,e)=>(e.type==="file"?t.push({name:e.path}):e.files&&t.push(...T(e.files)),t),[]);async function nt(r,t){var e;try{const s=(e=(await V(`https://unpkg.com/${r}@${t}/?meta`)).match(new RegExp("(?<=@)\\d+\\.\\d+\\.\\d+(?=\\/\\?meta)")))==null?void 0:e[0];if(s){const c=await y.get(`https://unpkg.com/${r}@${s}/?meta`);return{fileList:T(c.files||[]),version:s}}else throw new $({packageName:r,version:t,cdn:"unpkg"})}catch(n){throw n instanceof f?new P({packageName:r,version:t,cdn:"unpkg"}):n}}function st(r,t,e){return`https://unpkg.com/${r}@${t}${e}`}const it={getFileList:nt,getUrl:st},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}},ot=(r,t)=>{var e,n;return((e=r.dependencies)==null?void 0:e[t])||((n=r.devDependencies)==null?void 0:n[t])},at=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),c=lt(s,r);if(!c)throw new N({packageName:r,version:t,cdn:e});return q[e].getUrl(r,s.version,c)},lt=({fileList:r},t)=>{var c,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(i=>!t.includes(i));let s="";for(let i of e)if(i instanceof RegExp?s=((c=r.find(a=>i.test(a.name)&&!n.some(g=>a.name.includes(g))))==null?void 0:c.name)||"":s=((u=r.find(a=>a.name.includes(i)&&!n.some(g=>a.name.includes(g))))==null?void 0:u.name)||"",s)break;return s},q={jsdelivr:rt,bootcdn:W,cdnjs:Z,unpkg:it};function ut(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 c=0;c<s;c++){const u=parseInt(e[c],10),i=parseInt(n[c],10);if(u>i)return 1;if(u<i)return-1}return 0}function dt(r,t){for(let e in t)Object.prototype.hasOwnProperty.call(t,e)&&(r[e]?ut(r[e],t[e])===-1&&(r[e]=t[e]):r[e]=t[e]);return r}class ht{constructor(){C(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](`${_} ${t.message}`)})}clear(){this.logList=[]}}const _="vite-add-cdn-script",v=new ht;async function Q({external:r,packageData:t,customScript:e,defaultCdns:n}){let s=[],c=!1;const u=await B();return await Promise.all(r.map(async i=>{const a=ot(t,i);if(e[i])return{urls:[],key:i};if(!a)return s.push(i),{urls:[],key:i};const g=u.getCdnCache(i,a);if(g)return{urls:g,key:i};{c=!0,console.log(`从网络获取${i}${a}的cdn地址`);const p=await Promise.allSettled(n.map(async x=>await at(i,a,x))).then(x=>x.filter(d=>{if(d.status==="fulfilled")return d.value,!0;v.warn(d.reason.toString())}).map(d=>d.value));if(p.length===0)throw new Error(`获取${i} ${a}的cdn地址失败`);const k={urls:p,key:i};return u.setCdnCache(i,a,k.urls),k}})).then(i=>(c&&u.save(),{urls:i,noVersionPackages:s}))}function ft(r){const{customScript:t={},defaultCdns:e=["jsdelivr","unpkg"]}=r;let n;return{name:_,enforce:"pre",apply:"build",config(s){n=s},async transformIndexHtml(s){var u,i;if(!e||e.length===0)throw new Error("defaultCdns不能为空");const c=l.resolve(process.cwd(),"package.json");try{const a=h.readFileSync(c,"utf-8"),g=JSON.parse(a),p=(i=(u=n.build)==null?void 0:u.rollupOptions)==null?void 0:i.external;if(!p)return s;let k=[];if(typeof p=="string")k=[p];else if(Array.isArray(p))k=p.filter(j=>typeof j=="string");else if(typeof p=="object")return s;const x={};let d="";const{urls:F,noVersionPackages:H}=await Q({external:k,packageData:g,customScript:t,defaultCdns:e});if(H.length>0){const j={dependencies:{}};await Promise.allSettled(F.map(async w=>{if(!w)return;const{key:L,urls:D}=w,U=t[L]||D[0];if(!U)return;const E=await ct(U);dt(j.dependencies,E.dependencies)})).then(w=>{w.forEach(L=>{L.status==="rejected"&&v.warn(L.reason.toString())})});const{urls:S,noVersionPackages:m}=await Q({external:H,packageData:j,customScript:t,defaultCdns:e});if(S.map(w=>{var U;if(!w)return;const{urls:L,key:D}=w;(U=F.find(E=>(E==null?void 0:E.key)===D))==null||U.urls.push(...L)}),m.length>0)throw console.error(`找不到${m.join(",")}的版本`),new Error(`找不到${m.join(",")}的版本`)}return v.consoleAll(),F.forEach(j=>{if(!j)return;const{urls:S,key:m}=j;if(t[m])d+=t[m];else{x[m]=S;const w=S[0];d+=`<script src="${w}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${m}"><\/script>
2
- `}}),d=`<script>
3
- function errorCDN(e) {
4
- const packNameUrl = JSON.parse('${JSON.stringify(x)}');
5
- const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
6
-
7
- const key = e.getAttribute("data-key");
8
- const curPackNameUrl = packNameUrl[key]
9
- if(nextCur>=curPackNameUrl.length){return;}
10
- // 新的cdn链接
11
- const url = curPackNameUrl[nextCur]
12
- // 克隆原标签
13
- const tagName = e.tagName
14
- const cdnDOM = document.createElement(tagName);
15
- cdnDOM.setAttribute(tagName === 'SCRIPT' ?'src' : 'href', url);
16
- Object.keys(e.dataset).forEach(_key => {
17
- cdnDOM.setAttribute('data-'+_key, e.dataset[_key]);
18
- })
19
- cdnDOM.setAttribute("data-cur", nextCur.toString());
20
- cdnDOM.setAttribute("onerror", "errorCDN(this)");
21
- document.head.appendChild(cdnDOM);
22
- e.remove();
23
- }
24
- <\/script>`+d,s=s.replace("</head>",`${d}</head>`),s}catch(a){v.consoleAll(),console.error("vite-add-cdn-script error:",a.message),process.exit(1)}}}}o.default=ft,o.libName=_,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
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": "0.0.11",
3
+ "version": "1.0.1",
4
4
  "keywords": [
5
5
  "vite",
6
6
  "cdn",
@@ -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.0"
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
  }