vite-add-cdn-script 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
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 | 重试次数 | number | 3 |
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,22 @@
1
1
  var D = Object.defineProperty;
2
2
  var F = (n, t, e) => t in n ? D(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
3
- var S = (n, t, e) => (F(n, typeof t != "symbol" ? t + "" : t, e), e);
4
- import O from "node:path";
5
- import y from "node:fs";
6
- import b from "node:https";
7
- class E {
3
+ var f = (n, t, e) => (F(n, typeof t != "symbol" ? t + "" : t, e), e);
4
+ import J from "node:path";
5
+ import j from "node:fs";
6
+ import E from "node:https";
7
+ class L {
8
8
  constructor() {
9
- S(this, "cdnCache", {});
10
- S(this, "cdnCachePath", "");
11
- this.cdnCachePath = O.resolve(process.cwd(), "./.cdn-cache.json");
9
+ f(this, "cdnCache", {});
10
+ f(this, "cdnCachePath", "");
11
+ this.cdnCachePath = J.resolve(process.cwd(), "./.cdn-cache.json");
12
12
  }
13
13
  // 初始化cdn缓存
14
14
  async init() {
15
15
  try {
16
- const t = await y.readFileSync(this.cdnCachePath, "utf-8");
16
+ const t = await j.readFileSync(this.cdnCachePath, "utf-8");
17
17
  this.cdnCache = JSON.parse(t);
18
18
  } catch {
19
- console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await y.writeFileSync(this.cdnCachePath, "", "utf-8");
19
+ console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await j.writeFileSync(this.cdnCachePath, "", "utf-8");
20
20
  }
21
21
  }
22
22
  /**
@@ -43,135 +43,171 @@ class E {
43
43
  * 更新cdn缓存
44
44
  */
45
45
  async save() {
46
- await y.writeFileSync(this.cdnCachePath, JSON.stringify(this.cdnCache), "utf-8");
46
+ await j.writeFileSync(this.cdnCachePath, JSON.stringify(this.cdnCache), "utf-8");
47
47
  }
48
48
  }
49
- let C;
50
- const L = async () => (C || (C = new E(), await C.init()), C), $ = {
49
+ let y;
50
+ const I = async () => (y || (y = new L(), await y.init()), y);
51
+ class N {
52
+ constructor(t) {
53
+ f(this, "_max");
54
+ f(this, "_count");
55
+ f(this, "_taskQueue");
56
+ this._max = t || 5, this._count = 0, this._taskQueue = [];
57
+ }
58
+ /**
59
+ * 请求封装
60
+ * @param caller 请求函数
61
+ * @param args 请求参数
62
+ * @returns {Promise<any>} 返回一个promise
63
+ */
64
+ call(t, ...e) {
65
+ return new Promise((r, s) => {
66
+ const c = this._createTask(t, e, r, s);
67
+ this._count >= this._max ? this._taskQueue.push(c) : c();
68
+ });
69
+ }
70
+ /**
71
+ * 创建一个任务
72
+ * @param caller 实际执行的函数
73
+ * @param args 执行函数的参数
74
+ * @param resolve
75
+ * @param reject
76
+ * @returns {Function} 返回一个任务函数
77
+ * @private
78
+ */
79
+ _createTask(t, e, r, s) {
80
+ return () => {
81
+ t(...e).then(r).catch(s).finally(() => {
82
+ this._count--, this._taskQueue.length && this._taskQueue.shift()();
83
+ }), this._count++;
84
+ };
85
+ }
86
+ }
87
+ const U = new N(5), R = {
51
88
  //get请求封装
52
89
  get: (n, t, e) => new Promise((r, s) => {
53
90
  try {
54
- b.get(n, (c) => {
55
- let o = "";
56
- c.on("data", (i) => {
57
- o += i;
91
+ E.get(n, (c) => {
92
+ let i = "";
93
+ c.on("data", (o) => {
94
+ i += o;
58
95
  }), c.on("end", () => {
59
- t == null || t(o), r(o);
96
+ t == null || t(i), r(i);
60
97
  });
98
+ }).on("error", function(c) {
99
+ e == null || e(c), s(c);
61
100
  });
62
101
  } catch (c) {
63
102
  e == null || e(c), s(c);
64
103
  }
65
104
  })
66
- }, N = async (n) => {
67
- const t = /^(https:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;
105
+ }, w = {
106
+ get: U.call.bind(U, R.get)
107
+ }, A = {
108
+ getFileList: (n, t) => new Promise((e, r) => {
109
+ w.get(
110
+ `https://api.bootcdn.cn/libraries/${n}`,
111
+ (s) => {
112
+ const c = JSON.parse(s);
113
+ if (c.length === 0) {
114
+ r(new Error(`${n} not found in bootcdn`));
115
+ return;
116
+ }
117
+ const i = c[0], a = i.assets.find((d) => d.version === t);
118
+ if (!a) {
119
+ r(new Error(`${n}@${t} not found in ${i.name}`));
120
+ return;
121
+ }
122
+ const l = a.files.map((d) => ({
123
+ name: "/" + d
124
+ }));
125
+ e({ fileList: l, recommendFileName: i.filename });
126
+ },
127
+ (s) => {
128
+ r(s);
129
+ }
130
+ );
131
+ }),
132
+ getUrl: (n, t, e) => `https://cdn.bootcdn.net/ajax/libs/${n}/${t}${e}`
133
+ }, M = {
134
+ getFileList: (n, t) => new Promise((e, r) => {
135
+ w.get(
136
+ `https://api.cdnjs.com/libraries/${n}/${t}`,
137
+ (s) => {
138
+ const c = JSON.parse(s);
139
+ if (c.error) {
140
+ r(new Error(`cdnjs: ${n}@${t} not found`));
141
+ return;
142
+ }
143
+ e({
144
+ fileList: c.rawFiles.map((i) => ({
145
+ name: "/" + i
146
+ }))
147
+ });
148
+ },
149
+ (s) => {
150
+ r(s);
151
+ }
152
+ );
153
+ }),
154
+ getUrl: (n, t, e) => `https://cdnjs.cloudflare.com/ajax/libs/${n}/${t}${e}`
155
+ }, V = {
156
+ getFileList: (n, t) => new Promise((e, r) => {
157
+ w.get(
158
+ `https://data.jsdelivr.com/v1/stats/packages/npm/${n}@${t}/files`,
159
+ (s) => {
160
+ const c = JSON.parse(s);
161
+ if (c.length === 0) {
162
+ r(new Error(`${n}@${t} not found`));
163
+ return;
164
+ }
165
+ e({ fileList: c });
166
+ },
167
+ (s) => {
168
+ r(s);
169
+ }
170
+ );
171
+ }),
172
+ // 拼接url
173
+ getUrl: (n, t, e) => `https://cdn.jsdelivr.net/npm/${n}@${t}${e}`
174
+ }, b = (n) => n.reduce((t, e) => (e.type === "file" ? t.push({ name: e.path }) : e.files && t.push(...b(e.files)), t), []), T = {
175
+ getFileList: (n, t) => new Promise((e, r) => {
176
+ w.get(
177
+ `https://unpkg.com/${n}@${t}/?meta`,
178
+ (s) => {
179
+ const c = JSON.parse(s);
180
+ e({ fileList: b(c.files || []) });
181
+ },
182
+ (s) => {
183
+ r(s);
184
+ }
185
+ );
186
+ }),
187
+ getUrl: (n, t, e) => `https://unpkg.com/${n}@${t}${e}`
188
+ }, Q = async (n) => {
189
+ const t = /^(https?:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;
68
190
  if (t.test(n)) {
69
191
  const e = n.replace(t, (r, s) => `${s}package.json`);
70
- return JSON.parse(await $.get(e));
192
+ return JSON.parse(await w.get(e));
71
193
  } else
72
194
  throw new Error(`${n} 不是正确的url`);
73
- }, I = (n, t) => {
195
+ }, q = (n, t) => {
74
196
  var e, r;
75
197
  return ((e = n.dependencies) == null ? void 0 : e[t]) || ((r = n.devDependencies) == null ? void 0 : r[t]);
76
- }, J = (n) => n.reduce((t, e) => (e.type === "file" ? t.push({ name: e.path }) : e.files && t.push(...J(e.files)), t), []), k = {
77
- jsdelivr: {
78
- getFileList: (n, t) => new Promise((e, r) => {
79
- $.get(
80
- `https://data.jsdelivr.com/v1/stats/packages/npm/${n}@${t}/files`,
81
- (s) => {
82
- const c = JSON.parse(s);
83
- if (c.length === 0) {
84
- r(new Error(`${n}@${t} not found`));
85
- return;
86
- }
87
- e({ fileList: c });
88
- },
89
- (s) => {
90
- r(s);
91
- }
92
- );
93
- }),
94
- // 拼接url
95
- getUrl: (n, t, e) => `https://cdn.jsdelivr.net/npm/${n}@${t}${e}`
96
- },
97
- unpkg: {
98
- getFileList: (n, t) => new Promise((e, r) => {
99
- $.get(
100
- `https://unpkg.com/${n}@${t}/?meta`,
101
- (s) => {
102
- const c = JSON.parse(s);
103
- e({ fileList: J(c.files || []) });
104
- },
105
- (s) => {
106
- r(s);
107
- }
108
- );
109
- }),
110
- getUrl: (n, t, e) => `https://unpkg.com/${n}@${t}${e}`
111
- },
112
- bootcdn: {
113
- getFileList: (n, t) => new Promise((e, r) => {
114
- $.get(
115
- `https://api.bootcdn.cn/libraries/${n}`,
116
- (s) => {
117
- const c = JSON.parse(s);
118
- if (c.length === 0) {
119
- r(new Error(`${n} not found in bootcdn`));
120
- return;
121
- }
122
- const o = c[0], a = o.assets.find((d) => d.version === t);
123
- if (!a) {
124
- r(new Error(`${n}@${t} not found in ${o.name}`));
125
- return;
126
- }
127
- const l = a.files.map((d) => ({
128
- name: "/" + d
129
- }));
130
- e({ fileList: l, recommendFileName: o.filename });
131
- },
132
- (s) => {
133
- r(s);
134
- }
135
- );
136
- }),
137
- getUrl: (n, t, e) => `https://cdn.bootcdn.net/ajax/libs/${n}/${t}${e}`
138
- },
139
- cdnjs: {
140
- getFileList: (n, t) => new Promise((e, r) => {
141
- $.get(
142
- `https://api.cdnjs.com/libraries/${n}/${t}`,
143
- (s) => {
144
- const c = JSON.parse(s);
145
- if (c.error) {
146
- r(new Error(`cdnjs: ${n}@${t} not found`));
147
- return;
148
- }
149
- e({
150
- fileList: c.rawFiles.map((o) => ({
151
- name: "/" + o
152
- }))
153
- });
154
- },
155
- (s) => {
156
- r(s);
157
- }
158
- );
159
- }),
160
- getUrl: (n, t, e) => `https://cdnjs.cloudflare.com/ajax/libs/${n}/${t}${e}`
161
- }
162
- }, R = async (n, t, e) => {
163
- var o;
164
- const r = (o = t.match(/\d+(.\d+)?(.\d+)?/)) == null ? void 0 : o[0];
198
+ }, H = async (n, t, e) => {
199
+ var i;
200
+ const r = (i = t.match(/\d+(.\d+)?(.\d+)?/)) == null ? void 0 : i[0];
165
201
  if (!r)
166
202
  throw new Error(`${n} version ${t} is not valid`);
167
- const s = await k[e].getFileList(n, r).catch((i) => {
168
- throw i;
169
- }), c = A(s, n);
203
+ const s = await v[e].getFileList(n, r).catch((o) => {
204
+ throw console.log(o), new Error(`${n} ${t} ${e} API 请求失败`);
205
+ }), c = B(s, n);
170
206
  if (!c)
171
207
  throw new Error(`在 ${e} 中找不到 ${n}@${r} 文件,请检查包名或版本号`);
172
- return k[e].getUrl(n, r, c);
173
- }, A = ({ fileList: n }, t) => {
174
- var c, o;
208
+ return v[e].getUrl(n, r, c);
209
+ }, B = ({ fileList: n }, t) => {
210
+ var c, i;
175
211
  let e = [
176
212
  `umd/${t}.production.min.js`,
177
213
  /umd\/.+?\.production\.min\.js$/,
@@ -189,137 +225,146 @@ const L = async () => (C || (C = new E(), await C.init()), C), $ = {
189
225
  /\.min\.js$/,
190
226
  /\.js$/
191
227
  ];
192
- const r = ["runtime", "compiler", ".esm", ".cjs", "development"].filter((i) => !t.includes(i));
228
+ const r = ["runtime", "compiler", ".esm", ".cjs", "development"].filter((o) => !t.includes(o));
193
229
  let s = "";
194
- for (let i of e)
195
- if (i instanceof RegExp ? s = ((c = n.find((a) => i.test(a.name) && !r.some((l) => a.name.includes(l)))) == null ? void 0 : c.name) || "" : s = ((o = n.find((a) => a.name.includes(i) && !r.some((l) => a.name.includes(l)))) == null ? void 0 : o.name) || "", s)
230
+ for (let o of e)
231
+ if (o instanceof RegExp ? s = ((c = n.find((a) => o.test(a.name) && !r.some((l) => a.name.includes(l)))) == null ? void 0 : c.name) || "" : s = ((i = n.find((a) => a.name.includes(o) && !r.some((l) => a.name.includes(l)))) == null ? void 0 : i.name) || "", s)
196
232
  break;
197
233
  return s;
234
+ }, v = {
235
+ jsdelivr: V,
236
+ bootcdn: A,
237
+ cdnjs: M,
238
+ unpkg: T
198
239
  };
199
- function M(n, t) {
240
+ function G(n, t) {
200
241
  const e = n.replace(/^\D/, "").split("."), r = t.replace(/^\D/, "").split("."), s = Math.max(e.length, r.length);
201
242
  for (; e.length < s; )
202
243
  e.push("0");
203
244
  for (; r.length < s; )
204
245
  r.push("0");
205
246
  for (let c = 0; c < s; c++) {
206
- const o = parseInt(e[c], 10), i = parseInt(r[c], 10);
207
- if (o > i)
247
+ const i = parseInt(e[c], 10), o = parseInt(r[c], 10);
248
+ if (i > o)
208
249
  return 1;
209
- if (o < i)
250
+ if (i < o)
210
251
  return -1;
211
252
  }
212
253
  return 0;
213
254
  }
214
- function V(n, t) {
255
+ function z(n, t) {
215
256
  for (let e in t)
216
- Object.prototype.hasOwnProperty.call(t, e) && (n[e] ? M(n[e], t[e]) === -1 && (n[e] = t[e]) : n[e] = t[e]);
257
+ Object.prototype.hasOwnProperty.call(t, e) && (n[e] ? G(n[e], t[e]) === -1 && (n[e] = t[e]) : n[e] = t[e]);
217
258
  return n;
218
259
  }
219
- async function v({ external: n, packageData: t, customScript: e, defaultCdns: r }) {
260
+ async function O({ external: n, packageData: t, customScript: e, defaultCdns: r }) {
220
261
  let s = [], c = !1;
221
- const o = await L();
262
+ const i = await I();
222
263
  return await Promise.all(
223
- n.map(async (i) => {
224
- const a = I(t, i);
225
- if (e[i])
264
+ n.map(async (o) => {
265
+ const a = q(t, o);
266
+ if (e[o])
226
267
  return {
227
268
  urls: [],
228
- key: i
269
+ key: o
229
270
  };
230
- if (!a)
231
- return s.push(i), {
271
+ const l = i.getCdnCache(o, a);
272
+ if (!a && !l)
273
+ return s.push(o), {
232
274
  urls: [],
233
- key: i
275
+ key: o
234
276
  };
235
- const l = o.getCdnCache(i, a);
236
277
  if (l)
237
278
  return {
238
279
  urls: l,
239
- key: i
280
+ key: o
240
281
  };
241
282
  {
242
- c = !0, console.log(`从网络获取${i}${a}的cdn地址`);
283
+ c = !0, console.log(`从网络获取${o}${a}的cdn地址`);
243
284
  const d = {
244
285
  urls: await Promise.all(
245
- r.map(async (h) => await R(i, a, h))
286
+ r.map(async (C) => await H(o, a, C))
246
287
  ),
247
- key: i
288
+ key: o
248
289
  };
249
- return o.setCdnCache(i, a, d.urls), d;
290
+ return i.setCdnCache(o, a, d.urls), d;
250
291
  }
251
292
  })
252
- ).then((i) => (c && o.save(), {
253
- urls: i,
293
+ ).then((o) => (c && i.save(), {
294
+ urls: o,
254
295
  noVersionPackages: s
255
296
  }));
256
297
  }
257
- function q(n) {
258
- const { customScript: t = {}, retryTimes: e = 1, defaultCdns: r = ["jsdelivr", "unpkg"] } = n;
259
- let s;
298
+ function tt(n) {
299
+ const { customScript: t = {}, retryTimes: e, defaultCdns: r = ["jsdelivr", "unpkg", "cdnjs"] } = n;
300
+ let s = e;
301
+ s || (s = r.length - 1);
302
+ let c;
260
303
  return {
261
304
  name: "vite-add-cdn-script",
262
305
  enforce: "pre",
263
306
  apply: "build",
264
- config(c) {
265
- s = c;
307
+ config(i) {
308
+ c = i;
266
309
  },
267
- async transformIndexHtml(c) {
310
+ async transformIndexHtml(i) {
268
311
  if (!r || r.length === 0)
269
312
  throw new Error("defaultCdns不能为空");
270
- const o = O.resolve(process.cwd(), "package.json");
313
+ const o = J.resolve(process.cwd(), "package.json");
271
314
  try {
272
- const i = y.readFileSync(o, "utf-8"), a = JSON.parse(i), l = s.build.rollupOptions.external, d = {};
273
- let h = "";
274
- const { urls: P, noVersionPackages: U } = await v({
275
- external: l,
276
- packageData: a,
315
+ const a = j.readFileSync(o, "utf-8"), l = JSON.parse(a), d = c.build.rollupOptions.external, C = {};
316
+ let p = "";
317
+ const { urls: k, noVersionPackages: S } = await O({
318
+ external: d,
319
+ packageData: l,
277
320
  customScript: t,
278
321
  defaultCdns: r
279
322
  });
280
- if (U.length > 0) {
281
- const f = { dependencies: {} };
323
+ if (S.length > 0) {
324
+ const m = { dependencies: {} };
282
325
  await Promise.all(
283
- P.map(async (p) => {
284
- if (!p)
326
+ k.map(async (u) => {
327
+ if (!u)
285
328
  return;
286
- const { key: j, urls: x } = p, m = t[j] || x[0];
287
- if (!m)
329
+ const { key: x, urls: _ } = u, g = t[x] || _[0];
330
+ if (!g)
288
331
  return;
289
- const g = await N(m);
290
- V(f.dependencies, g.dependencies);
332
+ const $ = await Q(g);
333
+ z(m.dependencies, $.dependencies);
291
334
  })
292
- );
293
- const { urls: w, noVersionPackages: u } = await v({
294
- external: U,
295
- packageData: f,
335
+ ).catch((u) => {
336
+ console.log("err", u);
337
+ });
338
+ const { urls: P, noVersionPackages: h } = await O({
339
+ external: S,
340
+ packageData: m,
296
341
  customScript: t,
297
342
  defaultCdns: r
298
343
  });
299
- if (w.map((p) => {
300
- var m;
301
- if (!p)
344
+ if (P.map((u) => {
345
+ var g;
346
+ if (!u)
302
347
  return;
303
- const { urls: j, key: x } = p;
304
- (m = P.find((g) => (g == null ? void 0 : g.key) === x)) == null || m.urls.push(...j);
305
- }), u.length > 0)
306
- throw console.error(`找不到${u.join(",")}的版本`), new Error(`找不到${u.join(",")}的版本`);
348
+ const { urls: x, key: _ } = u;
349
+ (g = k.find(($) => ($ == null ? void 0 : $.key) === _)) == null || g.urls.push(...x);
350
+ }), h.length > 0)
351
+ throw console.error(`找不到${h.join(",")}的版本`), new Error(`找不到${h.join(",")}的版本`);
307
352
  }
308
- return P.forEach((f) => {
309
- if (!f)
353
+ return k.forEach((m) => {
354
+ if (!m)
310
355
  return;
311
- const { urls: w, key: u } = f;
312
- if (t[u])
313
- h += t[u];
356
+ const { urls: P, key: h } = m;
357
+ if (t[h])
358
+ p += t[h];
314
359
  else {
315
- d[u] = w;
316
- const p = w[0];
317
- h += `<script src="${p}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${u}"><\/script>
360
+ C[h] = P;
361
+ const u = P[0];
362
+ p += `<script src="${u}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${h}"><\/script>
318
363
  `;
319
364
  }
320
- }), h = `<script>
365
+ }), p = `<script>
321
366
  function errorCDN(e) {
322
- const packNameUrl = JSON.parse('${JSON.stringify(d)}');
367
+ const packNameUrl = JSON.parse('${JSON.stringify(C)}');
323
368
  const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
324
369
  if(nextCur>${e}){return;}
325
370
 
@@ -339,13 +384,13 @@ function q(n) {
339
384
  document.head.appendChild(cdnDOM);
340
385
  e.remove();
341
386
  }
342
- <\/script>` + h, c = c.replace("</head>", `${h}</head>`), c;
343
- } catch (i) {
344
- console.error("获取dependencies出错:", i);
387
+ <\/script>` + p, i = i.replace("</head>", `${p}</head>`), i;
388
+ } catch (a) {
389
+ console.error("获取dependencies出错:", a);
345
390
  }
346
391
  }
347
392
  };
348
393
  }
349
394
  export {
350
- q as default
395
+ tt as default
351
396
  };
@@ -1,7 +1,7 @@
1
- (function(u,a){typeof exports=="object"&&typeof module<"u"?module.exports=a(require("node:path"),require("node:fs"),require("node:https")):typeof define=="function"&&define.amd?define(["node:path","node:fs","node:https"],a):(u=typeof globalThis<"u"?globalThis:u||self,u.index=a(u.path,u.fs,u.https))})(this,function(u,a,f){"use strict";var V=Object.defineProperty;var T=(u,a,f)=>a in u?V(u,a,{enumerable:!0,configurable:!0,writable:!0,value:f}):u[a]=f;var k=(u,a,f)=>(T(u,typeof a!="symbol"?a+"":a,f),f);class F{constructor(){k(this,"cdnCache",{});k(this,"cdnCachePath","");this.cdnCachePath=u.resolve(process.cwd(),"./.cdn-cache.json")}async init(){try{const e=await a.readFileSync(this.cdnCachePath,"utf-8");this.cdnCache=JSON.parse(e)}catch{console.log("cdn缓存文件不存在,创建缓存文件"),this.cdnCache={},await a.writeFileSync(this.cdnCachePath,"","utf-8")}}getCdnCache(e,t){var r;return(r=this.cdnCache[e])==null?void 0:r[t]}setCdnCache(e,t,r){this.cdnCache[e]?this.cdnCache[e][t]=r:this.cdnCache[e]={[t]:r}}async save(){await a.writeFileSync(this.cdnCachePath,JSON.stringify(this.cdnCache),"utf-8")}}let j;const E=async()=>(j||(j=new F,await j.init()),j),$={get:(n,e,t)=>new Promise((r,s)=>{try{f.get(n,i=>{let o="";i.on("data",c=>{o+=c}),i.on("end",()=>{e==null||e(o),r(o)})})}catch(i){t==null||t(i),s(i)}})},L=async n=>{const e=/^(https:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;if(e.test(n)){const t=n.replace(e,(r,s)=>`${s}package.json`);return JSON.parse(await $.get(t))}else throw new Error(`${n} 不是正确的url`)},b=(n,e)=>{var t,r;return((t=n.dependencies)==null?void 0:t[e])||((r=n.devDependencies)==null?void 0:r[e])},v=n=>n.reduce((e,t)=>(t.type==="file"?e.push({name:t.path}):t.files&&e.push(...v(t.files)),e),[]),O={jsdelivr:{getFileList:(n,e)=>new Promise((t,r)=>{$.get(`https://data.jsdelivr.com/v1/stats/packages/npm/${n}@${e}/files`,s=>{const i=JSON.parse(s);if(i.length===0){r(new Error(`${n}@${e} not found`));return}t({fileList:i})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://cdn.jsdelivr.net/npm/${n}@${e}${t}`},unpkg:{getFileList:(n,e)=>new Promise((t,r)=>{$.get(`https://unpkg.com/${n}@${e}/?meta`,s=>{const i=JSON.parse(s);t({fileList:v(i.files||[])})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://unpkg.com/${n}@${e}${t}`},bootcdn:{getFileList:(n,e)=>new Promise((t,r)=>{$.get(`https://api.bootcdn.cn/libraries/${n}`,s=>{const i=JSON.parse(s);if(i.length===0){r(new Error(`${n} not found in bootcdn`));return}const o=i[0],d=o.assets.find(h=>h.version===e);if(!d){r(new Error(`${n}@${e} not found in ${o.name}`));return}const l=d.files.map(h=>({name:"/"+h}));t({fileList:l,recommendFileName:o.filename})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://cdn.bootcdn.net/ajax/libs/${n}/${e}${t}`},cdnjs:{getFileList:(n,e)=>new Promise((t,r)=>{$.get(`https://api.cdnjs.com/libraries/${n}/${e}`,s=>{const i=JSON.parse(s);if(i.error){r(new Error(`cdnjs: ${n}@${e} not found`));return}t({fileList:i.rawFiles.map(o=>({name:"/"+o}))})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://cdnjs.cloudflare.com/ajax/libs/${n}/${e}${t}`}},N=async(n,e,t)=>{var o;const r=(o=e.match(/\d+(.\d+)?(.\d+)?/))==null?void 0:o[0];if(!r)throw new Error(`${n} version ${e} is not valid`);const s=await O[t].getFileList(n,r).catch(c=>{throw c}),i=I(s,n);if(!i)throw new Error(`在 ${t} 中找不到 ${n}@${r} 文件,请检查包名或版本号`);return O[t].getUrl(n,r,i)},I=({fileList:n},e)=>{var i,o;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 r=["runtime","compiler",".esm",".cjs","development"].filter(c=>!e.includes(c));let s="";for(let c of t)if(c instanceof RegExp?s=((i=n.find(d=>c.test(d.name)&&!r.some(l=>d.name.includes(l))))==null?void 0:i.name)||"":s=((o=n.find(d=>d.name.includes(c)&&!r.some(l=>d.name.includes(l))))==null?void 0:o.name)||"",s)break;return s};function R(n,e){const t=n.replace(/^\D/,"").split("."),r=e.replace(/^\D/,"").split("."),s=Math.max(t.length,r.length);for(;t.length<s;)t.push("0");for(;r.length<s;)r.push("0");for(let i=0;i<s;i++){const o=parseInt(t[i],10),c=parseInt(r[i],10);if(o>c)return 1;if(o<c)return-1}return 0}function A(n,e){for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&(n[t]?R(n[t],e[t])===-1&&(n[t]=e[t]):n[t]=e[t]);return n}async function J({external:n,packageData:e,customScript:t,defaultCdns:r}){let s=[],i=!1;const o=await E();return await Promise.all(n.map(async c=>{const d=b(e,c);if(t[c])return{urls:[],key:c};if(!d)return s.push(c),{urls:[],key:c};const l=o.getCdnCache(c,d);if(l)return{urls:l,key:c};{i=!0,console.log(`从网络获取${c}${d}的cdn地址`);const h={urls:await Promise.all(r.map(async m=>await N(c,d,m))),key:c};return o.setCdnCache(c,d,h.urls),h}})).then(c=>(i&&o.save(),{urls:c,noVersionPackages:s}))}function M(n){const{customScript:e={},retryTimes:t=1,defaultCdns:r=["jsdelivr","unpkg"]}=n;let s;return{name:"vite-add-cdn-script",enforce:"pre",apply:"build",config(i){s=i},async transformIndexHtml(i){if(!r||r.length===0)throw new Error("defaultCdns不能为空");const o=u.resolve(process.cwd(),"package.json");try{const c=a.readFileSync(o,"utf-8"),d=JSON.parse(c),l=s.build.rollupOptions.external,h={};let m="";const{urls:x,noVersionPackages:D}=await J({external:l,packageData:d,customScript:e,defaultCdns:r});if(D.length>0){const w={dependencies:{}};await Promise.all(x.map(async g=>{if(!g)return;const{key:S,urls:U}=g,C=e[S]||U[0];if(!C)return;const y=await L(C);A(w.dependencies,y.dependencies)}));const{urls:P,noVersionPackages:p}=await J({external:D,packageData:w,customScript:e,defaultCdns:r});if(P.map(g=>{var C;if(!g)return;const{urls:S,key:U}=g;(C=x.find(y=>(y==null?void 0:y.key)===U))==null||C.urls.push(...S)}),p.length>0)throw console.error(`找不到${p.join(",")}的版本`),new Error(`找不到${p.join(",")}的版本`)}return x.forEach(w=>{if(!w)return;const{urls:P,key:p}=w;if(e[p])m+=e[p];else{h[p]=P;const g=P[0];m+=`<script src="${g}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${p}"><\/script>
2
- `}}),m=`<script>
1
+ (function(d,u){typeof exports=="object"&&typeof module<"u"?module.exports=u(require("node:path"),require("node:fs"),require("node:https")):typeof define=="function"&&define.amd?define(["node:path","node:fs","node:https"],u):(d=typeof globalThis<"u"?globalThis:d||self,d.index=u(d.path,d.fs,d.https))})(this,function(d,u,m){"use strict";var z=Object.defineProperty;var K=(d,u,m)=>u in d?z(d,u,{enumerable:!0,configurable:!0,writable:!0,value:m}):d[u]=m;var $=(d,u,m)=>(K(d,typeof u!="symbol"?u+"":u,m),m);class E{constructor(){$(this,"cdnCache",{});$(this,"cdnCachePath","");this.cdnCachePath=d.resolve(process.cwd(),"./.cdn-cache.json")}async init(){try{const e=await u.readFileSync(this.cdnCachePath,"utf-8");this.cdnCache=JSON.parse(e)}catch{console.log("cdn缓存文件不存在,创建缓存文件"),this.cdnCache={},await u.writeFileSync(this.cdnCachePath,"","utf-8")}}getCdnCache(e,t){var r;return(r=this.cdnCache[e])==null?void 0:r[t]}setCdnCache(e,t,r){this.cdnCache[e]?this.cdnCache[e][t]=r:this.cdnCache[e]={[t]:r}}async save(){await u.writeFileSync(this.cdnCachePath,JSON.stringify(this.cdnCache),"utf-8")}}let j;const L=async()=>(j||(j=new E,await j.init()),j);class b{constructor(e){$(this,"_max");$(this,"_count");$(this,"_taskQueue");this._max=e||5,this._count=0,this._taskQueue=[]}call(e,...t){return new Promise((r,s)=>{const c=this._createTask(e,t,r,s);this._count>=this._max?this._taskQueue.push(c):c()})}_createTask(e,t,r,s){return()=>{e(...t).then(r).catch(s).finally(()=>{this._count--,this._taskQueue.length&&this._taskQueue.shift()()}),this._count++}}}const v=new b(5),I={get:(n,e,t)=>new Promise((r,s)=>{try{m.get(n,c=>{let i="";c.on("data",o=>{i+=o}),c.on("end",()=>{e==null||e(i),r(i)})}).on("error",function(c){t==null||t(c),s(c)})}catch(c){t==null||t(c),s(c)}})},w={get:v.call.bind(v,I.get)},N={getFileList:(n,e)=>new Promise((t,r)=>{w.get(`https://api.bootcdn.cn/libraries/${n}`,s=>{const c=JSON.parse(s);if(c.length===0){r(new Error(`${n} not found in bootcdn`));return}const i=c[0],a=i.assets.find(p=>p.version===e);if(!a){r(new Error(`${n}@${e} not found in ${i.name}`));return}const l=a.files.map(p=>({name:"/"+p}));t({fileList:l,recommendFileName:i.filename})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://cdn.bootcdn.net/ajax/libs/${n}/${e}${t}`},R={getFileList:(n,e)=>new Promise((t,r)=>{w.get(`https://api.cdnjs.com/libraries/${n}/${e}`,s=>{const c=JSON.parse(s);if(c.error){r(new Error(`cdnjs: ${n}@${e} not found`));return}t({fileList:c.rawFiles.map(i=>({name:"/"+i}))})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://cdnjs.cloudflare.com/ajax/libs/${n}/${e}${t}`},A={getFileList:(n,e)=>new Promise((t,r)=>{w.get(`https://data.jsdelivr.com/v1/stats/packages/npm/${n}@${e}/files`,s=>{const c=JSON.parse(s);if(c.length===0){r(new Error(`${n}@${e} not found`));return}t({fileList:c})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://cdn.jsdelivr.net/npm/${n}@${e}${t}`},O=n=>n.reduce((e,t)=>(t.type==="file"?e.push({name:t.path}):t.files&&e.push(...O(t.files)),e),[]),T={getFileList:(n,e)=>new Promise((t,r)=>{w.get(`https://unpkg.com/${n}@${e}/?meta`,s=>{const c=JSON.parse(s);t({fileList:O(c.files||[])})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://unpkg.com/${n}@${e}${t}`},M=async n=>{const e=/^(https?:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;if(e.test(n)){const t=n.replace(e,(r,s)=>`${s}package.json`);return JSON.parse(await w.get(t))}else throw new Error(`${n} 不是正确的url`)},V=(n,e)=>{var t,r;return((t=n.dependencies)==null?void 0:t[e])||((r=n.devDependencies)==null?void 0:r[e])},q=async(n,e,t)=>{var i;const r=(i=e.match(/\d+(.\d+)?(.\d+)?/))==null?void 0:i[0];if(!r)throw new Error(`${n} version ${e} is not valid`);const s=await J[t].getFileList(n,r).catch(o=>{throw console.log(o),new Error(`${n} ${e} ${t} API 请求失败`)}),c=Q(s,n);if(!c)throw new Error(`在 ${t} 中找不到 ${n}@${r} 文件,请检查包名或版本号`);return J[t].getUrl(n,r,c)},Q=({fileList:n},e)=>{var c,i;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 r=["runtime","compiler",".esm",".cjs","development"].filter(o=>!e.includes(o));let s="";for(let o of t)if(o instanceof RegExp?s=((c=n.find(a=>o.test(a.name)&&!r.some(l=>a.name.includes(l))))==null?void 0:c.name)||"":s=((i=n.find(a=>a.name.includes(o)&&!r.some(l=>a.name.includes(l))))==null?void 0:i.name)||"",s)break;return s},J={jsdelivr:A,bootcdn:N,cdnjs:R,unpkg:T};function H(n,e){const t=n.replace(/^\D/,"").split("."),r=e.replace(/^\D/,"").split("."),s=Math.max(t.length,r.length);for(;t.length<s;)t.push("0");for(;r.length<s;)r.push("0");for(let c=0;c<s;c++){const i=parseInt(t[c],10),o=parseInt(r[c],10);if(i>o)return 1;if(i<o)return-1}return 0}function B(n,e){for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&(n[t]?H(n[t],e[t])===-1&&(n[t]=e[t]):n[t]=e[t]);return n}async function D({external:n,packageData:e,customScript:t,defaultCdns:r}){let s=[],c=!1;const i=await L();return await Promise.all(n.map(async o=>{const a=V(e,o);if(t[o])return{urls:[],key:o};const l=i.getCdnCache(o,a);if(!a&&!l)return s.push(o),{urls:[],key:o};if(l)return{urls:l,key:o};{c=!0,console.log(`从网络获取${o}${a}的cdn地址`);const p={urls:await Promise.all(r.map(async k=>await q(o,a,k))),key:o};return i.setCdnCache(o,a,p.urls),p}})).then(o=>(c&&i.save(),{urls:o,noVersionPackages:s}))}function G(n){const{customScript:e={},retryTimes:t,defaultCdns:r=["jsdelivr","unpkg","cdnjs"]}=n;let s=t;s||(s=r.length-1);let c;return{name:"vite-add-cdn-script",enforce:"pre",apply:"build",config(i){c=i},async transformIndexHtml(i){if(!r||r.length===0)throw new Error("defaultCdns不能为空");const o=d.resolve(process.cwd(),"package.json");try{const a=u.readFileSync(o,"utf-8"),l=JSON.parse(a),p=c.build.rollupOptions.external,k={};let g="";const{urls:_,noVersionPackages:F}=await D({external:p,packageData:l,customScript:e,defaultCdns:r});if(F.length>0){const C={dependencies:{}};await Promise.all(_.map(async h=>{if(!h)return;const{key:S,urls:U}=h,P=e[S]||U[0];if(!P)return;const y=await M(P);B(C.dependencies,y.dependencies)})).catch(h=>{console.log("err",h)});const{urls:x,noVersionPackages:f}=await D({external:F,packageData:C,customScript:e,defaultCdns:r});if(x.map(h=>{var P;if(!h)return;const{urls:S,key:U}=h;(P=_.find(y=>(y==null?void 0:y.key)===U))==null||P.urls.push(...S)}),f.length>0)throw console.error(`找不到${f.join(",")}的版本`),new Error(`找不到${f.join(",")}的版本`)}return _.forEach(C=>{if(!C)return;const{urls:x,key:f}=C;if(e[f])g+=e[f];else{k[f]=x;const h=x[0];g+=`<script src="${h}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${f}"><\/script>
2
+ `}}),g=`<script>
3
3
  function errorCDN(e) {
4
- const packNameUrl = JSON.parse('${JSON.stringify(h)}');
4
+ const packNameUrl = JSON.parse('${JSON.stringify(k)}');
5
5
  const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
6
6
  if(nextCur>${t}){return;}
7
7
 
@@ -21,4 +21,4 @@
21
21
  document.head.appendChild(cdnDOM);
22
22
  e.remove();
23
23
  }
24
- <\/script>`+m,i=i.replace("</head>",`${m}</head>`),i}catch(c){console.error("获取dependencies出错:",c)}}}}return M});
24
+ <\/script>`+g,i=i.replace("</head>",`${g}</head>`),i}catch(a){console.error("获取dependencies出错:",a)}}}}return G});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-add-cdn-script",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "keywords": [
5
5
  "vite",
6
6
  "cdn",
@@ -42,8 +42,8 @@
42
42
  "@vitejs/plugin-react": "^4.2.1",
43
43
  "cross-env": "^7.0.3",
44
44
  "jest": "^29.7.0",
45
- "react": "^18.3.1",
46
- "react-dom": "^18.3.1",
45
+ "react": "^18.2.0",
46
+ "react-dom": "^18.2.0",
47
47
  "react-router-dom": "^6.23.1",
48
48
  "rollup-plugin-external-globals": "^0.10.0",
49
49
  "rollup-plugin-node-externals": "^7.1.2",