vite-add-cdn-script 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,13 +17,16 @@ vite.config.ts
17
17
  ```typescript
18
18
  import { defineConfig } from "vite";
19
19
  import react from "@vitejs/plugin-react";
20
- import viteAddCdnScript from "../vite-add-cdn-script/lib/main";
20
+ import viteAddCdnScript from "vite-add-cdn-script";
21
21
  import externalGlobals from "rollup-plugin-external-globals";
22
22
 
23
- // 需要使用cdn
23
+ // 需要使用cdn库,按顺序添加,如react-router-dom需要依赖react、@remix-run/router、react-router,因此需要放在最后
24
24
  const externals = {
25
25
  react: "React",
26
26
  "react-dom": "ReactDOM",
27
+ "@remix-run/router": "@remix-run/router",
28
+ "react-router": "react-router",
29
+ "react-router-dom": "ReactRouterDOM",
27
30
  };
28
31
 
29
32
  export default defineConfig({
@@ -45,6 +48,7 @@ import react from "@vitejs/plugin-react";
45
48
  import viteAddCdnScript from "../vite-add-cdn-script/lib/main";
46
49
  import externalGlobals from "rollup-plugin-external-globals";
47
50
 
51
+ // 需要使用cdn的模块,会按顺序插入脚本,如
48
52
  const externals = {
49
53
  react: "React",
50
54
  "react-dom": "ReactDOM",
@@ -73,27 +77,13 @@ export default defineConfig({
73
77
 
74
78
  options
75
79
 
76
- | 参数 | 解析 | 类型 | 默认值 |
77
- | ------------ | ------------------- | --------------------------- | -------------------------------------------------------------------- |
78
- | protocol | 协议 | “http”\|“https” | https |
79
- | customScript | 自定义 cdn 脚本 | { [*key*: string]: string } | |
80
- | retryTimes | 重试次数 | number | 3 |
81
- | defaultCdns | 默认使用 cdn 的顺序 | string[] | ["bootcdn", "bytedance", "unpkg", "cdnjs", "jsdelivr", "staticfile"] |
80
+ | 参数 | 解析 | 类型 | 默认值 |
81
+ | ------------ | ------------------- | --------------------------- | --------------------- |
82
+ | customScript | 自定义 cdn 脚本 | { [*key*: string]: string } | |
83
+ | retryTimes | 重试次数 | number | 3 |
84
+ | defaultCdns | 默认使用 cdn 的顺序 | string[] | ["jsdelivr", "unpkg"] |
82
85
 
83
86
  ## 注意事项
84
87
 
85
- 因为 cdn 对包管理的命名有很大的不同,默认是使用了 dist/xxx.min.js 的文件,如果您使用的库的 cdn 文件不是这个的话,则需要配置为自定义的 cdn
86
-
87
- 目前做了适配的非 xxx.min.js 适配的库如下,如果你有合适的 cdn 源或者,需要适配的库,欢迎提交 issue 或者 pr!!!
88
-
89
- ```
90
- {
91
- react: "umd/react.production.min.js",
92
- "react-dom": "umd/react-dom.production.min.js",
93
- "react-router-dom": "react-router-dom.production.min.js",
94
- mobx: "dist/mobx.umd.production.min.js",
95
- "mobx-react": "/dist/mobxreact.umd.production.min.js",
96
- vue: "/dist/vue.global.prod.js",
97
- "vue-router": "/dist/vue-router.global.prod.js",
98
- }
99
- ```
88
+ - 接入了各大 cdn api 接口进行请求,默认会保存一份 cdn 的缓存在你的根目录中`.cdn-cache.json`。如果发现缓存的资源有问题可以删除该文件,然后重新执行打包流程。
89
+ - 按顺序添加cdn,如react-router-dom需要依赖react、@remix-run/router、react-router,因此需要放在最后。
package/dist/index.js CHANGED
@@ -1,90 +1,344 @@
1
- import v from "node:path";
2
- import h from "node:fs";
3
- const u = {
4
- jsdelivr: "cdn.jsdelivr.net/npm",
5
- unpkg: "unpkg.com"
6
- }, m = {
7
- jsdelivr: "@",
8
- unpkg: "@"
9
- }, x = {
10
- // react
11
- react: "umd/react.production.min.js",
12
- "react-dom": "umd/react-dom.production.min.js",
13
- "@remix-run/router": "dist/router.umd.min.js",
14
- "react-router": "dist/umd/react-router.production.min.js",
15
- "react-router-dom": "dist/umd/react-router-dom.production.min.js",
16
- mobx: "dist/mobx.umd.production.min.js",
17
- "mobx-react": "dist/mobxreact.umd.production.min.js",
18
- // vue
19
- vue: "dist/vue.global.min.js",
20
- "vue-router": "dist/vue-router.global.min.js",
21
- // tool
22
- dayjs: "dayjs.min.js",
23
- moment: "moment.min.js",
24
- lodash: "lodash.min.js"
1
+ var D = Object.defineProperty;
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 y = (n, t, e) => (F(n, typeof t != "symbol" ? t + "" : t, e), e);
4
+ import U from "node:path";
5
+ import w from "node:fs";
6
+ import b from "node:https";
7
+ class E {
8
+ constructor() {
9
+ y(this, "cdnCache", {});
10
+ y(this, "cdnCachePath", "");
11
+ this.cdnCachePath = U.resolve(process.cwd(), "./.cdn-cache.json");
12
+ }
13
+ // 初始化cdn缓存
14
+ async init() {
15
+ try {
16
+ const t = await w.readFileSync(this.cdnCachePath, "utf-8");
17
+ this.cdnCache = JSON.parse(t);
18
+ } catch {
19
+ console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await w.writeFileSync(this.cdnCachePath, "", "utf-8");
20
+ }
21
+ }
22
+ /**
23
+ * 获取cdn缓存
24
+ * @param packageName 包名
25
+ * @param version 版本
26
+ */
27
+ getCdnCache(t, e) {
28
+ var r;
29
+ return (r = this.cdnCache[t]) == null ? void 0 : r[e];
30
+ }
31
+ /**
32
+ * 设置cdn缓存
33
+ * @param packageName 包名
34
+ * @param version 版本
35
+ * @param urls 地址列表
36
+ */
37
+ setCdnCache(t, e, r) {
38
+ this.cdnCache[t] ? this.cdnCache[t][e] = r : this.cdnCache[t] = {
39
+ [e]: r
40
+ };
41
+ }
42
+ /**
43
+ * 更新cdn缓存
44
+ */
45
+ async save() {
46
+ await w.writeFileSync(this.cdnCachePath, JSON.stringify(this.cdnCache), "utf-8");
47
+ }
48
+ }
49
+ let $;
50
+ const L = async () => ($ || ($ = new E(), await $.init()), $), f = {
51
+ //get请求封装
52
+ get: (n, t, e) => new Promise((r, s) => {
53
+ try {
54
+ b.get(n, (i) => {
55
+ let o = "";
56
+ i.on("data", (c) => {
57
+ o += c;
58
+ }), i.on("end", () => {
59
+ t == null || t(o), r(o);
60
+ });
61
+ });
62
+ } catch (i) {
63
+ e == null || e(i), s(i);
64
+ }
65
+ })
66
+ }, N = async (n) => {
67
+ const t = /^(https:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;
68
+ if (t.test(n)) {
69
+ const e = n.replace(t, (r, s) => `${s}package.json`);
70
+ return JSON.parse(await f.get(e));
71
+ } else
72
+ throw new Error(`${n} 不是正确的url`);
73
+ }, I = (n, t) => {
74
+ var e, r;
75
+ return ((e = n.dependencies) == null ? void 0 : e[t]) || ((r = n.devDependencies) == null ? void 0 : r[t]);
76
+ }, k = (n) => n.reduce((t, e) => (e.type === "file" ? t.push({ name: e.path }) : e.files && t.push(...k(e.files)), t), []), x = {
77
+ jsdelivr: {
78
+ getFileList: (n, t) => new Promise((e, r) => {
79
+ f.get(
80
+ `https://data.jsdelivr.com/v1/stats/packages/npm/${n}@${t}/files`,
81
+ (s) => {
82
+ const i = JSON.parse(s);
83
+ if (i.length === 0) {
84
+ r(new Error(`${n}@${t} not found`));
85
+ return;
86
+ }
87
+ e({ fileList: i });
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
+ f.get(
100
+ `https://unpkg.com/${n}@${t}/?meta`,
101
+ (s) => {
102
+ const i = JSON.parse(s);
103
+ e({ fileList: k(i.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
+ f.get(
115
+ `https://api.bootcdn.cn/libraries/${n}`,
116
+ (s) => {
117
+ const i = JSON.parse(s);
118
+ if (i.length === 0) {
119
+ r(new Error(`${n} not found in bootcdn`));
120
+ return;
121
+ }
122
+ const o = i[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
+ f.get(
142
+ `https://api.cdnjs.com/libraries/${n}/${t}`,
143
+ (s) => {
144
+ const i = JSON.parse(s);
145
+ if (i.error) {
146
+ r(new Error(`cdnjs: ${n}@${t} not found`));
147
+ return;
148
+ }
149
+ e({
150
+ fileList: i.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];
165
+ if (!r)
166
+ throw new Error(`${n} version ${t} is not valid`);
167
+ const s = await x[e].getFileList(n, r).catch((c) => {
168
+ throw c;
169
+ }), i = A(s, n);
170
+ if (!i)
171
+ throw new Error(`在 ${e} 中找不到 ${n}@${r} 文件,请检查包名或版本号`);
172
+ return x[e].getUrl(n, r, i);
173
+ }, A = ({ fileList: n }, t) => {
174
+ var i, o;
175
+ let e = [
176
+ `umd/${t}.production.min.js`,
177
+ /umd\/.+?\.production\.min\.js$/,
178
+ /dist\/.+?\.production\.min\.js$/,
179
+ /dist\/.+?\.umd\.min\.js$/,
180
+ `dist/${t}.prod.min.js`,
181
+ /dist\/.+?\.global.prod.min.js/,
182
+ `dist/${t}.min.js`,
183
+ /.+?\.global.prod.min.js/,
184
+ /.+?.global.prod.js/,
185
+ /lib\/.+?\.min\.js$/,
186
+ /dist\/.+?\.min\.js$/,
187
+ /index\.min\.js$/,
188
+ /index\.js$/,
189
+ /\.min\.js$/,
190
+ /\.js$/
191
+ ];
192
+ const r = ["runtime", "compiler", ".esm", ".cjs", "development"].filter((c) => !t.includes(c));
193
+ let s = "";
194
+ for (let c of e)
195
+ if (c instanceof RegExp ? s = ((i = n.find((a) => c.test(a.name) && !r.some((l) => a.name.includes(l)))) == null ? void 0 : i.name) || "" : s = ((o = n.find((a) => a.name.includes(c) && !r.some((l) => a.name.includes(l)))) == null ? void 0 : o.name) || "", s)
196
+ break;
197
+ return s;
25
198
  };
26
- function D(p) {
27
- const {
28
- protocol: l = "https",
29
- customScript: o = {},
30
- retryTimes: f = 1,
31
- defaultCdns: s = ["jsdelivr", "unpkg"],
32
- customFilepath: j = {}
33
- } = p;
34
- let a;
35
- const c = { ...x, ...j };
199
+ function M(n, t) {
200
+ const e = n.replace(/^\D/, "").split("."), r = t.replace(/^\D/, "").split("."), s = Math.max(e.length, r.length);
201
+ for (; e.length < s; )
202
+ e.push("0");
203
+ for (; r.length < s; )
204
+ r.push("0");
205
+ for (let i = 0; i < s; i++) {
206
+ const o = parseInt(e[i], 10), c = parseInt(r[i], 10);
207
+ if (o > c)
208
+ return 1;
209
+ if (o < c)
210
+ return -1;
211
+ }
212
+ return 0;
213
+ }
214
+ function V(n, t) {
215
+ 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]);
217
+ return n;
218
+ }
219
+ async function S({ external: n, packageData: t, customScript: e, defaultCdns: r }) {
220
+ let s = [], i = !1;
221
+ const o = await L();
222
+ return await Promise.all(
223
+ n.map(async (c) => {
224
+ const a = I(t, c);
225
+ if (e[c])
226
+ return {
227
+ urls: [],
228
+ key: c
229
+ };
230
+ if (!a) {
231
+ s.push(c);
232
+ return;
233
+ }
234
+ const l = o.getCdnCache(c, a);
235
+ if (l)
236
+ return {
237
+ urls: l,
238
+ key: c
239
+ };
240
+ {
241
+ i = !0;
242
+ const d = {
243
+ urls: await Promise.all(
244
+ r.map(async (h) => await R(c, a, h))
245
+ ),
246
+ key: c
247
+ };
248
+ return o.setCdnCache(c, a, d.urls), d;
249
+ }
250
+ })
251
+ ).then((c) => (i && o.save(), {
252
+ urls: c,
253
+ noVersionPackages: s
254
+ }));
255
+ }
256
+ function q(n) {
257
+ const { customScript: t = {}, retryTimes: e = 1, defaultCdns: r = ["jsdelivr", "unpkg"] } = n;
258
+ let s;
36
259
  return {
37
260
  name: "vite-add-cdn-script",
38
261
  enforce: "pre",
39
262
  apply: "build",
40
- config(e) {
41
- a = e;
263
+ config(i) {
264
+ s = i;
42
265
  },
43
- transformIndexHtml(e) {
44
- const g = v.resolve(process.cwd(), "package.json");
266
+ async transformIndexHtml(i) {
267
+ if (!r || r.length === 0)
268
+ throw new Error("defaultCdns不能为空");
269
+ const o = U.resolve(process.cwd(), "package.json");
45
270
  try {
46
- const r = s[0], b = h.readFileSync(g, "utf-8"), i = JSON.parse(b), O = a.build.rollupOptions.external;
47
- let n = "" + `<script>
48
- const separators = JSON.parse('${JSON.stringify(m)}');
49
- const cdnUrlObj = JSON.parse('${JSON.stringify(u)}');
50
- const defaultCdns = JSON.parse('${JSON.stringify(s)}');
51
- function errorCDN(e) {
52
- const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
53
- if(nextCur>=${f}){return;}
54
- const filename = e.getAttribute("data-filename");
55
- const key = e.getAttribute("data-key");
56
- const urlName = defaultCdns[nextCur]
57
- // 组装新的cdn链接
58
- const url = location.protocol + "//" + cdnUrlObj[urlName] + "/" + key + separators[urlName] + filename;
59
- // 克隆原标签
60
- const tagName = e.tagName
61
- const cdnDOM = document.createElement(tagName);
62
- cdnDOM.setAttribute(tagName === 'SCRIPT' ?'src' : 'href', url);
63
- Object.keys(e.dataset).forEach(_key => {
64
- cdnDOM.setAttribute('data-'+_key, e.dataset[_key]);
65
- })
66
- cdnDOM.setAttribute("data-cur", nextCur.toString());
67
- cdnDOM.setAttribute("onerror", "errorCDN(this)");
68
- document.head.appendChild(cdnDOM);
69
- e.remove();
70
- }
71
- <\/script>`;
72
- return O.forEach((t) => {
73
- if (o[t])
74
- n += o[t];
271
+ const c = w.readFileSync(o, "utf-8"), a = JSON.parse(c), l = s.build.rollupOptions.external, d = {};
272
+ let h = "";
273
+ const { urls: C, noVersionPackages: P } = await S({
274
+ external: l,
275
+ packageData: a,
276
+ customScript: t,
277
+ defaultCdns: r
278
+ });
279
+ if (P.length > 0) {
280
+ const p = { dependencies: {} };
281
+ await Promise.all(
282
+ C.map(async (g) => {
283
+ if (!g)
284
+ return;
285
+ const { key: v, urls: O } = g, j = t[v] || O[0];
286
+ if (!j)
287
+ return;
288
+ const J = await N(j);
289
+ V(p.dependencies, J.dependencies);
290
+ })
291
+ );
292
+ const { urls: m, noVersionPackages: u } = await S({
293
+ external: P,
294
+ packageData: p,
295
+ customScript: t,
296
+ defaultCdns: r
297
+ });
298
+ if (C.push(...m), u.length > 0)
299
+ throw console.error(`找不到${u.join(",")}的版本`), new Error(`找不到${u.join(",")}的版本`);
300
+ }
301
+ return C.forEach((p) => {
302
+ if (!p)
303
+ return;
304
+ const { urls: m, key: u } = p;
305
+ if (t[u])
306
+ h += t[u];
75
307
  else {
76
- const d = (i.dependencies[t] ? m[r] + i.dependencies[t].replace("^", "") : "") + "/" + (c[t] ? c[t] : `dist/${t}.min.js`), N = `${l}://${u[r]}/${t}${d}`;
77
- n += `<script src="${N}" type="text/javascript" onerror="errorCDN(this)" data-cur="0" data-key="${t}" data-filename="${d}"><\/script>
308
+ d[u] = m;
309
+ const g = m[0];
310
+ h += `<script src="${g}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${u}"><\/script>
78
311
  `;
79
312
  }
80
- }), e = e.replace("</head>", `${n}</head>`), e;
81
- } catch (r) {
82
- console.error("获取dependencies出错:", r);
313
+ }), h = `<script>
314
+ function errorCDN(e) {
315
+ const packNameUrl = JSON.parse('${JSON.stringify(d)}');
316
+ const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
317
+ if(nextCur>${e}){return;}
318
+
319
+ const key = e.getAttribute("data-key");
320
+ if(nextCur>=packNameUrl[key].length){return;}
321
+ // 新的cdn链接
322
+ const url = packNameUrl[key][nextCur]
323
+ // 克隆原标签
324
+ const tagName = e.tagName
325
+ const cdnDOM = document.createElement(tagName);
326
+ cdnDOM.setAttribute(tagName === 'SCRIPT' ?'src' : 'href', url);
327
+ Object.keys(e.dataset).forEach(_key => {
328
+ cdnDOM.setAttribute('data-'+_key, e.dataset[_key]);
329
+ })
330
+ cdnDOM.setAttribute("data-cur", nextCur.toString());
331
+ cdnDOM.setAttribute("onerror", "errorCDN(this)");
332
+ document.head.appendChild(cdnDOM);
333
+ e.remove();
334
+ }
335
+ <\/script>` + h, i = i.replace("</head>", `${h}</head>`), i;
336
+ } catch (c) {
337
+ console.error("获取dependencies出错:", c);
83
338
  }
84
339
  }
85
340
  };
86
341
  }
87
342
  export {
88
- D as default,
89
- x as npmProObj
343
+ q as default
90
344
  };
@@ -1,26 +1,24 @@
1
- (function(e,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("node:path"),require("node:fs")):typeof define=="function"&&define.amd?define(["exports","node:path","node:fs"],r):(e=typeof globalThis<"u"?globalThis:e||self,r(e.index={},e.path,e.fs))})(this,function(e,r,j){"use strict";const c={jsdelivr:"cdn.jsdelivr.net/npm",unpkg:"unpkg.com"},a={jsdelivr:"@",unpkg:"@"},i={react:"umd/react.production.min.js","react-dom":"umd/react-dom.production.min.js","@remix-run/router":"dist/router.umd.min.js","react-router":"dist/umd/react-router.production.min.js","react-router-dom":"dist/umd/react-router-dom.production.min.js",mobx:"dist/mobx.umd.production.min.js","mobx-react":"dist/mobxreact.umd.production.min.js",vue:"dist/vue.global.min.js","vue-router":"dist/vue-router.global.min.js",dayjs:"dayjs.min.js",moment:"moment.min.js",lodash:"lodash.min.js"};function b(g){const{protocol:O="https",customScript:d={},retryTimes:h=1,defaultCdns:u=["jsdelivr","unpkg"],customFilepath:N={}}=g;let p;const m={...i,...N};return{name:"vite-add-cdn-script",enforce:"pre",apply:"build",config(n){p=n},transformIndexHtml(n){const v=r.resolve(process.cwd(),"package.json");try{const o=u[0],S=j.readFileSync(v,"utf-8"),l=JSON.parse(S),x=p.build.rollupOptions.external;let s=""+`<script>
2
- const separators = JSON.parse('${JSON.stringify(a)}');
3
- const cdnUrlObj = JSON.parse('${JSON.stringify(c)}');
4
- const defaultCdns = JSON.parse('${JSON.stringify(u)}');
5
- function errorCDN(e) {
6
- const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
7
- if(nextCur>=${h}){return;}
8
- const filename = e.getAttribute("data-filename");
9
- const key = e.getAttribute("data-key");
10
- const urlName = defaultCdns[nextCur]
11
- // 组装新的cdn链接
12
- const url = location.protocol + "//" + cdnUrlObj[urlName] + "/" + key + separators[urlName] + filename;
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>`;return x.forEach(t=>{if(d[t])s+=d[t];else{const f=(l.dependencies[t]?a[o]+l.dependencies[t].replace("^",""):"")+"/"+(m[t]?m[t]:`dist/${t}.min.js`),y=`${O}://${c[o]}/${t}${f}`;s+=`<script src="${y}" type="text/javascript" onerror="errorCDN(this)" data-cur="0" data-key="${t}" data-filename="${f}"><\/script>
26
- `}}),n=n.replace("</head>",`${s}</head>`),n}catch(o){console.error("获取dependencies出错:",o)}}}}e.default=b,e.npmProObj=i,Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
1
+ (function(d,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):(d=typeof globalThis<"u"?globalThis:d||self,d.index=a(d.path,d.fs,d.https))})(this,function(d,a,f){"use strict";var V=Object.defineProperty;var T=(d,a,f)=>a in d?V(d,a,{enumerable:!0,configurable:!0,writable:!0,value:f}):d[a]=f;var P=(d,a,f)=>(T(d,typeof a!="symbol"?a+"":a,f),f);class O{constructor(){P(this,"cdnCache",{});P(this,"cdnCachePath","");this.cdnCachePath=d.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 w;const J=async()=>(w||(w=new O,await w.init()),w),g={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)}})},D=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 g.get(t))}else throw new Error(`${n} 不是正确的url`)},F=(n,e)=>{var t,r;return((t=n.dependencies)==null?void 0:t[e])||((r=n.devDependencies)==null?void 0:r[e])},x=n=>n.reduce((e,t)=>(t.type==="file"?e.push({name:t.path}):t.files&&e.push(...x(t.files)),e),[]),S={jsdelivr:{getFileList:(n,e)=>new Promise((t,r)=>{g.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)=>{g.get(`https://unpkg.com/${n}@${e}/?meta`,s=>{const i=JSON.parse(s);t({fileList:x(i.files||[])})},s=>{r(s)})}),getUrl:(n,e,t)=>`https://unpkg.com/${n}@${e}${t}`},bootcdn:{getFileList:(n,e)=>new Promise((t,r)=>{g.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],u=o.assets.find(h=>h.version===e);if(!u){r(new Error(`${n}@${e} not found in ${o.name}`));return}const l=u.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)=>{g.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}`}},E=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 S[t].getFileList(n,r).catch(c=>{throw c}),i=L(s,n);if(!i)throw new Error(`在 ${t} 中找不到 ${n}@${r} 文件,请检查包名或版本号`);return S[t].getUrl(n,r,i)},L=({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(u=>c.test(u.name)&&!r.some(l=>u.name.includes(l))))==null?void 0:i.name)||"":s=((o=n.find(u=>u.name.includes(c)&&!r.some(l=>u.name.includes(l))))==null?void 0:o.name)||"",s)break;return s};function b(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 N(n,e){for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&(n[t]?b(n[t],e[t])===-1&&(n[t]=e[t]):n[t]=e[t]);return n}async function U({external:n,packageData:e,customScript:t,defaultCdns:r}){let s=[],i=!1;const o=await J();return await Promise.all(n.map(async c=>{const u=F(e,c);if(t[c])return{urls:[],key:c};if(!u){s.push(c);return}const l=o.getCdnCache(c,u);if(l)return{urls:l,key:c};{i=!0;const h={urls:await Promise.all(r.map(async m=>await E(c,u,m))),key:c};return o.setCdnCache(c,u,h.urls),h}})).then(c=>(i&&o.save(),{urls:c,noVersionPackages:s}))}function I(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=d.resolve(process.cwd(),"package.json");try{const c=a.readFileSync(o,"utf-8"),u=JSON.parse(c),l=s.build.rollupOptions.external,h={};let m="";const{urls:j,noVersionPackages:k}=await U({external:l,packageData:u,customScript:e,defaultCdns:r});if(k.length>0){const $={dependencies:{}};await Promise.all(j.map(async y=>{if(!y)return;const{key:R,urls:A}=y,v=e[R]||A[0];if(!v)return;const M=await D(v);N($.dependencies,M.dependencies)}));const{urls:C,noVersionPackages:p}=await U({external:k,packageData:$,customScript:e,defaultCdns:r});if(j.push(...C),p.length>0)throw console.error(`找不到${p.join(",")}的版本`),new Error(`找不到${p.join(",")}的版本`)}return j.forEach($=>{if(!$)return;const{urls:C,key:p}=$;if(e[p])m+=e[p];else{h[p]=C;const y=C[0];m+=`<script src="${y}" type="text/javascript" crossorigin="anonymous" onerror="errorCDN(this)" data-cur="0" data-key="${p}"><\/script>
2
+ `}}),m=`<script>
3
+ function errorCDN(e) {
4
+ const packNameUrl = JSON.parse('${JSON.stringify(h)}');
5
+ const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
6
+ if(nextCur>${t}){return;}
7
+
8
+ const key = e.getAttribute("data-key");
9
+ if(nextCur>=packNameUrl[key].length){return;}
10
+ // 新的cdn链接
11
+ const url = packNameUrl[key][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>`+m,i=i.replace("</head>",`${m}</head>`),i}catch(c){console.error("获取dependencies出错:",c)}}}}return I});
package/index.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  interface IOptions {
2
- protocol?: string;
3
2
  customScript?: { [key: string]: string };
4
- customFilepath?: { [key: string]: string };
5
3
  retryTimes?: number;
6
4
  defaultCdns?: string[];
7
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-add-cdn-script",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "keywords": [
5
5
  "vite",
6
6
  "cdn",
@@ -30,20 +30,30 @@
30
30
  },
31
31
  "scripts": {
32
32
  "dev": "vite",
33
- "build": "tsc && vite build"
33
+ "build:page": "tsc && cross-env BUILD_MODE=page vite build",
34
+ "build": "tsc && cross-env BUILD_MODE=lib vite build",
35
+ "test": "jest"
34
36
  },
35
37
  "devDependencies": {
38
+ "@jest/globals": "^29.7.0",
36
39
  "@types/node": "^20.12.11",
37
40
  "@types/react": "^18.3.2",
38
41
  "@types/react-dom": "^18.3.0",
39
42
  "@vitejs/plugin-react": "^4.2.1",
43
+ "cross-env": "^7.0.3",
44
+ "jest": "^29.7.0",
40
45
  "react": "^18.3.1",
41
46
  "react-dom": "^18.3.1",
47
+ "react-router-dom": "^6.23.1",
48
+ "rollup-plugin-external-globals": "^0.10.0",
42
49
  "rollup-plugin-node-externals": "^7.1.2",
50
+ "ts-jest": "^29.1.4",
51
+ "ts-node": "^10.9.2",
43
52
  "typescript": "^5.4.5",
44
53
  "vite": "^5.2.11"
45
54
  },
46
55
  "publishConfig": {
47
56
  "registry": "https://registry.npmjs.org/"
48
- }
49
- }
57
+ },
58
+ "dependencies": {}
59
+ }