vite-add-cdn-script 0.0.10 → 0.0.11
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/LICENSE +165 -0
- package/README.md +88 -89
- package/dist/index.js +166 -166
- package/dist/index.umd.cjs +7 -7
- package/index.d.ts +5 -6
- package/package.json +64 -64
package/LICENSE
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
GNU LESSER GENERAL PUBLIC LICENSE
|
2
|
+
Version 3, 29 June 2007
|
3
|
+
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
6
|
+
of this license document, but changing it is not allowed.
|
7
|
+
|
8
|
+
|
9
|
+
This version of the GNU Lesser General Public License incorporates
|
10
|
+
the terms and conditions of version 3 of the GNU General Public
|
11
|
+
License, supplemented by the additional permissions listed below.
|
12
|
+
|
13
|
+
0. Additional Definitions.
|
14
|
+
|
15
|
+
As used herein, "this License" refers to version 3 of the GNU Lesser
|
16
|
+
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
17
|
+
General Public License.
|
18
|
+
|
19
|
+
"The Library" refers to a covered work governed by this License,
|
20
|
+
other than an Application or a Combined Work as defined below.
|
21
|
+
|
22
|
+
An "Application" is any work that makes use of an interface provided
|
23
|
+
by the Library, but which is not otherwise based on the Library.
|
24
|
+
Defining a subclass of a class defined by the Library is deemed a mode
|
25
|
+
of using an interface provided by the Library.
|
26
|
+
|
27
|
+
A "Combined Work" is a work produced by combining or linking an
|
28
|
+
Application with the Library. The particular version of the Library
|
29
|
+
with which the Combined Work was made is also called the "Linked
|
30
|
+
Version".
|
31
|
+
|
32
|
+
The "Minimal Corresponding Source" for a Combined Work means the
|
33
|
+
Corresponding Source for the Combined Work, excluding any source code
|
34
|
+
for portions of the Combined Work that, considered in isolation, are
|
35
|
+
based on the Application, and not on the Linked Version.
|
36
|
+
|
37
|
+
The "Corresponding Application Code" for a Combined Work means the
|
38
|
+
object code and/or source code for the Application, including any data
|
39
|
+
and utility programs needed for reproducing the Combined Work from the
|
40
|
+
Application, but excluding the System Libraries of the Combined Work.
|
41
|
+
|
42
|
+
1. Exception to Section 3 of the GNU GPL.
|
43
|
+
|
44
|
+
You may convey a covered work under sections 3 and 4 of this License
|
45
|
+
without being bound by section 3 of the GNU GPL.
|
46
|
+
|
47
|
+
2. Conveying Modified Versions.
|
48
|
+
|
49
|
+
If you modify a copy of the Library, and, in your modifications, a
|
50
|
+
facility refers to a function or data to be supplied by an Application
|
51
|
+
that uses the facility (other than as an argument passed when the
|
52
|
+
facility is invoked), then you may convey a copy of the modified
|
53
|
+
version:
|
54
|
+
|
55
|
+
a) under this License, provided that you make a good faith effort to
|
56
|
+
ensure that, in the event an Application does not supply the
|
57
|
+
function or data, the facility still operates, and performs
|
58
|
+
whatever part of its purpose remains meaningful, or
|
59
|
+
|
60
|
+
b) under the GNU GPL, with none of the additional permissions of
|
61
|
+
this License applicable to that copy.
|
62
|
+
|
63
|
+
3. Object Code Incorporating Material from Library Header Files.
|
64
|
+
|
65
|
+
The object code form of an Application may incorporate material from
|
66
|
+
a header file that is part of the Library. You may convey such object
|
67
|
+
code under terms of your choice, provided that, if the incorporated
|
68
|
+
material is not limited to numerical parameters, data structure
|
69
|
+
layouts and accessors, or small macros, inline functions and templates
|
70
|
+
(ten or fewer lines in length), you do both of the following:
|
71
|
+
|
72
|
+
a) Give prominent notice with each copy of the object code that the
|
73
|
+
Library is used in it and that the Library and its use are
|
74
|
+
covered by this License.
|
75
|
+
|
76
|
+
b) Accompany the object code with a copy of the GNU GPL and this license
|
77
|
+
document.
|
78
|
+
|
79
|
+
4. Combined Works.
|
80
|
+
|
81
|
+
You may convey a Combined Work under terms of your choice that,
|
82
|
+
taken together, effectively do not restrict modification of the
|
83
|
+
portions of the Library contained in the Combined Work and reverse
|
84
|
+
engineering for debugging such modifications, if you also do each of
|
85
|
+
the following:
|
86
|
+
|
87
|
+
a) Give prominent notice with each copy of the Combined Work that
|
88
|
+
the Library is used in it and that the Library and its use are
|
89
|
+
covered by this License.
|
90
|
+
|
91
|
+
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
92
|
+
document.
|
93
|
+
|
94
|
+
c) For a Combined Work that displays copyright notices during
|
95
|
+
execution, include the copyright notice for the Library among
|
96
|
+
these notices, as well as a reference directing the user to the
|
97
|
+
copies of the GNU GPL and this license document.
|
98
|
+
|
99
|
+
d) Do one of the following:
|
100
|
+
|
101
|
+
0) Convey the Minimal Corresponding Source under the terms of this
|
102
|
+
License, and the Corresponding Application Code in a form
|
103
|
+
suitable for, and under terms that permit, the user to
|
104
|
+
recombine or relink the Application with a modified version of
|
105
|
+
the Linked Version to produce a modified Combined Work, in the
|
106
|
+
manner specified by section 6 of the GNU GPL for conveying
|
107
|
+
Corresponding Source.
|
108
|
+
|
109
|
+
1) Use a suitable shared library mechanism for linking with the
|
110
|
+
Library. A suitable mechanism is one that (a) uses at run time
|
111
|
+
a copy of the Library already present on the user's computer
|
112
|
+
system, and (b) will operate properly with a modified version
|
113
|
+
of the Library that is interface-compatible with the Linked
|
114
|
+
Version.
|
115
|
+
|
116
|
+
e) Provide Installation Information, but only if you would otherwise
|
117
|
+
be required to provide such information under section 6 of the
|
118
|
+
GNU GPL, and only to the extent that such information is
|
119
|
+
necessary to install and execute a modified version of the
|
120
|
+
Combined Work produced by recombining or relinking the
|
121
|
+
Application with a modified version of the Linked Version. (If
|
122
|
+
you use option 4d0, the Installation Information must accompany
|
123
|
+
the Minimal Corresponding Source and Corresponding Application
|
124
|
+
Code. If you use option 4d1, you must provide the Installation
|
125
|
+
Information in the manner specified by section 6 of the GNU GPL
|
126
|
+
for conveying Corresponding Source.)
|
127
|
+
|
128
|
+
5. Combined Libraries.
|
129
|
+
|
130
|
+
You may place library facilities that are a work based on the
|
131
|
+
Library side by side in a single library together with other library
|
132
|
+
facilities that are not Applications and are not covered by this
|
133
|
+
License, and convey such a combined library under terms of your
|
134
|
+
choice, if you do both of the following:
|
135
|
+
|
136
|
+
a) Accompany the combined library with a copy of the same work based
|
137
|
+
on the Library, uncombined with any other library facilities,
|
138
|
+
conveyed under the terms of this License.
|
139
|
+
|
140
|
+
b) Give prominent notice with the combined library that part of it
|
141
|
+
is a work based on the Library, and explaining where to find the
|
142
|
+
accompanying uncombined form of the same work.
|
143
|
+
|
144
|
+
6. Revised Versions of the GNU Lesser General Public License.
|
145
|
+
|
146
|
+
The Free Software Foundation may publish revised and/or new versions
|
147
|
+
of the GNU Lesser General Public License from time to time. Such new
|
148
|
+
versions will be similar in spirit to the present version, but may
|
149
|
+
differ in detail to address new problems or concerns.
|
150
|
+
|
151
|
+
Each version is given a distinguishing version number. If the
|
152
|
+
Library as you received it specifies that a certain numbered version
|
153
|
+
of the GNU Lesser General Public License "or any later version"
|
154
|
+
applies to it, you have the option of following the terms and
|
155
|
+
conditions either of that published version or of any later version
|
156
|
+
published by the Free Software Foundation. If the Library as you
|
157
|
+
received it does not specify a version number of the GNU Lesser
|
158
|
+
General Public License, you may choose any version of the GNU Lesser
|
159
|
+
General Public License ever published by the Free Software Foundation.
|
160
|
+
|
161
|
+
If the Library as you received it specifies that a proxy can decide
|
162
|
+
whether future versions of the GNU Lesser General Public License shall
|
163
|
+
apply, that proxy's public statement of acceptance of any version is
|
164
|
+
permanent authorization for you to choose that version for the
|
165
|
+
Library.
|
package/README.md
CHANGED
@@ -1,89 +1,88 @@
|
|
1
|
-
# vite-add-cdn-script
|
2
|
-
|
3
|
-
这是一个在 vite.js 中使用公共 cdn 的库,包括了 unpkg, jsdelivr 等多个 cdn 资源,如加载失败会自动切换下一个 cdn 进行加载。
|
4
|
-
|
5
|
-
## 开始
|
6
|
-
|
7
|
-
### 安装
|
8
|
-
|
9
|
-
```
|
10
|
-
pnpm install vite-add-cdn-script rollup-plugin-external-globals -D
|
11
|
-
```
|
12
|
-
|
13
|
-
### 使用
|
14
|
-
|
15
|
-
vite.config.ts
|
16
|
-
|
17
|
-
```typescript
|
18
|
-
import { defineConfig } from "vite";
|
19
|
-
import react from "@vitejs/plugin-react";
|
20
|
-
import viteAddCdnScript from "vite-add-cdn-script";
|
21
|
-
import externalGlobals from "rollup-plugin-external-globals";
|
22
|
-
|
23
|
-
// 需要使用cdn库,按顺序添加,如react-router-dom需要依赖react、@remix-run/router、react-router,因此需要放在最后
|
24
|
-
const externals = {
|
25
|
-
react: "React",
|
26
|
-
"react-dom": "ReactDOM",
|
27
|
-
"@remix-run/router": "@remix-run/router",
|
28
|
-
"react-router": "react-router",
|
29
|
-
"react-router-dom": "ReactRouterDOM",
|
30
|
-
};
|
31
|
-
|
32
|
-
export default defineConfig({
|
33
|
-
plugins: [react(), viteAddCdnScript({})],
|
34
|
-
build: {
|
35
|
-
rollupOptions: {
|
36
|
-
external: [...Object.keys(externals)],
|
37
|
-
plugins: [externalGlobals(externals)],
|
38
|
-
},
|
39
|
-
},
|
40
|
-
});
|
41
|
-
```
|
42
|
-
|
43
|
-
使用自定义的 cdn
|
44
|
-
|
45
|
-
```typescript
|
46
|
-
import { defineConfig } from "vite";
|
47
|
-
import react from "@vitejs/plugin-react";
|
48
|
-
import viteAddCdnScript from "../vite-add-cdn-script/lib/main";
|
49
|
-
import externalGlobals from "rollup-plugin-external-globals";
|
50
|
-
|
51
|
-
// 需要使用cdn的模块,会按顺序插入脚本,如
|
52
|
-
const externals = {
|
53
|
-
react: "React",
|
54
|
-
"react-dom": "ReactDOM",
|
55
|
-
};
|
56
|
-
|
57
|
-
export default defineConfig({
|
58
|
-
plugins: [
|
59
|
-
react(),
|
60
|
-
viteAddCdnScript({
|
61
|
-
customScript: {
|
62
|
-
react: "<script src='https://cdn.jsdelivr.net/npm/react@17.0.2/umd/react.production.min.js'></script>",
|
63
|
-
"react-dom":
|
64
|
-
"<script src='https://cdn.jsdelivr.net/npm/react-dom@17.0.2/umd/react-dom.production.min.js'></script>",
|
65
|
-
},
|
66
|
-
}),
|
67
|
-
],
|
68
|
-
base: "./",
|
69
|
-
build: {
|
70
|
-
rollupOptions: {
|
71
|
-
external: [...Object.keys(externals)],
|
72
|
-
plugins: [externalGlobals(externals)],
|
73
|
-
},
|
74
|
-
},
|
75
|
-
});
|
76
|
-
```
|
77
|
-
|
78
|
-
options
|
79
|
-
|
80
|
-
| 参数 | 解析 | 类型 | 默认值
|
81
|
-
| ------------ | ------------------- | --------------------------- |
|
82
|
-
| customScript | 自定义 cdn 脚本 | { [*key*: string]: string } | 无
|
83
|
-
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
-
|
89
|
-
- 按顺序添加 cdn,如 react-router-dom 需要依赖 react、@remix-run/router、react-router,因此需要放在最后。
|
1
|
+
# vite-add-cdn-script
|
2
|
+
|
3
|
+
这是一个在 vite.js 中使用公共 cdn 的库,包括了 unpkg, jsdelivr 等多个 cdn 资源,如加载失败会自动切换下一个 cdn 进行加载。
|
4
|
+
|
5
|
+
## 开始
|
6
|
+
|
7
|
+
### 安装
|
8
|
+
|
9
|
+
```
|
10
|
+
pnpm install vite-add-cdn-script rollup-plugin-external-globals -D
|
11
|
+
```
|
12
|
+
|
13
|
+
### 使用
|
14
|
+
|
15
|
+
vite.config.ts
|
16
|
+
|
17
|
+
```typescript
|
18
|
+
import { defineConfig } from "vite";
|
19
|
+
import react from "@vitejs/plugin-react";
|
20
|
+
import viteAddCdnScript from "vite-add-cdn-script";
|
21
|
+
import externalGlobals from "rollup-plugin-external-globals";
|
22
|
+
|
23
|
+
// 需要使用cdn库,按顺序添加,如react-router-dom需要依赖react、@remix-run/router、react-router,因此需要放在最后
|
24
|
+
const externals = {
|
25
|
+
react: "React",
|
26
|
+
"react-dom": "ReactDOM",
|
27
|
+
"@remix-run/router": "@remix-run/router",
|
28
|
+
"react-router": "react-router",
|
29
|
+
"react-router-dom": "ReactRouterDOM",
|
30
|
+
};
|
31
|
+
|
32
|
+
export default defineConfig({
|
33
|
+
plugins: [react(), viteAddCdnScript({})],
|
34
|
+
build: {
|
35
|
+
rollupOptions: {
|
36
|
+
external: [...Object.keys(externals)],
|
37
|
+
plugins: [externalGlobals(externals)],
|
38
|
+
},
|
39
|
+
},
|
40
|
+
});
|
41
|
+
```
|
42
|
+
|
43
|
+
使用自定义的 cdn
|
44
|
+
|
45
|
+
```typescript
|
46
|
+
import { defineConfig } from "vite";
|
47
|
+
import react from "@vitejs/plugin-react";
|
48
|
+
import viteAddCdnScript from "../vite-add-cdn-script/lib/main";
|
49
|
+
import externalGlobals from "rollup-plugin-external-globals";
|
50
|
+
|
51
|
+
// 需要使用cdn的模块,会按顺序插入脚本,如
|
52
|
+
const externals = {
|
53
|
+
react: "React",
|
54
|
+
"react-dom": "ReactDOM",
|
55
|
+
};
|
56
|
+
|
57
|
+
export default defineConfig({
|
58
|
+
plugins: [
|
59
|
+
react(),
|
60
|
+
viteAddCdnScript({
|
61
|
+
customScript: {
|
62
|
+
react: "<script src='https://cdn.jsdelivr.net/npm/react@17.0.2/umd/react.production.min.js'></script>",
|
63
|
+
"react-dom":
|
64
|
+
"<script src='https://cdn.jsdelivr.net/npm/react-dom@17.0.2/umd/react-dom.production.min.js'></script>",
|
65
|
+
},
|
66
|
+
}),
|
67
|
+
],
|
68
|
+
base: "./",
|
69
|
+
build: {
|
70
|
+
rollupOptions: {
|
71
|
+
external: [...Object.keys(externals)],
|
72
|
+
plugins: [externalGlobals(externals)],
|
73
|
+
},
|
74
|
+
},
|
75
|
+
});
|
76
|
+
```
|
77
|
+
|
78
|
+
options
|
79
|
+
|
80
|
+
| 参数 | 解析 | 类型 | 默认值 |
|
81
|
+
| ------------ | ------------------- | --------------------------- | --------------------- |
|
82
|
+
| customScript | 自定义 cdn 脚本 | { [*key*: string]: string } | 无 |
|
83
|
+
| defaultCdns | 默认使用 cdn 的顺序 | string[] | ["jsdelivr", "unpkg"] |
|
84
|
+
|
85
|
+
## 注意事项
|
86
|
+
|
87
|
+
- 接入了各大 cdn 的 api 接口进行请求,默认会保存一份 cdn 的缓存在你的根目录中`.cdn-cache.json`。如果发现缓存的资源有问题可以删除该文件,然后重新执行打包流程。
|
88
|
+
- 按顺序添加 cdn,如 react-router-dom 需要依赖 react、@remix-run/router、react-router,因此需要放在最后。
|
package/dist/index.js
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
var
|
2
|
-
var
|
3
|
-
var
|
4
|
-
import
|
5
|
-
import
|
6
|
-
import
|
7
|
-
import
|
8
|
-
class
|
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
9
|
constructor() {
|
10
|
-
|
11
|
-
|
12
|
-
this.cdnCachePath =
|
10
|
+
g(this, "cdnCache", {});
|
11
|
+
g(this, "cdnCachePath", "");
|
12
|
+
this.cdnCachePath = A.resolve(process.cwd(), "./.cdn-cache.json");
|
13
13
|
}
|
14
14
|
// 初始化cdn缓存
|
15
15
|
async init() {
|
16
16
|
try {
|
17
|
-
const t = await
|
17
|
+
const t = await E.readFileSync(this.cdnCachePath, "utf-8");
|
18
18
|
this.cdnCache = JSON.parse(t);
|
19
19
|
} catch {
|
20
|
-
console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await
|
20
|
+
console.log("cdn缓存文件不存在,创建缓存文件"), this.cdnCache = {}, await E.writeFileSync(this.cdnCachePath, "", "utf-8");
|
21
21
|
}
|
22
22
|
}
|
23
23
|
/**
|
@@ -44,36 +44,36 @@ class z {
|
|
44
44
|
* 更新cdn缓存
|
45
45
|
*/
|
46
46
|
async save() {
|
47
|
-
await
|
47
|
+
await E.writeFileSync(this.cdnCachePath, JSON.stringify(this.cdnCache), "utf-8");
|
48
48
|
}
|
49
49
|
}
|
50
|
-
let
|
51
|
-
const
|
50
|
+
let U;
|
51
|
+
const z = async () => (U || (U = new B(), await U.init()), U);
|
52
52
|
class u extends Error {
|
53
53
|
constructor(t) {
|
54
54
|
super(t), this.name = "NetworkError";
|
55
55
|
}
|
56
56
|
}
|
57
|
-
class
|
57
|
+
class P extends u {
|
58
58
|
constructor({ packageName: t, version: e, cdn: s }) {
|
59
59
|
super(`${s} ${t}@${e} 网络请求失败`), this.name = "PackageNetworkError";
|
60
60
|
}
|
61
61
|
}
|
62
|
-
class
|
62
|
+
class m extends Error {
|
63
63
|
constructor({ packageName: t, version: e, cdn: s }) {
|
64
64
|
super(`${s}上没有${t}@${e}的版本`), this.name = "NoVersionError";
|
65
65
|
}
|
66
66
|
}
|
67
|
-
class
|
67
|
+
class K extends Error {
|
68
68
|
constructor({ packageName: t, version: e, cdn: s }) {
|
69
69
|
super(`在 ${s} 中找不到 ${t}@${e} 文件,请检查包名或版本号`), this.name = "GetFileListError";
|
70
70
|
}
|
71
71
|
}
|
72
|
-
class
|
72
|
+
class N {
|
73
73
|
constructor(t) {
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
g(this, "_max");
|
75
|
+
g(this, "_count");
|
76
|
+
g(this, "_taskQueue");
|
77
77
|
this._max = t || 5, this._count = 0, this._taskQueue = [];
|
78
78
|
}
|
79
79
|
/**
|
@@ -105,18 +105,18 @@ class X {
|
|
105
105
|
};
|
106
106
|
}
|
107
107
|
}
|
108
|
-
const
|
108
|
+
const _ = new N(5), J = async (r) => {
|
109
109
|
try {
|
110
|
-
const t = await
|
111
|
-
return t.status >= 300 && t.status < 400 ? await
|
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
112
|
} catch (t) {
|
113
113
|
throw Promise.reject(new u(t.message));
|
114
114
|
}
|
115
|
-
},
|
115
|
+
}, W = {
|
116
116
|
//get请求封装
|
117
117
|
get: async (r) => {
|
118
118
|
try {
|
119
|
-
const t = await
|
119
|
+
const t = await O(r);
|
120
120
|
if (t.ok) {
|
121
121
|
const e = t.headers.get("content-type"), s = await t.text();
|
122
122
|
return e && e.includes("application/json") ? JSON.parse(s) : s;
|
@@ -126,23 +126,23 @@ const D = new X(5), M = async (r) => {
|
|
126
126
|
throw new u(t.message);
|
127
127
|
}
|
128
128
|
}
|
129
|
-
},
|
130
|
-
get:
|
131
|
-
},
|
129
|
+
}, $ = {
|
130
|
+
get: _.call.bind(_, W.get)
|
131
|
+
}, X = async (r, t) => {
|
132
132
|
try {
|
133
|
-
const e = await
|
133
|
+
const e = await $.get(`https://api.bootcdn.cn/libraries/${r}`);
|
134
134
|
if (e.length === 0)
|
135
|
-
throw new
|
135
|
+
throw new m({
|
136
136
|
packageName: r,
|
137
137
|
version: t,
|
138
138
|
cdn: "bootcdn"
|
139
139
|
});
|
140
140
|
const s = e[0], o = s.assets.reverse().find((c) => {
|
141
|
-
if (
|
141
|
+
if (V.satisfies(c.version, t))
|
142
142
|
return !0;
|
143
143
|
});
|
144
144
|
if (!o)
|
145
|
-
throw new
|
145
|
+
throw new m({
|
146
146
|
packageName: r,
|
147
147
|
version: t,
|
148
148
|
cdn: "bootcdn"
|
@@ -151,32 +151,32 @@ const D = new X(5), M = async (r) => {
|
|
151
151
|
name: "/" + c
|
152
152
|
})), recommendFileName: s.filename, version: o.version };
|
153
153
|
} catch (e) {
|
154
|
-
throw e instanceof u ? new
|
154
|
+
throw e instanceof u ? new P({
|
155
155
|
packageName: r,
|
156
156
|
version: t,
|
157
157
|
cdn: "unpkg"
|
158
158
|
}) : e;
|
159
159
|
}
|
160
|
-
},
|
161
|
-
getFileList:
|
162
|
-
getUrl:
|
160
|
+
}, Y = (r, t, e) => `https://cdn.bootcdn.net/ajax/libs/${r}/${t}${e}`, Z = {
|
161
|
+
getFileList: X,
|
162
|
+
getUrl: Y
|
163
163
|
};
|
164
|
-
async function
|
164
|
+
async function M(r, t, e = !1) {
|
165
165
|
try {
|
166
166
|
if (!e && t.match(/^\D/)) {
|
167
|
-
const n = await
|
167
|
+
const n = await et(r, t);
|
168
168
|
for (let o of n)
|
169
|
-
if (
|
170
|
-
return
|
171
|
-
throw new
|
169
|
+
if (V.satisfies(o, t))
|
170
|
+
return M(r, o, !0);
|
171
|
+
throw new m({
|
172
172
|
packageName: r,
|
173
173
|
version: t,
|
174
174
|
cdn: "cdnjs"
|
175
175
|
});
|
176
176
|
}
|
177
|
-
const s = await
|
177
|
+
const s = await $.get(`https://api.cdnjs.com/libraries/${r}/${t}`);
|
178
178
|
if (s.error)
|
179
|
-
throw new
|
179
|
+
throw new m({
|
180
180
|
packageName: r,
|
181
181
|
version: t,
|
182
182
|
cdn: "cdnjs"
|
@@ -188,62 +188,62 @@ async function I(r, t, e = !1) {
|
|
188
188
|
version: t
|
189
189
|
};
|
190
190
|
} catch (s) {
|
191
|
-
throw s instanceof u ? new
|
191
|
+
throw s instanceof u ? new P({
|
192
192
|
packageName: r,
|
193
193
|
version: t,
|
194
194
|
cdn: "unpkg"
|
195
195
|
}) : s;
|
196
196
|
}
|
197
197
|
}
|
198
|
-
const
|
198
|
+
const tt = (r, t, e) => `https://cdnjs.cloudflare.com/ajax/libs/${r}/${t}${e}`, et = async (r, t) => {
|
199
199
|
try {
|
200
|
-
return (await
|
200
|
+
return (await $.get(`https://api.cdnjs.com/libraries/${r}?fields=versions`)).versions;
|
201
201
|
} catch (e) {
|
202
|
-
throw e instanceof u ? new
|
202
|
+
throw e instanceof u ? new P({
|
203
203
|
packageName: r,
|
204
204
|
version: t,
|
205
205
|
cdn: "unpkg"
|
206
206
|
}) : e;
|
207
207
|
}
|
208
|
-
},
|
209
|
-
getFileList:
|
210
|
-
getUrl:
|
211
|
-
},
|
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
212
|
async function Q(r, t, e = !1) {
|
213
213
|
try {
|
214
214
|
if (!e && t.match(/^\D/)) {
|
215
|
-
const n = await
|
215
|
+
const n = await nt(r, t);
|
216
216
|
if (typeof n == "string")
|
217
217
|
return Q(r, n, !0);
|
218
|
-
throw new
|
218
|
+
throw new m({
|
219
219
|
packageName: r,
|
220
220
|
version: t,
|
221
221
|
cdn: "jsdelivr"
|
222
222
|
});
|
223
223
|
}
|
224
|
-
const s = await
|
224
|
+
const s = await $.get(`https://data.jsdelivr.com/v1/packages/npm/${r}@${t}`);
|
225
225
|
if (s.status)
|
226
|
-
throw new
|
226
|
+
throw new m({
|
227
227
|
packageName: r,
|
228
228
|
version: t,
|
229
229
|
cdn: "jsdelivr"
|
230
230
|
});
|
231
|
-
return { fileList:
|
231
|
+
return { fileList: I(s.files), version: t };
|
232
232
|
} catch (s) {
|
233
|
-
throw s instanceof u ? new
|
233
|
+
throw s instanceof u ? new P({
|
234
234
|
packageName: r,
|
235
235
|
version: t,
|
236
236
|
cdn: "unpkg"
|
237
237
|
}) : s;
|
238
238
|
}
|
239
239
|
}
|
240
|
-
const
|
240
|
+
const st = (r, t, e) => `https://cdn.jsdelivr.net/npm/${r}@${t}${e}`, nt = async (r, t) => {
|
241
241
|
try {
|
242
|
-
return (await
|
242
|
+
return (await $.get(
|
243
243
|
`https://data.jsdelivr.com/v1/packages/npm/${r}/resolved?specifier=${t}`
|
244
244
|
)).version;
|
245
245
|
} catch (e) {
|
246
|
-
throw e instanceof u ? new
|
246
|
+
throw e instanceof u ? new P({
|
247
247
|
packageName: r,
|
248
248
|
version: t,
|
249
249
|
cdn: "unpkg"
|
@@ -252,61 +252,61 @@ const nt = (r, t, e) => `https://cdn.jsdelivr.net/npm/${r}@${t}${e}`, ot = async
|
|
252
252
|
}, ct = {
|
253
253
|
getFileList: Q,
|
254
254
|
// 拼接url
|
255
|
-
getUrl:
|
256
|
-
},
|
257
|
-
async function
|
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
258
|
var e;
|
259
259
|
try {
|
260
|
-
const n = (e = (await
|
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
261
|
if (n) {
|
262
|
-
const o = await
|
263
|
-
return { fileList:
|
262
|
+
const o = await $.get(`https://unpkg.com/${r}@${n}/?meta`);
|
263
|
+
return { fileList: T(o.files || []), version: n };
|
264
264
|
} else
|
265
|
-
throw new
|
265
|
+
throw new m({
|
266
266
|
packageName: r,
|
267
267
|
version: t,
|
268
268
|
cdn: "unpkg"
|
269
269
|
});
|
270
270
|
} catch (s) {
|
271
|
-
throw s instanceof u ? new
|
271
|
+
throw s instanceof u ? new P({
|
272
272
|
packageName: r,
|
273
273
|
version: t,
|
274
274
|
cdn: "unpkg"
|
275
275
|
}) : s;
|
276
276
|
}
|
277
277
|
}
|
278
|
-
function
|
278
|
+
function it(r, t, e) {
|
279
279
|
return `https://unpkg.com/${r}@${t}${e}`;
|
280
280
|
}
|
281
|
-
const
|
282
|
-
getFileList:
|
283
|
-
getUrl:
|
284
|
-
},
|
281
|
+
const at = {
|
282
|
+
getFileList: ot,
|
283
|
+
getUrl: it
|
284
|
+
}, lt = async (r) => {
|
285
285
|
try {
|
286
286
|
const t = /^(https?:\/\/.*\d+\.\d+\.\d+\/).+?\.js$/;
|
287
287
|
if (t.test(r)) {
|
288
288
|
const e = r.replace(t, (s, n) => `${n}package.json`);
|
289
|
-
return await
|
289
|
+
return await $.get(e);
|
290
290
|
} else
|
291
291
|
throw new Error(`${r} 不是正确的url`);
|
292
292
|
} catch (t) {
|
293
293
|
throw t;
|
294
294
|
}
|
295
|
-
},
|
295
|
+
}, ut = (r, t) => {
|
296
296
|
var e, s;
|
297
297
|
return ((e = r.dependencies) == null ? void 0 : e[t]) || ((s = r.devDependencies) == null ? void 0 : s[t]);
|
298
|
-
},
|
298
|
+
}, dt = async (r, t, e) => {
|
299
299
|
if (!t.match(/\d+(.\d+)?(.\d+)?/))
|
300
300
|
throw new Error(`${r} version ${t} is not valid`);
|
301
|
-
const n = await
|
301
|
+
const n = await D[e].getFileList(r, t), o = ht(n, r);
|
302
302
|
if (!o)
|
303
|
-
throw new
|
303
|
+
throw new K({
|
304
304
|
packageName: r,
|
305
305
|
version: t,
|
306
306
|
cdn: e
|
307
307
|
});
|
308
|
-
return
|
309
|
-
},
|
308
|
+
return D[e].getUrl(r, n.version, o);
|
309
|
+
}, ht = ({ fileList: r }, t) => {
|
310
310
|
var o, a;
|
311
311
|
let e = [
|
312
312
|
`umd/${t}.production.min.js`,
|
@@ -328,16 +328,16 @@ const lt = {
|
|
328
328
|
const s = ["runtime", "compiler", ".esm", ".cjs", "development"].filter((c) => !t.includes(c));
|
329
329
|
let n = "";
|
330
330
|
for (let c of e)
|
331
|
-
if (c instanceof RegExp ? n = ((o = r.find((i) => c.test(i.name) && !s.some((
|
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
332
|
break;
|
333
333
|
return n;
|
334
|
-
},
|
334
|
+
}, D = {
|
335
335
|
jsdelivr: ct,
|
336
|
-
bootcdn:
|
337
|
-
cdnjs:
|
338
|
-
unpkg:
|
336
|
+
bootcdn: Z,
|
337
|
+
cdnjs: rt,
|
338
|
+
unpkg: at
|
339
339
|
};
|
340
|
-
function
|
340
|
+
function ft(r, t) {
|
341
341
|
const e = r.replace(/^\D/, "").split("."), s = t.replace(/^\D/, "").split("."), n = Math.max(e.length, s.length);
|
342
342
|
for (; e.length < n; )
|
343
343
|
e.push("0");
|
@@ -352,15 +352,15 @@ function pt(r, t) {
|
|
352
352
|
}
|
353
353
|
return 0;
|
354
354
|
}
|
355
|
-
function
|
355
|
+
function pt(r, t) {
|
356
356
|
for (let e in t)
|
357
|
-
Object.prototype.hasOwnProperty.call(t, e) && (r[e] ?
|
357
|
+
Object.prototype.hasOwnProperty.call(t, e) && (r[e] ? ft(r[e], t[e]) === -1 && (r[e] = t[e]) : r[e] = t[e]);
|
358
358
|
return r;
|
359
359
|
}
|
360
|
-
class
|
360
|
+
class wt {
|
361
361
|
constructor() {
|
362
362
|
// 打印记录
|
363
|
-
|
363
|
+
g(this, "logList", []);
|
364
364
|
}
|
365
365
|
// 打印方法
|
366
366
|
log(t) {
|
@@ -390,7 +390,7 @@ class gt {
|
|
390
390
|
// 打印全部
|
391
391
|
consoleAll() {
|
392
392
|
this.logList.forEach((t) => {
|
393
|
-
console[t.type](`${
|
393
|
+
console[t.type](`${H} ${t.message}`);
|
394
394
|
});
|
395
395
|
}
|
396
396
|
// 清除打印记录
|
@@ -398,18 +398,18 @@ class gt {
|
|
398
398
|
this.logList = [];
|
399
399
|
}
|
400
400
|
}
|
401
|
-
const
|
402
|
-
async function
|
401
|
+
const H = "vite-add-cdn-script", b = new wt();
|
402
|
+
async function R({
|
403
403
|
external: r,
|
404
404
|
packageData: t,
|
405
405
|
customScript: e,
|
406
406
|
defaultCdns: s
|
407
407
|
}) {
|
408
408
|
let n = [], o = !1;
|
409
|
-
const a = await
|
409
|
+
const a = await z();
|
410
410
|
return await Promise.all(
|
411
411
|
r.map(async (c) => {
|
412
|
-
const i =
|
412
|
+
const i = ut(t, c);
|
413
413
|
if (e[c])
|
414
414
|
return {
|
415
415
|
urls: [],
|
@@ -420,28 +420,28 @@ async function A({
|
|
420
420
|
urls: [],
|
421
421
|
key: c
|
422
422
|
};
|
423
|
-
const
|
424
|
-
if (
|
423
|
+
const f = a.getCdnCache(c, i);
|
424
|
+
if (f)
|
425
425
|
return {
|
426
|
-
urls:
|
426
|
+
urls: f,
|
427
427
|
key: c
|
428
428
|
};
|
429
429
|
{
|
430
430
|
o = !0, console.log(`从网络获取${c}${i}的cdn地址`);
|
431
|
-
const
|
432
|
-
s.map(async (
|
433
|
-
).then((
|
434
|
-
if (
|
435
|
-
return
|
436
|
-
|
437
|
-
}).map((
|
438
|
-
if (
|
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
439
|
throw new Error(`获取${c} ${i}的cdn地址失败`);
|
440
|
-
const
|
441
|
-
urls:
|
440
|
+
const y = {
|
441
|
+
urls: d,
|
442
442
|
key: c
|
443
443
|
};
|
444
|
-
return a.setCdnCache(c, i,
|
444
|
+
return a.setCdnCache(c, i, y.urls), y;
|
445
445
|
}
|
446
446
|
})
|
447
447
|
).then((c) => (o && a.save(), {
|
@@ -450,93 +450,93 @@ async function A({
|
|
450
450
|
}));
|
451
451
|
}
|
452
452
|
function Pt(r) {
|
453
|
-
const { customScript: t = {},
|
454
|
-
let
|
453
|
+
const { customScript: t = {}, defaultCdns: e = ["jsdelivr", "unpkg"] } = r;
|
454
|
+
let s;
|
455
455
|
return {
|
456
|
-
name:
|
456
|
+
name: H,
|
457
457
|
enforce: "pre",
|
458
458
|
apply: "build",
|
459
|
-
config(
|
460
|
-
|
459
|
+
config(n) {
|
460
|
+
s = n;
|
461
461
|
},
|
462
|
-
async transformIndexHtml(
|
463
|
-
var
|
464
|
-
if (!
|
462
|
+
async transformIndexHtml(n) {
|
463
|
+
var a, c;
|
464
|
+
if (!e || e.length === 0)
|
465
465
|
throw new Error("defaultCdns不能为空");
|
466
|
-
const
|
466
|
+
const o = A.resolve(process.cwd(), "package.json");
|
467
467
|
try {
|
468
|
-
const
|
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
469
|
if (!d)
|
470
|
-
return
|
471
|
-
let
|
470
|
+
return n;
|
471
|
+
let y = [];
|
472
472
|
if (typeof d == "string")
|
473
|
-
|
473
|
+
y = [d];
|
474
474
|
else if (Array.isArray(d))
|
475
|
-
|
475
|
+
y = d.filter((w) => typeof w == "string");
|
476
476
|
else if (typeof d == "object")
|
477
|
-
return
|
478
|
-
const
|
479
|
-
let
|
480
|
-
const { urls:
|
481
|
-
external:
|
482
|
-
packageData:
|
477
|
+
return n;
|
478
|
+
const j = {};
|
479
|
+
let l = "";
|
480
|
+
const { urls: S, noVersionPackages: F } = await R({
|
481
|
+
external: y,
|
482
|
+
packageData: f,
|
483
483
|
customScript: t,
|
484
|
-
defaultCdns:
|
484
|
+
defaultCdns: e
|
485
485
|
});
|
486
|
-
if (
|
487
|
-
const
|
486
|
+
if (F.length > 0) {
|
487
|
+
const w = { dependencies: {} };
|
488
488
|
await Promise.allSettled(
|
489
|
-
|
489
|
+
S.map(async (h) => {
|
490
490
|
if (!h)
|
491
491
|
return;
|
492
|
-
const { key:
|
493
|
-
if (!
|
492
|
+
const { key: C, urls: v } = h, k = t[C] || v[0];
|
493
|
+
if (!k)
|
494
494
|
return;
|
495
|
-
const x = await
|
496
|
-
|
495
|
+
const x = await lt(k);
|
496
|
+
pt(w.dependencies, x.dependencies);
|
497
497
|
})
|
498
498
|
).then((h) => {
|
499
|
-
h.forEach((
|
500
|
-
|
499
|
+
h.forEach((C) => {
|
500
|
+
C.status === "rejected" && b.warn(C.reason.toString());
|
501
501
|
});
|
502
502
|
});
|
503
|
-
const { urls:
|
504
|
-
external:
|
505
|
-
packageData:
|
503
|
+
const { urls: L, noVersionPackages: p } = await R({
|
504
|
+
external: F,
|
505
|
+
packageData: w,
|
506
506
|
customScript: t,
|
507
|
-
defaultCdns:
|
507
|
+
defaultCdns: e
|
508
508
|
});
|
509
|
-
if (
|
510
|
-
var
|
509
|
+
if (L.map((h) => {
|
510
|
+
var k;
|
511
511
|
if (!h)
|
512
512
|
return;
|
513
|
-
const { urls:
|
514
|
-
(
|
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
515
|
}), p.length > 0)
|
516
516
|
throw console.error(`找不到${p.join(",")}的版本`), new Error(`找不到${p.join(",")}的版本`);
|
517
517
|
}
|
518
|
-
return
|
519
|
-
if (!
|
518
|
+
return b.consoleAll(), S.forEach((w) => {
|
519
|
+
if (!w)
|
520
520
|
return;
|
521
|
-
const { urls:
|
521
|
+
const { urls: L, key: p } = w;
|
522
522
|
if (t[p])
|
523
|
-
|
523
|
+
l += t[p];
|
524
524
|
else {
|
525
|
-
|
526
|
-
const h =
|
527
|
-
|
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
528
|
`;
|
529
529
|
}
|
530
|
-
}),
|
530
|
+
}), l = `<script>
|
531
531
|
function errorCDN(e) {
|
532
|
-
const packNameUrl = JSON.parse('${JSON.stringify(
|
532
|
+
const packNameUrl = JSON.parse('${JSON.stringify(j)}');
|
533
533
|
const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
|
534
|
-
if(nextCur>${e}){return;}
|
535
534
|
|
536
535
|
const key = e.getAttribute("data-key");
|
537
|
-
|
536
|
+
const curPackNameUrl = packNameUrl[key]
|
537
|
+
if(nextCur>=curPackNameUrl.length){return;}
|
538
538
|
// 新的cdn链接
|
539
|
-
const url =
|
539
|
+
const url = curPackNameUrl[nextCur]
|
540
540
|
// 克隆原标签
|
541
541
|
const tagName = e.tagName
|
542
542
|
const cdnDOM = document.createElement(tagName);
|
@@ -549,14 +549,14 @@ function Pt(r) {
|
|
549
549
|
document.head.appendChild(cdnDOM);
|
550
550
|
e.remove();
|
551
551
|
}
|
552
|
-
<\/script>` +
|
553
|
-
} catch (
|
554
|
-
|
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);
|
555
555
|
}
|
556
556
|
}
|
557
557
|
};
|
558
558
|
}
|
559
559
|
export {
|
560
560
|
Pt as default,
|
561
|
-
|
561
|
+
H as libName
|
562
562
|
};
|
package/dist/index.umd.cjs
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
(function(
|
2
|
-
`}}),
|
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
3
|
function errorCDN(e) {
|
4
|
-
const packNameUrl = JSON.parse('${JSON.stringify(
|
4
|
+
const packNameUrl = JSON.parse('${JSON.stringify(x)}');
|
5
5
|
const nextCur = parseInt(e.getAttribute("data-cur")) + 1;
|
6
|
-
if(nextCur>${e}){return;}
|
7
6
|
|
8
7
|
const key = e.getAttribute("data-key");
|
9
|
-
|
8
|
+
const curPackNameUrl = packNameUrl[key]
|
9
|
+
if(nextCur>=curPackNameUrl.length){return;}
|
10
10
|
// 新的cdn链接
|
11
|
-
const url =
|
11
|
+
const url = curPackNameUrl[nextCur]
|
12
12
|
// 克隆原标签
|
13
13
|
const tagName = e.tagName
|
14
14
|
const cdnDOM = document.createElement(tagName);
|
@@ -21,4 +21,4 @@
|
|
21
21
|
document.head.appendChild(cdnDOM);
|
22
22
|
e.remove();
|
23
23
|
}
|
24
|
-
<\/script>`+
|
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"}})});
|
package/index.d.ts
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
interface IOptions {
|
2
|
-
customScript?: { [key: string]: string };
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
export default function viteAddCdnScript(options: IOptions);
|
1
|
+
interface IOptions {
|
2
|
+
customScript?: { [key: string]: string };
|
3
|
+
defaultCdns?: string[];
|
4
|
+
}
|
5
|
+
export default function viteAddCdnScript(options: IOptions);
|
package/package.json
CHANGED
@@ -1,64 +1,64 @@
|
|
1
|
-
{
|
2
|
-
"name": "vite-add-cdn-script",
|
3
|
-
"version": "0.0.
|
4
|
-
"keywords": [
|
5
|
-
"vite",
|
6
|
-
"cdn",
|
7
|
-
"cdn-script",
|
8
|
-
"auto-add-cdn",
|
9
|
-
"vite-add-cdn-script"
|
10
|
-
],
|
11
|
-
"description": "A plugin for vite to add cdn script to index.html",
|
12
|
-
"repository": {
|
13
|
-
"type": "git",
|
14
|
-
"url": "git+https://github.com/baizeteam/baize-
|
15
|
-
},
|
16
|
-
"homepage": "https://github.com/baizeteam/baize-
|
17
|
-
"author": "baizeteam",
|
18
|
-
"type": "module",
|
19
|
-
"files": [
|
20
|
-
"dist",
|
21
|
-
"index.d.ts"
|
22
|
-
],
|
23
|
-
"main": "./dist/index.umd.cjs",
|
24
|
-
"module": "./dist/index.js",
|
25
|
-
"types": "./index.d.ts",
|
26
|
-
"exports": {
|
27
|
-
"types": "./index.d.ts",
|
28
|
-
"import": "./dist/index.js",
|
29
|
-
"require": "./dist/index.js"
|
30
|
-
},
|
31
|
-
"
|
32
|
-
"
|
33
|
-
"
|
34
|
-
"
|
35
|
-
"
|
36
|
-
|
37
|
-
|
38
|
-
"@
|
39
|
-
"
|
40
|
-
"
|
41
|
-
"
|
42
|
-
"
|
43
|
-
"
|
44
|
-
"
|
45
|
-
"
|
46
|
-
"jest": "^29.
|
47
|
-
"
|
48
|
-
"
|
49
|
-
"
|
50
|
-
|
51
|
-
|
52
|
-
"
|
53
|
-
|
54
|
-
|
55
|
-
"
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
"
|
62
|
-
"
|
63
|
-
}
|
64
|
-
}
|
1
|
+
{
|
2
|
+
"name": "vite-add-cdn-script",
|
3
|
+
"version": "0.0.11",
|
4
|
+
"keywords": [
|
5
|
+
"vite",
|
6
|
+
"cdn",
|
7
|
+
"cdn-script",
|
8
|
+
"auto-add-cdn",
|
9
|
+
"vite-add-cdn-script"
|
10
|
+
],
|
11
|
+
"description": "A plugin for vite to add cdn script to index.html",
|
12
|
+
"repository": {
|
13
|
+
"type": "git",
|
14
|
+
"url": "git+https://github.com/baizeteam/baize-package.git"
|
15
|
+
},
|
16
|
+
"homepage": "https://github.com/baizeteam/baize-package/tree/release/package/vite-add-cdn-script#readme",
|
17
|
+
"author": "baizeteam",
|
18
|
+
"type": "module",
|
19
|
+
"files": [
|
20
|
+
"dist",
|
21
|
+
"index.d.ts"
|
22
|
+
],
|
23
|
+
"main": "./dist/index.umd.cjs",
|
24
|
+
"module": "./dist/index.js",
|
25
|
+
"types": "./index.d.ts",
|
26
|
+
"exports": {
|
27
|
+
"types": "./index.d.ts",
|
28
|
+
"import": "./dist/index.js",
|
29
|
+
"require": "./dist/index.js"
|
30
|
+
},
|
31
|
+
"devDependencies": {
|
32
|
+
"@jest/globals": "^29.7.0",
|
33
|
+
"@types/node": "^20.12.11",
|
34
|
+
"@types/node-fetch": "2",
|
35
|
+
"@types/react": "^18.3.2",
|
36
|
+
"@types/react-dom": "^18.3.0",
|
37
|
+
"@types/semver": "^7.5.8",
|
38
|
+
"@vitejs/plugin-react": "^4.2.1",
|
39
|
+
"cross-env": "^7.0.3",
|
40
|
+
"jest": "^29.7.0",
|
41
|
+
"react": "^18.2.0",
|
42
|
+
"react-dom": "^18.2.0",
|
43
|
+
"react-router-dom": "^6.23.1",
|
44
|
+
"rollup-plugin-external-globals": "^0.10.0",
|
45
|
+
"rollup-plugin-node-externals": "^7.1.2",
|
46
|
+
"ts-jest": "^29.1.4",
|
47
|
+
"ts-node": "^10.9.2",
|
48
|
+
"typescript": "^5.4.5",
|
49
|
+
"vite": "^5.2.11"
|
50
|
+
},
|
51
|
+
"publishConfig": {
|
52
|
+
"registry": "https://registry.npmjs.org/"
|
53
|
+
},
|
54
|
+
"dependencies": {
|
55
|
+
"node-fetch": "2",
|
56
|
+
"semver": "^7.6.2"
|
57
|
+
},
|
58
|
+
"scripts": {
|
59
|
+
"dev": "vite",
|
60
|
+
"build:page": "tsc && cross-env BUILD_MODE=page vite build",
|
61
|
+
"build": "tsc && cross-env BUILD_MODE=lib vite build",
|
62
|
+
"test": "jest"
|
63
|
+
}
|
64
|
+
}
|