vite-plugin-external-cdn 1.0.0

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 ADDED
@@ -0,0 +1,15 @@
1
+ ISC LICENSE
2
+
3
+ Copyright 2023-PRESENT ZuoJt
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose
6
+ with or without fee is hereby granted, provided that the above copyright notice
7
+ and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ <div align="center">
2
+ <a href="https://vitejs.dev/">
3
+ <img width="200" height="200" hspace="10" src="https://vitejs.dev/logo.svg" alt="vite logo" />
4
+ </a>
5
+ <h1>Vite External CDN</h1>
6
+ <p>
7
+ A <a href="https://vitejs.dev/">Vite</a> plugin to convert dependencies to cdn at build time usingPlugin for <a href="https://github.com/eight04/rollup-plugin-external-globals">rollup-plugin-external-globals</a>.
8
+ </p>
9
+ </div>
10
+
11
+ ## Installation
12
+
13
+ Install the plugin with npm:
14
+
15
+ ```
16
+ npm install vite-plugin-external-cdn --save-dev
17
+ ```
18
+
19
+ or yarn
20
+
21
+ ```
22
+ yarn add vite-plugin-external-cdn -D
23
+ ```
24
+
25
+ ## Basic Usage
26
+
27
+ Add it to vite.config.js
28
+
29
+ ```js
30
+ // vite.config.js
31
+ import reactRefresh from '@vitejs/plugin-react-refresh'
32
+ import transformExternalCDN from 'vite-plugin-external-cdn'
33
+
34
+ export default {
35
+ plugins: [
36
+ transformExternalCDN({
37
+ modules: [
38
+ {
39
+ name: 'react',
40
+ var: 'React',
41
+ path: `umd/react.production.min.js`,
42
+ },
43
+ {
44
+ name: 'react-dom',
45
+ var: 'ReactDOM',
46
+ path: `umd/react-dom.production.min.js`,
47
+ },
48
+ ],
49
+ }),
50
+ ],
51
+ }
52
+ ```
53
+
54
+ ### Use autoComplete
55
+
56
+ ```js
57
+ // vite.config.js
58
+ import reactRefresh from '@vitejs/plugin-react-refresh'
59
+ import transformExternalCDN, { autoComplete } from 'vite-plugin-external-cdn'
60
+
61
+ export default {
62
+ plugins: [
63
+ transformExternalCDN({
64
+ modules: [
65
+ autoComplete('react'),
66
+ autoComplete('react-dom')
67
+ ],
68
+ }),
69
+ reactRefresh(),
70
+ ],
71
+ }
72
+ ```
73
+
74
+ ### Autocomplete supported modules
75
+
76
+ ```
77
+ "react" | "react-dom" | "react-router-dom" |
78
+ "antd" | "ahooks" | "@ant-design/charts" |
79
+ "vue" | "vue2" | "@vueuse/shared" |
80
+ "@vueuse/core" | "moment" |
81
+ "eventemitter3" | "file-saver" |
82
+ "browser-md5-file" | "xlsx | "crypto-js" |
83
+ "axios" | "lodash" | "localforage"
84
+ ```
85
+
86
+ ### VueUse demo
87
+
88
+ ```js
89
+ import vue from '@vitejs/plugin-vue'
90
+ import importToCDN, { autoComplete } from 'vite-plugin-cdn-import'
91
+
92
+ export default {
93
+ plugins: [
94
+ vue(),
95
+ importToCDN({
96
+ modules: [
97
+ autoComplete('vue'), // vue2 use autoComplete('vue2')
98
+ autoComplete('@vueuse/shared'),
99
+ autoComplete('@vueuse/core')
100
+ ],
101
+ }),
102
+ ],
103
+ }
104
+ ```
105
+
106
+ ## Options
107
+
108
+ | Name | Description | Type | Default |
109
+ | ------- | -------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------ |
110
+ | prodUrl | Overrides the global prodUrl, allowing you to specify the CDN location for a specific module | string | <https://cdn.jsdelivr.net/npm/{name}@{version}/{path}> |
111
+ | modules | Modules config | Array`<Module>` / Array`<(prodUrl:string) => Module>` | - |
112
+
113
+ ### Module
114
+
115
+ | Name | Description | Type |
116
+ | ---- | ------------------------------------------------------------------------------------- | ----------------- |
117
+ | name | The name of the module you want to externalize | string |
118
+ | var | A variable that will be assigned to the module in global scope, Rollup requires this | string |
119
+ | path | Specify the load path on the CDN | string / string[] |
120
+ | css | You can alternatively specify multiple style sheets which will be loaded from the CDN | string / string[] |
121
+
122
+ ## Other CDN prodUrl
123
+
124
+ | Name | pordUrl |
125
+ | ----- | -------------------------------------------------------- |
126
+ | unpkg | //unpkg.com/{name}@{version}/{path} |
127
+ | cdnjs | //cdnjs.cloudflare.com/ajax/libs/{name}/{version}/{path} |
128
+
129
+ ## Resources
130
+
131
+ - [webpack-cdn-plugin](https://github.com/shirotech/webpack-cdn-plugin)
132
+ - [rollup-plugin-external-globals](https://github.com/eight04/rollup-plugin-external-globals)
@@ -0,0 +1,138 @@
1
+ import { PluginOption } from 'vite';
2
+
3
+ interface Module {
4
+ name: string;
5
+ var: string;
6
+ path: string | string[];
7
+ version?: string;
8
+ css?: string | string[];
9
+ }
10
+ interface Options {
11
+ modules: (Module | ((prodUrl: string) => Module))[];
12
+ prodUrl?: string;
13
+ }
14
+
15
+ declare function transformExternalCDN(options: Options): PluginOption | PluginOption[];
16
+
17
+ declare const modulesConfig: {
18
+ react: {
19
+ var: string;
20
+ jsdeliver: {
21
+ path: string;
22
+ };
23
+ };
24
+ 'react-dom': {
25
+ var: string;
26
+ jsdeliver: {
27
+ path: string;
28
+ };
29
+ };
30
+ 'react-router-dom': {
31
+ var: string;
32
+ jsdeliver: {
33
+ path: string;
34
+ };
35
+ };
36
+ antd: {
37
+ var: string;
38
+ jsdeliver: {
39
+ path: string;
40
+ css: string;
41
+ };
42
+ };
43
+ ahooks: {
44
+ var: string;
45
+ jsdeliver: {
46
+ path: string;
47
+ };
48
+ };
49
+ '@ant-design/charts': {
50
+ var: string;
51
+ jsdeliver: {
52
+ path: string;
53
+ };
54
+ };
55
+ vue: {
56
+ var: string;
57
+ jsdeliver: {
58
+ path: string;
59
+ };
60
+ };
61
+ vue2: {
62
+ var: string;
63
+ jsdeliver: {
64
+ name: string;
65
+ path: string;
66
+ };
67
+ };
68
+ '@vueuse/shared': {
69
+ var: string;
70
+ jsdeliver: {
71
+ path: string;
72
+ };
73
+ };
74
+ '@vueuse/core': {
75
+ var: string;
76
+ jsdeliver: {
77
+ path: string;
78
+ };
79
+ };
80
+ moment: {
81
+ var: string;
82
+ jsdeliver: {
83
+ path: string;
84
+ };
85
+ };
86
+ eventemitter3: {
87
+ var: string;
88
+ jsdeliver: {
89
+ path: string;
90
+ };
91
+ };
92
+ 'file-saver': {
93
+ var: string;
94
+ jsdeliver: {
95
+ path: string;
96
+ };
97
+ };
98
+ 'browser-md5-file': {
99
+ var: string;
100
+ jsdeliver: {
101
+ path: string;
102
+ };
103
+ };
104
+ xlsx: {
105
+ var: string;
106
+ jsdeliver: {
107
+ path: string;
108
+ };
109
+ };
110
+ axios: {
111
+ var: string;
112
+ jsdeliver: {
113
+ path: string;
114
+ };
115
+ };
116
+ lodash: {
117
+ var: string;
118
+ jsdeliver: {
119
+ path: string;
120
+ };
121
+ };
122
+ 'crypto-js': {
123
+ var: string;
124
+ jsdeliver: {
125
+ path: string;
126
+ };
127
+ };
128
+ localforage: {
129
+ var: string;
130
+ jsdeliver: {
131
+ path: string;
132
+ };
133
+ };
134
+ };
135
+ type ModuleName = keyof typeof modulesConfig;
136
+ declare function autoComplete(name: ModuleName): (prodUrl: string) => Module;
137
+
138
+ export { Options, transformExternalCDN as PluginExternalCDN, autoComplete, transformExternalCDN as default };
@@ -0,0 +1,138 @@
1
+ import { PluginOption } from 'vite';
2
+
3
+ interface Module {
4
+ name: string;
5
+ var: string;
6
+ path: string | string[];
7
+ version?: string;
8
+ css?: string | string[];
9
+ }
10
+ interface Options {
11
+ modules: (Module | ((prodUrl: string) => Module))[];
12
+ prodUrl?: string;
13
+ }
14
+
15
+ declare function transformExternalCDN(options: Options): PluginOption | PluginOption[];
16
+
17
+ declare const modulesConfig: {
18
+ react: {
19
+ var: string;
20
+ jsdeliver: {
21
+ path: string;
22
+ };
23
+ };
24
+ 'react-dom': {
25
+ var: string;
26
+ jsdeliver: {
27
+ path: string;
28
+ };
29
+ };
30
+ 'react-router-dom': {
31
+ var: string;
32
+ jsdeliver: {
33
+ path: string;
34
+ };
35
+ };
36
+ antd: {
37
+ var: string;
38
+ jsdeliver: {
39
+ path: string;
40
+ css: string;
41
+ };
42
+ };
43
+ ahooks: {
44
+ var: string;
45
+ jsdeliver: {
46
+ path: string;
47
+ };
48
+ };
49
+ '@ant-design/charts': {
50
+ var: string;
51
+ jsdeliver: {
52
+ path: string;
53
+ };
54
+ };
55
+ vue: {
56
+ var: string;
57
+ jsdeliver: {
58
+ path: string;
59
+ };
60
+ };
61
+ vue2: {
62
+ var: string;
63
+ jsdeliver: {
64
+ name: string;
65
+ path: string;
66
+ };
67
+ };
68
+ '@vueuse/shared': {
69
+ var: string;
70
+ jsdeliver: {
71
+ path: string;
72
+ };
73
+ };
74
+ '@vueuse/core': {
75
+ var: string;
76
+ jsdeliver: {
77
+ path: string;
78
+ };
79
+ };
80
+ moment: {
81
+ var: string;
82
+ jsdeliver: {
83
+ path: string;
84
+ };
85
+ };
86
+ eventemitter3: {
87
+ var: string;
88
+ jsdeliver: {
89
+ path: string;
90
+ };
91
+ };
92
+ 'file-saver': {
93
+ var: string;
94
+ jsdeliver: {
95
+ path: string;
96
+ };
97
+ };
98
+ 'browser-md5-file': {
99
+ var: string;
100
+ jsdeliver: {
101
+ path: string;
102
+ };
103
+ };
104
+ xlsx: {
105
+ var: string;
106
+ jsdeliver: {
107
+ path: string;
108
+ };
109
+ };
110
+ axios: {
111
+ var: string;
112
+ jsdeliver: {
113
+ path: string;
114
+ };
115
+ };
116
+ lodash: {
117
+ var: string;
118
+ jsdeliver: {
119
+ path: string;
120
+ };
121
+ };
122
+ 'crypto-js': {
123
+ var: string;
124
+ jsdeliver: {
125
+ path: string;
126
+ };
127
+ };
128
+ localforage: {
129
+ var: string;
130
+ jsdeliver: {
131
+ path: string;
132
+ };
133
+ };
134
+ };
135
+ type ModuleName = keyof typeof modulesConfig;
136
+ declare function autoComplete(name: ModuleName): (prodUrl: string) => Module;
137
+
138
+ export { Options, transformExternalCDN as PluginExternalCDN, autoComplete, transformExternalCDN as default };
package/dist/index.js ADDED
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ PluginExternalCDN: () => transformExternalCDN,
34
+ autoComplete: () => autoComplete,
35
+ default: () => src_default
36
+ });
37
+ module.exports = __toCommonJS(src_exports);
38
+
39
+ // src/transform.ts
40
+ var import_rollup_plugin_external_globals = __toESM(require("rollup-plugin-external-globals"));
41
+ var fs = __toESM(require("fs"));
42
+ var path = __toESM(require("path"));
43
+ var process = __toESM(require("process"));
44
+
45
+ // src/utils.ts
46
+ var isFullPath = (path2) => {
47
+ return path2.startsWith("http:") || path2.startsWith("https:") || path2.startsWith("//");
48
+ };
49
+ var generateUrl = (url, data) => {
50
+ const { name, version, path: path2 } = data;
51
+ if (isFullPath(path2)) {
52
+ url = path2;
53
+ }
54
+ return url.replace(/\{name\}/g, name).replace(/\{version\}/g, version).replace(/\{path\}/g, path2);
55
+ };
56
+
57
+ // src/transform.ts
58
+ function getDepsVersion(name) {
59
+ const pwd = process.cwd();
60
+ const pkg = path.join(pwd, "node_modules", name, "package.json");
61
+ if (name && fs.existsSync(pkg)) {
62
+ const pkgJson = JSON.parse(fs.readFileSync(pkg, "utf8"));
63
+ return pkgJson.version;
64
+ }
65
+ return "";
66
+ }
67
+ function generateExternals(options) {
68
+ const { modules = [], prodUrl = "https://cdn.jsdelivr.net/npm/{name}@{version}/{path}" } = options;
69
+ return modules.map((m) => {
70
+ let v;
71
+ if (typeof m === "function") {
72
+ v = m(prodUrl);
73
+ } else {
74
+ v = m;
75
+ }
76
+ const version = getDepsVersion(v.name);
77
+ let pathList = [];
78
+ if (!Array.isArray(v.path)) {
79
+ pathList.push(v.path);
80
+ } else {
81
+ pathList = v.path;
82
+ }
83
+ const data = {
84
+ ...v,
85
+ version
86
+ };
87
+ pathList = pathList.map((p) => {
88
+ if (!version && !isFullPath(p)) {
89
+ throw new Error(`modules: ${data.name} package.json file does not exist`);
90
+ }
91
+ return generateUrl(prodUrl, {
92
+ ...data,
93
+ path: p
94
+ });
95
+ });
96
+ let css = v.css || [];
97
+ if (!Array.isArray(css) && css) {
98
+ css = [css];
99
+ }
100
+ const cssList = !Array.isArray(css) ? [] : css.map(
101
+ (c) => generateUrl(prodUrl, {
102
+ ...data,
103
+ path: c
104
+ })
105
+ );
106
+ return {
107
+ ...v,
108
+ version,
109
+ pathList,
110
+ cssList
111
+ };
112
+ });
113
+ }
114
+ function transformExternalCDN(options) {
115
+ let isBuild = false;
116
+ const externalMap = {};
117
+ const externals = generateExternals(options);
118
+ externals.forEach((v) => {
119
+ externalMap[v.name] = v.var;
120
+ });
121
+ const externalLibs = Object.keys(externalMap);
122
+ const plugin = [
123
+ {
124
+ name: "vite-plugin-external-cdn",
125
+ enforce: "post",
126
+ apply: "build",
127
+ ...(0, import_rollup_plugin_external_globals.default)(externalMap)
128
+ },
129
+ {
130
+ config(config, { command }) {
131
+ const userConfig = {
132
+ build: {
133
+ rollupOptions: {}
134
+ }
135
+ };
136
+ if (command === "build") {
137
+ isBuild = true;
138
+ userConfig.build.rollupOptions = {
139
+ external: [...externalLibs]
140
+ };
141
+ } else {
142
+ isBuild = false;
143
+ }
144
+ return userConfig;
145
+ },
146
+ transformIndexHtml(html) {
147
+ const cssCode = externals.map((v) => v.cssList.map((css) => `<link href="${css}" rel="stylesheet">`).join("\n")).filter((v) => v).join("\n");
148
+ const jsCode = !isBuild ? "" : externals.map((p) => p.pathList.map((url) => `<script src="${url}"></script>`).join("\n")).join("\n");
149
+ return html.replace(/<\/title>/i, `</title>${cssCode}
150
+ ${jsCode}`);
151
+ }
152
+ }
153
+ ];
154
+ return plugin;
155
+ }
156
+
157
+ // src/preset.ts
158
+ var modulesConfig = {
159
+ react: {
160
+ var: "React",
161
+ jsdeliver: {
162
+ path: "umd/react.production.min.js"
163
+ }
164
+ },
165
+ "react-dom": {
166
+ var: "ReactDOM",
167
+ jsdeliver: {
168
+ path: "umd/react-dom.production.min.js"
169
+ }
170
+ },
171
+ "react-router-dom": {
172
+ var: "ReactRouterDOM",
173
+ jsdeliver: {
174
+ path: "umd/react-router-dom.min.js"
175
+ }
176
+ },
177
+ antd: {
178
+ var: "antd",
179
+ jsdeliver: {
180
+ path: "dist/antd.min.js",
181
+ css: "dist/antd.min.css"
182
+ }
183
+ },
184
+ ahooks: {
185
+ var: "ahooks",
186
+ jsdeliver: {
187
+ path: "dist/ahooks.js"
188
+ }
189
+ },
190
+ "@ant-design/charts": {
191
+ var: "charts",
192
+ jsdeliver: {
193
+ path: "dist/charts.min.js"
194
+ }
195
+ },
196
+ vue: {
197
+ var: "Vue",
198
+ jsdeliver: {
199
+ path: "dist/vue.global.prod.js"
200
+ }
201
+ },
202
+ vue2: {
203
+ var: "Vue",
204
+ jsdeliver: {
205
+ name: "vue",
206
+ path: "dist/vue.runtime.min.js"
207
+ }
208
+ },
209
+ "@vueuse/shared": {
210
+ var: "VueUse",
211
+ jsdeliver: {
212
+ path: "index.iife.min.js"
213
+ }
214
+ },
215
+ "@vueuse/core": {
216
+ var: "VueUse",
217
+ jsdeliver: {
218
+ path: "index.iife.min.js"
219
+ }
220
+ },
221
+ moment: {
222
+ var: "moment",
223
+ jsdeliver: {
224
+ path: "moment.min.js"
225
+ }
226
+ },
227
+ eventemitter3: {
228
+ var: "EventEmitter3",
229
+ jsdeliver: {
230
+ path: "umd/eventemitter3.min.js"
231
+ }
232
+ },
233
+ "file-saver": {
234
+ var: "window",
235
+ jsdeliver: {
236
+ path: "dist/FileSaver.min.js"
237
+ }
238
+ },
239
+ "browser-md5-file": {
240
+ var: "browserMD5File",
241
+ jsdeliver: {
242
+ path: "dist/index.umd.min.js"
243
+ }
244
+ },
245
+ xlsx: {
246
+ var: "XLSX",
247
+ jsdeliver: {
248
+ path: "dist/xlsx.full.min.js"
249
+ }
250
+ },
251
+ axios: {
252
+ var: "axios",
253
+ jsdeliver: {
254
+ path: "dist/axios.min.js"
255
+ }
256
+ },
257
+ lodash: {
258
+ var: "_",
259
+ jsdeliver: {
260
+ path: "lodash.min.js"
261
+ }
262
+ },
263
+ "crypto-js": {
264
+ var: "crypto-js",
265
+ jsdeliver: {
266
+ path: "crypto-js.min.js"
267
+ }
268
+ },
269
+ localforage: {
270
+ var: "localforage",
271
+ jsdeliver: {
272
+ path: "dist/localforage.min.js"
273
+ }
274
+ }
275
+ };
276
+ function isJsdeliver(prodUrl) {
277
+ return prodUrl.includes("//cdn.jsdelivr.net");
278
+ }
279
+ function isUnpkg(prodUrl) {
280
+ return prodUrl.includes("//unpkg.com");
281
+ }
282
+ function isCdnjs(prodUrl) {
283
+ return prodUrl.includes("//cdnjs.cloudflare.com");
284
+ }
285
+ function autoComplete(name) {
286
+ const config = modulesConfig[name];
287
+ if (!config) {
288
+ throw new Error(`The configuration of module ${name} does not exist `);
289
+ }
290
+ return (prodUrl) => {
291
+ if (isCdnjs(prodUrl)) {
292
+ throw new Error(`The configuration of module ${name} in ${prodUrl} does not exist `);
293
+ } else {
294
+ if (!(isJsdeliver(prodUrl) || isUnpkg(prodUrl))) {
295
+ console.warn("Unknown prodUrl, using the jsdeliver rule");
296
+ }
297
+ return {
298
+ name,
299
+ var: config.var,
300
+ ...config.jsdeliver
301
+ };
302
+ }
303
+ };
304
+ }
305
+
306
+ // src/index.ts
307
+ var src_default = transformExternalCDN;
308
+ // Annotate the CommonJS export names for ESM import in node:
309
+ 0 && (module.exports = {
310
+ PluginExternalCDN,
311
+ autoComplete
312
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,274 @@
1
+ // src/transform.ts
2
+ import externalGlobals from "rollup-plugin-external-globals";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import * as process from "process";
6
+
7
+ // src/utils.ts
8
+ var isFullPath = (path2) => {
9
+ return path2.startsWith("http:") || path2.startsWith("https:") || path2.startsWith("//");
10
+ };
11
+ var generateUrl = (url, data) => {
12
+ const { name, version, path: path2 } = data;
13
+ if (isFullPath(path2)) {
14
+ url = path2;
15
+ }
16
+ return url.replace(/\{name\}/g, name).replace(/\{version\}/g, version).replace(/\{path\}/g, path2);
17
+ };
18
+
19
+ // src/transform.ts
20
+ function getDepsVersion(name) {
21
+ const pwd = process.cwd();
22
+ const pkg = path.join(pwd, "node_modules", name, "package.json");
23
+ if (name && fs.existsSync(pkg)) {
24
+ const pkgJson = JSON.parse(fs.readFileSync(pkg, "utf8"));
25
+ return pkgJson.version;
26
+ }
27
+ return "";
28
+ }
29
+ function generateExternals(options) {
30
+ const { modules = [], prodUrl = "https://cdn.jsdelivr.net/npm/{name}@{version}/{path}" } = options;
31
+ return modules.map((m) => {
32
+ let v;
33
+ if (typeof m === "function") {
34
+ v = m(prodUrl);
35
+ } else {
36
+ v = m;
37
+ }
38
+ const version = getDepsVersion(v.name);
39
+ let pathList = [];
40
+ if (!Array.isArray(v.path)) {
41
+ pathList.push(v.path);
42
+ } else {
43
+ pathList = v.path;
44
+ }
45
+ const data = {
46
+ ...v,
47
+ version
48
+ };
49
+ pathList = pathList.map((p) => {
50
+ if (!version && !isFullPath(p)) {
51
+ throw new Error(`modules: ${data.name} package.json file does not exist`);
52
+ }
53
+ return generateUrl(prodUrl, {
54
+ ...data,
55
+ path: p
56
+ });
57
+ });
58
+ let css = v.css || [];
59
+ if (!Array.isArray(css) && css) {
60
+ css = [css];
61
+ }
62
+ const cssList = !Array.isArray(css) ? [] : css.map(
63
+ (c) => generateUrl(prodUrl, {
64
+ ...data,
65
+ path: c
66
+ })
67
+ );
68
+ return {
69
+ ...v,
70
+ version,
71
+ pathList,
72
+ cssList
73
+ };
74
+ });
75
+ }
76
+ function transformExternalCDN(options) {
77
+ let isBuild = false;
78
+ const externalMap = {};
79
+ const externals = generateExternals(options);
80
+ externals.forEach((v) => {
81
+ externalMap[v.name] = v.var;
82
+ });
83
+ const externalLibs = Object.keys(externalMap);
84
+ const plugin = [
85
+ {
86
+ name: "vite-plugin-external-cdn",
87
+ enforce: "post",
88
+ apply: "build",
89
+ ...externalGlobals(externalMap)
90
+ },
91
+ {
92
+ config(config, { command }) {
93
+ const userConfig = {
94
+ build: {
95
+ rollupOptions: {}
96
+ }
97
+ };
98
+ if (command === "build") {
99
+ isBuild = true;
100
+ userConfig.build.rollupOptions = {
101
+ external: [...externalLibs]
102
+ };
103
+ } else {
104
+ isBuild = false;
105
+ }
106
+ return userConfig;
107
+ },
108
+ transformIndexHtml(html) {
109
+ const cssCode = externals.map((v) => v.cssList.map((css) => `<link href="${css}" rel="stylesheet">`).join("\n")).filter((v) => v).join("\n");
110
+ const jsCode = !isBuild ? "" : externals.map((p) => p.pathList.map((url) => `<script src="${url}"></script>`).join("\n")).join("\n");
111
+ return html.replace(/<\/title>/i, `</title>${cssCode}
112
+ ${jsCode}`);
113
+ }
114
+ }
115
+ ];
116
+ return plugin;
117
+ }
118
+
119
+ // src/preset.ts
120
+ var modulesConfig = {
121
+ react: {
122
+ var: "React",
123
+ jsdeliver: {
124
+ path: "umd/react.production.min.js"
125
+ }
126
+ },
127
+ "react-dom": {
128
+ var: "ReactDOM",
129
+ jsdeliver: {
130
+ path: "umd/react-dom.production.min.js"
131
+ }
132
+ },
133
+ "react-router-dom": {
134
+ var: "ReactRouterDOM",
135
+ jsdeliver: {
136
+ path: "umd/react-router-dom.min.js"
137
+ }
138
+ },
139
+ antd: {
140
+ var: "antd",
141
+ jsdeliver: {
142
+ path: "dist/antd.min.js",
143
+ css: "dist/antd.min.css"
144
+ }
145
+ },
146
+ ahooks: {
147
+ var: "ahooks",
148
+ jsdeliver: {
149
+ path: "dist/ahooks.js"
150
+ }
151
+ },
152
+ "@ant-design/charts": {
153
+ var: "charts",
154
+ jsdeliver: {
155
+ path: "dist/charts.min.js"
156
+ }
157
+ },
158
+ vue: {
159
+ var: "Vue",
160
+ jsdeliver: {
161
+ path: "dist/vue.global.prod.js"
162
+ }
163
+ },
164
+ vue2: {
165
+ var: "Vue",
166
+ jsdeliver: {
167
+ name: "vue",
168
+ path: "dist/vue.runtime.min.js"
169
+ }
170
+ },
171
+ "@vueuse/shared": {
172
+ var: "VueUse",
173
+ jsdeliver: {
174
+ path: "index.iife.min.js"
175
+ }
176
+ },
177
+ "@vueuse/core": {
178
+ var: "VueUse",
179
+ jsdeliver: {
180
+ path: "index.iife.min.js"
181
+ }
182
+ },
183
+ moment: {
184
+ var: "moment",
185
+ jsdeliver: {
186
+ path: "moment.min.js"
187
+ }
188
+ },
189
+ eventemitter3: {
190
+ var: "EventEmitter3",
191
+ jsdeliver: {
192
+ path: "umd/eventemitter3.min.js"
193
+ }
194
+ },
195
+ "file-saver": {
196
+ var: "window",
197
+ jsdeliver: {
198
+ path: "dist/FileSaver.min.js"
199
+ }
200
+ },
201
+ "browser-md5-file": {
202
+ var: "browserMD5File",
203
+ jsdeliver: {
204
+ path: "dist/index.umd.min.js"
205
+ }
206
+ },
207
+ xlsx: {
208
+ var: "XLSX",
209
+ jsdeliver: {
210
+ path: "dist/xlsx.full.min.js"
211
+ }
212
+ },
213
+ axios: {
214
+ var: "axios",
215
+ jsdeliver: {
216
+ path: "dist/axios.min.js"
217
+ }
218
+ },
219
+ lodash: {
220
+ var: "_",
221
+ jsdeliver: {
222
+ path: "lodash.min.js"
223
+ }
224
+ },
225
+ "crypto-js": {
226
+ var: "crypto-js",
227
+ jsdeliver: {
228
+ path: "crypto-js.min.js"
229
+ }
230
+ },
231
+ localforage: {
232
+ var: "localforage",
233
+ jsdeliver: {
234
+ path: "dist/localforage.min.js"
235
+ }
236
+ }
237
+ };
238
+ function isJsdeliver(prodUrl) {
239
+ return prodUrl.includes("//cdn.jsdelivr.net");
240
+ }
241
+ function isUnpkg(prodUrl) {
242
+ return prodUrl.includes("//unpkg.com");
243
+ }
244
+ function isCdnjs(prodUrl) {
245
+ return prodUrl.includes("//cdnjs.cloudflare.com");
246
+ }
247
+ function autoComplete(name) {
248
+ const config = modulesConfig[name];
249
+ if (!config) {
250
+ throw new Error(`The configuration of module ${name} does not exist `);
251
+ }
252
+ return (prodUrl) => {
253
+ if (isCdnjs(prodUrl)) {
254
+ throw new Error(`The configuration of module ${name} in ${prodUrl} does not exist `);
255
+ } else {
256
+ if (!(isJsdeliver(prodUrl) || isUnpkg(prodUrl))) {
257
+ console.warn("Unknown prodUrl, using the jsdeliver rule");
258
+ }
259
+ return {
260
+ name,
261
+ var: config.var,
262
+ ...config.jsdeliver
263
+ };
264
+ }
265
+ };
266
+ }
267
+
268
+ // src/index.ts
269
+ var src_default = transformExternalCDN;
270
+ export {
271
+ transformExternalCDN as PluginExternalCDN,
272
+ autoComplete,
273
+ src_default as default
274
+ };
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "vite-plugin-external-cdn",
3
+ "version": "1.0.0",
4
+ "description": "A vite plugin to import dependencies as a CDN.",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "main": "dist/index.js",
9
+ "module": "dist/index.mjs",
10
+ "types": "dist/index.d.ts",
11
+ "scripts": {
12
+ "dev": "tsc -w",
13
+ "build": "pnpm lint:fix && rimraf dist && tsup src/index.ts --dts --format cjs,esm",
14
+ "prepare": "husky install",
15
+ "lint-staged": "lint-staged",
16
+ "format": "prettier -w src/**/*.* examples/**/*.*",
17
+ "lint": "eslint .",
18
+ "lint:fix": "eslint --fix src/**/*.*",
19
+ "type-check": "tsc --noEmit"
20
+ },
21
+ "keywords": [
22
+ "vite-plugin",
23
+ "cdn",
24
+ "external"
25
+ ],
26
+ "author": "zuojiangtao",
27
+ "license": "ISC",
28
+ "dependencies": {
29
+ "rollup-plugin-external-globals": "^0.8.0"
30
+ },
31
+ "devDependencies": {
32
+ "@commitlint/cli": "^17.6.7",
33
+ "@commitlint/config-conventional": "^17.6.7",
34
+ "@rushstack/eslint-patch": "^1.3.3",
35
+ "@types/node": "^20.4.9",
36
+ "@typescript-eslint/eslint-plugin": "^6.3.0",
37
+ "@typescript-eslint/parser": "^6.3.0",
38
+ "eslint": "^8.46.0",
39
+ "eslint-config-prettier": "^9.0.0",
40
+ "eslint-plugin-prettier": "^5.0.0",
41
+ "husky": "^8.0.3",
42
+ "lint-staged": "^13.2.3",
43
+ "prettier": "^3.0.1",
44
+ "rimraf": "^5.0.1",
45
+ "tsup": "^7.2.0",
46
+ "typescript": "^5.1.6",
47
+ "vite": "^4.4.9"
48
+ },
49
+ "lint-staged": {
50
+ "src/**/*.{ts,js,json,tsx,jsx,vue}": [
51
+ "prettier --write",
52
+ "eslint --cache --fix",
53
+ "eslint"
54
+ ]
55
+ }
56
+ }