@linglongos/vite-plugin-html 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/dist/index.cjs +380 -0
- package/dist/index.d.cts +53 -0
- package/dist/index.d.mts +53 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.mjs +370 -0
- package/package.json +70 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ejs = require('ejs');
|
|
4
|
+
const dotenvExpand = require('dotenv-expand');
|
|
5
|
+
const dotenv = require('dotenv');
|
|
6
|
+
const path = require('pathe');
|
|
7
|
+
const fse = require('fs-extra');
|
|
8
|
+
const vite = require('vite');
|
|
9
|
+
const nodeHtmlParser = require('node-html-parser');
|
|
10
|
+
const tinyglobby = require('tinyglobby');
|
|
11
|
+
const consola = require('consola');
|
|
12
|
+
const colorette = require('colorette');
|
|
13
|
+
const history = require('connect-history-api-fallback');
|
|
14
|
+
const htmlMinifierTerser = require('html-minifier-terser');
|
|
15
|
+
const pluginutils = require('@rollup/pluginutils');
|
|
16
|
+
|
|
17
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
18
|
+
|
|
19
|
+
const dotenv__default = /*#__PURE__*/_interopDefaultCompat(dotenv);
|
|
20
|
+
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
21
|
+
const fse__default = /*#__PURE__*/_interopDefaultCompat(fse);
|
|
22
|
+
const consola__default = /*#__PURE__*/_interopDefaultCompat(consola);
|
|
23
|
+
const history__default = /*#__PURE__*/_interopDefaultCompat(history);
|
|
24
|
+
|
|
25
|
+
function loadEnv(mode, envDir, prefix = "") {
|
|
26
|
+
if (mode === "local") {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`"local" cannot be used as a mode name because it conflicts with the .local postfix for .env files.`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
const env = {};
|
|
32
|
+
const envFiles = [
|
|
33
|
+
/** mode local file */
|
|
34
|
+
`.env.${mode}.local`,
|
|
35
|
+
/** mode file */
|
|
36
|
+
`.env.${mode}`,
|
|
37
|
+
/** local file */
|
|
38
|
+
`.env.local`,
|
|
39
|
+
/** default file */
|
|
40
|
+
`.env`
|
|
41
|
+
];
|
|
42
|
+
for (const file of envFiles) {
|
|
43
|
+
const path = lookupFile(envDir, [file], true);
|
|
44
|
+
if (path) {
|
|
45
|
+
const parsed = dotenv__default.parse(fse__default.readFileSync(path));
|
|
46
|
+
dotenvExpand.expand({
|
|
47
|
+
parsed,
|
|
48
|
+
// prevent process.env mutation
|
|
49
|
+
ignoreProcessEnv: true
|
|
50
|
+
});
|
|
51
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
52
|
+
if (key.startsWith(prefix) && env[key] === void 0) {
|
|
53
|
+
env[key] = value;
|
|
54
|
+
} else if (key === "NODE_ENV") {
|
|
55
|
+
process.env.VITE_USER_NODE_ENV = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return env;
|
|
61
|
+
}
|
|
62
|
+
function lookupFile(dir, formats, pathOnly = false) {
|
|
63
|
+
for (const format of formats) {
|
|
64
|
+
const fullPath = path.join(dir, format);
|
|
65
|
+
if (fse__default.pathExistsSync(fullPath) && fse__default.statSync(fullPath).isFile()) {
|
|
66
|
+
return pathOnly ? fullPath : fse__default.readFileSync(fullPath, "utf-8");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const parentDir = path.dirname(dir);
|
|
70
|
+
if (parentDir !== dir) {
|
|
71
|
+
return lookupFile(parentDir, formats, pathOnly);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function isDirEmpty(dir) {
|
|
75
|
+
return fse__default.readdir(dir).then((files) => {
|
|
76
|
+
return files.length === 0;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const DEFAULT_TEMPLATE = "index.html";
|
|
81
|
+
const ignoreDirs = [".", "", "/"];
|
|
82
|
+
const bodyInjectRE = /<\/body>/;
|
|
83
|
+
function createPlugin(userOptions = {}) {
|
|
84
|
+
const {
|
|
85
|
+
entry,
|
|
86
|
+
template = DEFAULT_TEMPLATE,
|
|
87
|
+
pages = [],
|
|
88
|
+
verbose = false
|
|
89
|
+
} = userOptions;
|
|
90
|
+
let viteConfig;
|
|
91
|
+
let env = {};
|
|
92
|
+
const transformIndexHtmlHandler = async (html, ctx) => {
|
|
93
|
+
const url = ctx.filename;
|
|
94
|
+
const base = viteConfig.base;
|
|
95
|
+
const excludeBaseUrl = url.replace(base, "/");
|
|
96
|
+
const htmlName = path__default.relative(process.cwd(), excludeBaseUrl);
|
|
97
|
+
const page = getPage(userOptions, htmlName, viteConfig);
|
|
98
|
+
const { injectOptions = {} } = page;
|
|
99
|
+
const _html = await renderHtml(html, {
|
|
100
|
+
injectOptions,
|
|
101
|
+
viteConfig,
|
|
102
|
+
env,
|
|
103
|
+
entry: page.entry || entry,
|
|
104
|
+
verbose
|
|
105
|
+
});
|
|
106
|
+
const { tags = [] } = injectOptions;
|
|
107
|
+
return {
|
|
108
|
+
html: _html,
|
|
109
|
+
tags
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
name: "vite:html",
|
|
114
|
+
configResolved(resolvedConfig) {
|
|
115
|
+
viteConfig = resolvedConfig;
|
|
116
|
+
env = loadEnv(viteConfig.mode, viteConfig.root, "");
|
|
117
|
+
},
|
|
118
|
+
config(conf) {
|
|
119
|
+
const input = createInput(userOptions, conf);
|
|
120
|
+
if (input) {
|
|
121
|
+
return {
|
|
122
|
+
build: {
|
|
123
|
+
rollupOptions: {
|
|
124
|
+
input
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
configureServer(server) {
|
|
131
|
+
let _pages = [];
|
|
132
|
+
const rewrites = [];
|
|
133
|
+
if (!isMpa(viteConfig)) {
|
|
134
|
+
const template2 = userOptions.template || DEFAULT_TEMPLATE;
|
|
135
|
+
const filename = DEFAULT_TEMPLATE;
|
|
136
|
+
_pages.push({
|
|
137
|
+
filename,
|
|
138
|
+
template: template2
|
|
139
|
+
});
|
|
140
|
+
} else {
|
|
141
|
+
_pages = pages.map((page) => {
|
|
142
|
+
return {
|
|
143
|
+
filename: page.filename || DEFAULT_TEMPLATE,
|
|
144
|
+
template: page.template || DEFAULT_TEMPLATE
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const proxy = viteConfig.server?.proxy ?? {};
|
|
149
|
+
const baseUrl = viteConfig.base ?? "/";
|
|
150
|
+
const keys = Object.keys(proxy);
|
|
151
|
+
let indexPage = null;
|
|
152
|
+
for (const page of _pages) {
|
|
153
|
+
if (page.filename !== "index.html") {
|
|
154
|
+
rewrites.push(createRewire(page.template, page, baseUrl, keys));
|
|
155
|
+
} else {
|
|
156
|
+
indexPage = page;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (indexPage) {
|
|
160
|
+
rewrites.push(createRewire("", indexPage, baseUrl, keys));
|
|
161
|
+
}
|
|
162
|
+
server.middlewares.use(
|
|
163
|
+
history__default({
|
|
164
|
+
disableDotRule: void 0,
|
|
165
|
+
htmlAcceptHeaders: ["text/html", "application/xhtml+xml"],
|
|
166
|
+
rewrites
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
},
|
|
170
|
+
transformIndexHtml: {
|
|
171
|
+
order: "pre",
|
|
172
|
+
handler: transformIndexHtmlHandler
|
|
173
|
+
},
|
|
174
|
+
async closeBundle() {
|
|
175
|
+
const outputDirs = [];
|
|
176
|
+
if (isMpa(viteConfig) || pages.length) {
|
|
177
|
+
for (const page of pages) {
|
|
178
|
+
const dir = path__default.dirname(page.template);
|
|
179
|
+
if (!ignoreDirs.includes(dir)) {
|
|
180
|
+
outputDirs.push(dir);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
const dir = path__default.dirname(template);
|
|
185
|
+
if (!ignoreDirs.includes(dir)) {
|
|
186
|
+
outputDirs.push(dir);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const cwd = path__default.resolve(viteConfig.root, viteConfig.build.outDir);
|
|
190
|
+
const htmlFiles = await tinyglobby.glob(
|
|
191
|
+
outputDirs.map((dir) => `${dir}/*.html`),
|
|
192
|
+
{ cwd: path__default.resolve(cwd), absolute: true }
|
|
193
|
+
);
|
|
194
|
+
await Promise.all(
|
|
195
|
+
htmlFiles.map(
|
|
196
|
+
(file) => fse__default.move(file, path__default.resolve(cwd, path__default.basename(file)), {
|
|
197
|
+
overwrite: true
|
|
198
|
+
})
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
const htmlDirs = await tinyglobby.glob(
|
|
202
|
+
outputDirs.map((dir) => dir),
|
|
203
|
+
{ cwd: path__default.resolve(cwd), type: "dir", absolute: true }
|
|
204
|
+
);
|
|
205
|
+
await Promise.all(
|
|
206
|
+
htmlDirs.map(async (item) => {
|
|
207
|
+
const isEmpty = await isDirEmpty(item);
|
|
208
|
+
if (isEmpty) {
|
|
209
|
+
return fse__default.remove(item);
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function createInput({ pages = [], template = DEFAULT_TEMPLATE }, viteConfig) {
|
|
217
|
+
const input = {};
|
|
218
|
+
if (isMpa(viteConfig) || pages?.length) {
|
|
219
|
+
const templates = pages.map((page) => page.template);
|
|
220
|
+
templates.forEach((temp) => {
|
|
221
|
+
let dirName = path__default.dirname(temp);
|
|
222
|
+
const file = path__default.basename(temp);
|
|
223
|
+
dirName = dirName.replace(/\s+/g, "").replace(/\//g, "-");
|
|
224
|
+
const key = dirName === "." || dirName === "public" || !dirName ? file.replace(/\.html/, "") : dirName;
|
|
225
|
+
input[key] = path__default.resolve(viteConfig.root, temp);
|
|
226
|
+
});
|
|
227
|
+
return input;
|
|
228
|
+
} else {
|
|
229
|
+
const dir = path__default.dirname(template);
|
|
230
|
+
if (ignoreDirs.includes(dir)) {
|
|
231
|
+
return void 0;
|
|
232
|
+
} else {
|
|
233
|
+
const file = path__default.basename(template);
|
|
234
|
+
const key = file.replace(/\.html/, "");
|
|
235
|
+
return {
|
|
236
|
+
[key]: path__default.resolve(viteConfig.root, template)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async function renderHtml(html, config) {
|
|
242
|
+
const { injectOptions, viteConfig, env, entry, verbose } = config;
|
|
243
|
+
const { data, ejsOptions } = injectOptions;
|
|
244
|
+
const ejsData = {
|
|
245
|
+
...viteConfig?.env ?? {},
|
|
246
|
+
...viteConfig?.define ?? {},
|
|
247
|
+
...env || {},
|
|
248
|
+
...data
|
|
249
|
+
};
|
|
250
|
+
let result = await ejs.render(html, ejsData, ejsOptions);
|
|
251
|
+
if (entry) {
|
|
252
|
+
result = removeEntryScript(result, verbose);
|
|
253
|
+
result = result.replace(
|
|
254
|
+
bodyInjectRE,
|
|
255
|
+
`<script type="module" src="${vite.normalizePath(
|
|
256
|
+
`${entry}`
|
|
257
|
+
)}"><\/script>
|
|
258
|
+
</body>`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
function getPage({ pages = [], entry, template = DEFAULT_TEMPLATE, inject = {} }, name, viteConfig) {
|
|
264
|
+
let page;
|
|
265
|
+
if (isMpa(viteConfig) || pages?.length) {
|
|
266
|
+
page = getPageConfig(name, pages, DEFAULT_TEMPLATE);
|
|
267
|
+
} else {
|
|
268
|
+
page = createSpaPage(entry, template, inject);
|
|
269
|
+
}
|
|
270
|
+
return page;
|
|
271
|
+
}
|
|
272
|
+
function isMpa(viteConfig) {
|
|
273
|
+
const input = viteConfig?.build?.rollupOptions?.input ?? void 0;
|
|
274
|
+
return typeof input !== "string" && Object.keys(input || {}).length > 1;
|
|
275
|
+
}
|
|
276
|
+
function removeEntryScript(html, verbose = false) {
|
|
277
|
+
if (!html) {
|
|
278
|
+
return html;
|
|
279
|
+
}
|
|
280
|
+
const root = nodeHtmlParser.parse(html);
|
|
281
|
+
const scriptNodes = root.querySelectorAll("script[type=module]") || [];
|
|
282
|
+
const removedNode = [];
|
|
283
|
+
scriptNodes.forEach((item) => {
|
|
284
|
+
removedNode.push(item.toString());
|
|
285
|
+
item.parentNode.removeChild(item);
|
|
286
|
+
});
|
|
287
|
+
verbose && removedNode.length && consola__default.warn(`vite-plugin-html: Since you have already configured entry, ${colorette.dim(
|
|
288
|
+
removedNode.toString()
|
|
289
|
+
)} is deleted. You may also delete it from the index.html.
|
|
290
|
+
`);
|
|
291
|
+
return root.toString();
|
|
292
|
+
}
|
|
293
|
+
function createSpaPage(entry, template, inject = {}) {
|
|
294
|
+
return {
|
|
295
|
+
entry,
|
|
296
|
+
filename: "index.html",
|
|
297
|
+
template,
|
|
298
|
+
injectOptions: inject
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function getPageConfig(htmlName, pages, defaultPage) {
|
|
302
|
+
const defaultPageOption = {
|
|
303
|
+
filename: defaultPage,
|
|
304
|
+
template: `./${defaultPage}`
|
|
305
|
+
};
|
|
306
|
+
const page = pages.filter((page2) => {
|
|
307
|
+
return path__default.resolve("/" + page2.template) === path__default.resolve("/" + htmlName);
|
|
308
|
+
})?.[0];
|
|
309
|
+
return page ?? defaultPageOption ?? void 0;
|
|
310
|
+
}
|
|
311
|
+
function createRewire(reg, page, baseUrl, proxyUrlKeys) {
|
|
312
|
+
return {
|
|
313
|
+
from: new RegExp(`^/${reg}*`),
|
|
314
|
+
to({ parsedUrl }) {
|
|
315
|
+
const pathname = parsedUrl.path;
|
|
316
|
+
const excludeBaseUrl = pathname.replace(baseUrl, "/");
|
|
317
|
+
const template = path__default.resolve(baseUrl, page.template);
|
|
318
|
+
if (excludeBaseUrl.startsWith("/static")) {
|
|
319
|
+
return excludeBaseUrl;
|
|
320
|
+
}
|
|
321
|
+
if (excludeBaseUrl === "/") {
|
|
322
|
+
return template;
|
|
323
|
+
}
|
|
324
|
+
const isApiUrl = proxyUrlKeys.some(
|
|
325
|
+
(item) => pathname.startsWith(path__default.resolve(baseUrl, item))
|
|
326
|
+
);
|
|
327
|
+
return isApiUrl ? parsedUrl.path : template;
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const htmlFilter = pluginutils.createFilter(["**/*.html"]);
|
|
333
|
+
|
|
334
|
+
function getOptions(minify) {
|
|
335
|
+
return {
|
|
336
|
+
collapseWhitespace: minify,
|
|
337
|
+
keepClosingSlash: minify,
|
|
338
|
+
removeComments: minify,
|
|
339
|
+
removeRedundantAttributes: minify,
|
|
340
|
+
removeScriptTypeAttributes: minify,
|
|
341
|
+
removeStyleLinkTypeAttributes: minify,
|
|
342
|
+
useShortDoctype: minify,
|
|
343
|
+
minifyCSS: minify
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async function minifyHtml(html, minify) {
|
|
347
|
+
if (typeof minify === "boolean" && !minify) {
|
|
348
|
+
return html;
|
|
349
|
+
}
|
|
350
|
+
let minifyOptions = minify;
|
|
351
|
+
if (typeof minify === "boolean" && minify) {
|
|
352
|
+
minifyOptions = getOptions(minify);
|
|
353
|
+
}
|
|
354
|
+
return await htmlMinifierTerser.minify(html, minifyOptions);
|
|
355
|
+
}
|
|
356
|
+
function createMinifyHtmlPlugin({
|
|
357
|
+
minify = true
|
|
358
|
+
} = {}) {
|
|
359
|
+
return {
|
|
360
|
+
name: "vite:minify-html",
|
|
361
|
+
// apply: 'build',
|
|
362
|
+
enforce: "post",
|
|
363
|
+
async generateBundle(_, outBundle) {
|
|
364
|
+
if (minify) {
|
|
365
|
+
for (const bundle of Object.values(outBundle)) {
|
|
366
|
+
if (bundle.type === "asset" && htmlFilter(bundle.fileName) && typeof bundle.source === "string") {
|
|
367
|
+
bundle.source = await minifyHtml(bundle.source, minify);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
consola__default.wrapConsole();
|
|
376
|
+
function createHtmlPlugin(userOptions = {}) {
|
|
377
|
+
return [createPlugin(userOptions), createMinifyHtmlPlugin(userOptions)];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
exports.createHtmlPlugin = createHtmlPlugin;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { HtmlTagDescriptor, PluginOption } from 'vite';
|
|
2
|
+
import { Options } from 'ejs';
|
|
3
|
+
import { Options as Options$1 } from 'html-minifier-terser';
|
|
4
|
+
|
|
5
|
+
interface InjectOptions {
|
|
6
|
+
/**
|
|
7
|
+
* @description Data injected into the html template
|
|
8
|
+
*/
|
|
9
|
+
data?: Record<string, any>;
|
|
10
|
+
tags?: HtmlTagDescriptor[];
|
|
11
|
+
/**
|
|
12
|
+
* @description ejs options configuration
|
|
13
|
+
*/
|
|
14
|
+
ejsOptions?: Options;
|
|
15
|
+
}
|
|
16
|
+
interface PageOption {
|
|
17
|
+
filename: string;
|
|
18
|
+
template: string;
|
|
19
|
+
entry?: string;
|
|
20
|
+
injectOptions?: InjectOptions;
|
|
21
|
+
}
|
|
22
|
+
type Pages = PageOption[];
|
|
23
|
+
interface UserOptions {
|
|
24
|
+
/**
|
|
25
|
+
* @description Page options
|
|
26
|
+
*/
|
|
27
|
+
pages?: Pages;
|
|
28
|
+
/**
|
|
29
|
+
* @description Minimize options
|
|
30
|
+
*/
|
|
31
|
+
minify?: Options$1 | boolean;
|
|
32
|
+
/**
|
|
33
|
+
* page entry
|
|
34
|
+
*/
|
|
35
|
+
entry?: string;
|
|
36
|
+
/**
|
|
37
|
+
* template path
|
|
38
|
+
*/
|
|
39
|
+
template?: string;
|
|
40
|
+
/**
|
|
41
|
+
* @description inject options
|
|
42
|
+
*/
|
|
43
|
+
inject?: InjectOptions;
|
|
44
|
+
/**
|
|
45
|
+
* output warning log
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
verbose?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare function createHtmlPlugin(userOptions?: UserOptions): PluginOption[];
|
|
52
|
+
|
|
53
|
+
export { createHtmlPlugin };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { HtmlTagDescriptor, PluginOption } from 'vite';
|
|
2
|
+
import { Options } from 'ejs';
|
|
3
|
+
import { Options as Options$1 } from 'html-minifier-terser';
|
|
4
|
+
|
|
5
|
+
interface InjectOptions {
|
|
6
|
+
/**
|
|
7
|
+
* @description Data injected into the html template
|
|
8
|
+
*/
|
|
9
|
+
data?: Record<string, any>;
|
|
10
|
+
tags?: HtmlTagDescriptor[];
|
|
11
|
+
/**
|
|
12
|
+
* @description ejs options configuration
|
|
13
|
+
*/
|
|
14
|
+
ejsOptions?: Options;
|
|
15
|
+
}
|
|
16
|
+
interface PageOption {
|
|
17
|
+
filename: string;
|
|
18
|
+
template: string;
|
|
19
|
+
entry?: string;
|
|
20
|
+
injectOptions?: InjectOptions;
|
|
21
|
+
}
|
|
22
|
+
type Pages = PageOption[];
|
|
23
|
+
interface UserOptions {
|
|
24
|
+
/**
|
|
25
|
+
* @description Page options
|
|
26
|
+
*/
|
|
27
|
+
pages?: Pages;
|
|
28
|
+
/**
|
|
29
|
+
* @description Minimize options
|
|
30
|
+
*/
|
|
31
|
+
minify?: Options$1 | boolean;
|
|
32
|
+
/**
|
|
33
|
+
* page entry
|
|
34
|
+
*/
|
|
35
|
+
entry?: string;
|
|
36
|
+
/**
|
|
37
|
+
* template path
|
|
38
|
+
*/
|
|
39
|
+
template?: string;
|
|
40
|
+
/**
|
|
41
|
+
* @description inject options
|
|
42
|
+
*/
|
|
43
|
+
inject?: InjectOptions;
|
|
44
|
+
/**
|
|
45
|
+
* output warning log
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
verbose?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare function createHtmlPlugin(userOptions?: UserOptions): PluginOption[];
|
|
52
|
+
|
|
53
|
+
export { createHtmlPlugin };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { HtmlTagDescriptor, PluginOption } from 'vite';
|
|
2
|
+
import { Options } from 'ejs';
|
|
3
|
+
import { Options as Options$1 } from 'html-minifier-terser';
|
|
4
|
+
|
|
5
|
+
interface InjectOptions {
|
|
6
|
+
/**
|
|
7
|
+
* @description Data injected into the html template
|
|
8
|
+
*/
|
|
9
|
+
data?: Record<string, any>;
|
|
10
|
+
tags?: HtmlTagDescriptor[];
|
|
11
|
+
/**
|
|
12
|
+
* @description ejs options configuration
|
|
13
|
+
*/
|
|
14
|
+
ejsOptions?: Options;
|
|
15
|
+
}
|
|
16
|
+
interface PageOption {
|
|
17
|
+
filename: string;
|
|
18
|
+
template: string;
|
|
19
|
+
entry?: string;
|
|
20
|
+
injectOptions?: InjectOptions;
|
|
21
|
+
}
|
|
22
|
+
type Pages = PageOption[];
|
|
23
|
+
interface UserOptions {
|
|
24
|
+
/**
|
|
25
|
+
* @description Page options
|
|
26
|
+
*/
|
|
27
|
+
pages?: Pages;
|
|
28
|
+
/**
|
|
29
|
+
* @description Minimize options
|
|
30
|
+
*/
|
|
31
|
+
minify?: Options$1 | boolean;
|
|
32
|
+
/**
|
|
33
|
+
* page entry
|
|
34
|
+
*/
|
|
35
|
+
entry?: string;
|
|
36
|
+
/**
|
|
37
|
+
* template path
|
|
38
|
+
*/
|
|
39
|
+
template?: string;
|
|
40
|
+
/**
|
|
41
|
+
* @description inject options
|
|
42
|
+
*/
|
|
43
|
+
inject?: InjectOptions;
|
|
44
|
+
/**
|
|
45
|
+
* output warning log
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
verbose?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare function createHtmlPlugin(userOptions?: UserOptions): PluginOption[];
|
|
52
|
+
|
|
53
|
+
export { createHtmlPlugin };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { render } from 'ejs';
|
|
2
|
+
import { expand } from 'dotenv-expand';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
import path, { join, dirname } from 'pathe';
|
|
5
|
+
import fse from 'fs-extra';
|
|
6
|
+
import { normalizePath } from 'vite';
|
|
7
|
+
import { parse } from 'node-html-parser';
|
|
8
|
+
import { glob } from 'tinyglobby';
|
|
9
|
+
import consola from 'consola';
|
|
10
|
+
import { dim } from 'colorette';
|
|
11
|
+
import history from 'connect-history-api-fallback';
|
|
12
|
+
import { minify } from 'html-minifier-terser';
|
|
13
|
+
import { createFilter } from '@rollup/pluginutils';
|
|
14
|
+
|
|
15
|
+
function loadEnv(mode, envDir, prefix = "") {
|
|
16
|
+
if (mode === "local") {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`"local" cannot be used as a mode name because it conflicts with the .local postfix for .env files.`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
const env = {};
|
|
22
|
+
const envFiles = [
|
|
23
|
+
/** mode local file */
|
|
24
|
+
`.env.${mode}.local`,
|
|
25
|
+
/** mode file */
|
|
26
|
+
`.env.${mode}`,
|
|
27
|
+
/** local file */
|
|
28
|
+
`.env.local`,
|
|
29
|
+
/** default file */
|
|
30
|
+
`.env`
|
|
31
|
+
];
|
|
32
|
+
for (const file of envFiles) {
|
|
33
|
+
const path = lookupFile(envDir, [file], true);
|
|
34
|
+
if (path) {
|
|
35
|
+
const parsed = dotenv.parse(fse.readFileSync(path));
|
|
36
|
+
expand({
|
|
37
|
+
parsed,
|
|
38
|
+
// prevent process.env mutation
|
|
39
|
+
ignoreProcessEnv: true
|
|
40
|
+
});
|
|
41
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
42
|
+
if (key.startsWith(prefix) && env[key] === void 0) {
|
|
43
|
+
env[key] = value;
|
|
44
|
+
} else if (key === "NODE_ENV") {
|
|
45
|
+
process.env.VITE_USER_NODE_ENV = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return env;
|
|
51
|
+
}
|
|
52
|
+
function lookupFile(dir, formats, pathOnly = false) {
|
|
53
|
+
for (const format of formats) {
|
|
54
|
+
const fullPath = join(dir, format);
|
|
55
|
+
if (fse.pathExistsSync(fullPath) && fse.statSync(fullPath).isFile()) {
|
|
56
|
+
return pathOnly ? fullPath : fse.readFileSync(fullPath, "utf-8");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const parentDir = dirname(dir);
|
|
60
|
+
if (parentDir !== dir) {
|
|
61
|
+
return lookupFile(parentDir, formats, pathOnly);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function isDirEmpty(dir) {
|
|
65
|
+
return fse.readdir(dir).then((files) => {
|
|
66
|
+
return files.length === 0;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const DEFAULT_TEMPLATE = "index.html";
|
|
71
|
+
const ignoreDirs = [".", "", "/"];
|
|
72
|
+
const bodyInjectRE = /<\/body>/;
|
|
73
|
+
function createPlugin(userOptions = {}) {
|
|
74
|
+
const {
|
|
75
|
+
entry,
|
|
76
|
+
template = DEFAULT_TEMPLATE,
|
|
77
|
+
pages = [],
|
|
78
|
+
verbose = false
|
|
79
|
+
} = userOptions;
|
|
80
|
+
let viteConfig;
|
|
81
|
+
let env = {};
|
|
82
|
+
const transformIndexHtmlHandler = async (html, ctx) => {
|
|
83
|
+
const url = ctx.filename;
|
|
84
|
+
const base = viteConfig.base;
|
|
85
|
+
const excludeBaseUrl = url.replace(base, "/");
|
|
86
|
+
const htmlName = path.relative(process.cwd(), excludeBaseUrl);
|
|
87
|
+
const page = getPage(userOptions, htmlName, viteConfig);
|
|
88
|
+
const { injectOptions = {} } = page;
|
|
89
|
+
const _html = await renderHtml(html, {
|
|
90
|
+
injectOptions,
|
|
91
|
+
viteConfig,
|
|
92
|
+
env,
|
|
93
|
+
entry: page.entry || entry,
|
|
94
|
+
verbose
|
|
95
|
+
});
|
|
96
|
+
const { tags = [] } = injectOptions;
|
|
97
|
+
return {
|
|
98
|
+
html: _html,
|
|
99
|
+
tags
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
name: "vite:html",
|
|
104
|
+
configResolved(resolvedConfig) {
|
|
105
|
+
viteConfig = resolvedConfig;
|
|
106
|
+
env = loadEnv(viteConfig.mode, viteConfig.root, "");
|
|
107
|
+
},
|
|
108
|
+
config(conf) {
|
|
109
|
+
const input = createInput(userOptions, conf);
|
|
110
|
+
if (input) {
|
|
111
|
+
return {
|
|
112
|
+
build: {
|
|
113
|
+
rollupOptions: {
|
|
114
|
+
input
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
configureServer(server) {
|
|
121
|
+
let _pages = [];
|
|
122
|
+
const rewrites = [];
|
|
123
|
+
if (!isMpa(viteConfig)) {
|
|
124
|
+
const template2 = userOptions.template || DEFAULT_TEMPLATE;
|
|
125
|
+
const filename = DEFAULT_TEMPLATE;
|
|
126
|
+
_pages.push({
|
|
127
|
+
filename,
|
|
128
|
+
template: template2
|
|
129
|
+
});
|
|
130
|
+
} else {
|
|
131
|
+
_pages = pages.map((page) => {
|
|
132
|
+
return {
|
|
133
|
+
filename: page.filename || DEFAULT_TEMPLATE,
|
|
134
|
+
template: page.template || DEFAULT_TEMPLATE
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const proxy = viteConfig.server?.proxy ?? {};
|
|
139
|
+
const baseUrl = viteConfig.base ?? "/";
|
|
140
|
+
const keys = Object.keys(proxy);
|
|
141
|
+
let indexPage = null;
|
|
142
|
+
for (const page of _pages) {
|
|
143
|
+
if (page.filename !== "index.html") {
|
|
144
|
+
rewrites.push(createRewire(page.template, page, baseUrl, keys));
|
|
145
|
+
} else {
|
|
146
|
+
indexPage = page;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (indexPage) {
|
|
150
|
+
rewrites.push(createRewire("", indexPage, baseUrl, keys));
|
|
151
|
+
}
|
|
152
|
+
server.middlewares.use(
|
|
153
|
+
history({
|
|
154
|
+
disableDotRule: void 0,
|
|
155
|
+
htmlAcceptHeaders: ["text/html", "application/xhtml+xml"],
|
|
156
|
+
rewrites
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
},
|
|
160
|
+
transformIndexHtml: {
|
|
161
|
+
order: "pre",
|
|
162
|
+
handler: transformIndexHtmlHandler
|
|
163
|
+
},
|
|
164
|
+
async closeBundle() {
|
|
165
|
+
const outputDirs = [];
|
|
166
|
+
if (isMpa(viteConfig) || pages.length) {
|
|
167
|
+
for (const page of pages) {
|
|
168
|
+
const dir = path.dirname(page.template);
|
|
169
|
+
if (!ignoreDirs.includes(dir)) {
|
|
170
|
+
outputDirs.push(dir);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
const dir = path.dirname(template);
|
|
175
|
+
if (!ignoreDirs.includes(dir)) {
|
|
176
|
+
outputDirs.push(dir);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const cwd = path.resolve(viteConfig.root, viteConfig.build.outDir);
|
|
180
|
+
const htmlFiles = await glob(
|
|
181
|
+
outputDirs.map((dir) => `${dir}/*.html`),
|
|
182
|
+
{ cwd: path.resolve(cwd), absolute: true }
|
|
183
|
+
);
|
|
184
|
+
await Promise.all(
|
|
185
|
+
htmlFiles.map(
|
|
186
|
+
(file) => fse.move(file, path.resolve(cwd, path.basename(file)), {
|
|
187
|
+
overwrite: true
|
|
188
|
+
})
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
const htmlDirs = await glob(
|
|
192
|
+
outputDirs.map((dir) => dir),
|
|
193
|
+
{ cwd: path.resolve(cwd), type: "dir", absolute: true }
|
|
194
|
+
);
|
|
195
|
+
await Promise.all(
|
|
196
|
+
htmlDirs.map(async (item) => {
|
|
197
|
+
const isEmpty = await isDirEmpty(item);
|
|
198
|
+
if (isEmpty) {
|
|
199
|
+
return fse.remove(item);
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function createInput({ pages = [], template = DEFAULT_TEMPLATE }, viteConfig) {
|
|
207
|
+
const input = {};
|
|
208
|
+
if (isMpa(viteConfig) || pages?.length) {
|
|
209
|
+
const templates = pages.map((page) => page.template);
|
|
210
|
+
templates.forEach((temp) => {
|
|
211
|
+
let dirName = path.dirname(temp);
|
|
212
|
+
const file = path.basename(temp);
|
|
213
|
+
dirName = dirName.replace(/\s+/g, "").replace(/\//g, "-");
|
|
214
|
+
const key = dirName === "." || dirName === "public" || !dirName ? file.replace(/\.html/, "") : dirName;
|
|
215
|
+
input[key] = path.resolve(viteConfig.root, temp);
|
|
216
|
+
});
|
|
217
|
+
return input;
|
|
218
|
+
} else {
|
|
219
|
+
const dir = path.dirname(template);
|
|
220
|
+
if (ignoreDirs.includes(dir)) {
|
|
221
|
+
return void 0;
|
|
222
|
+
} else {
|
|
223
|
+
const file = path.basename(template);
|
|
224
|
+
const key = file.replace(/\.html/, "");
|
|
225
|
+
return {
|
|
226
|
+
[key]: path.resolve(viteConfig.root, template)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function renderHtml(html, config) {
|
|
232
|
+
const { injectOptions, viteConfig, env, entry, verbose } = config;
|
|
233
|
+
const { data, ejsOptions } = injectOptions;
|
|
234
|
+
const ejsData = {
|
|
235
|
+
...viteConfig?.env ?? {},
|
|
236
|
+
...viteConfig?.define ?? {},
|
|
237
|
+
...env || {},
|
|
238
|
+
...data
|
|
239
|
+
};
|
|
240
|
+
let result = await render(html, ejsData, ejsOptions);
|
|
241
|
+
if (entry) {
|
|
242
|
+
result = removeEntryScript(result, verbose);
|
|
243
|
+
result = result.replace(
|
|
244
|
+
bodyInjectRE,
|
|
245
|
+
`<script type="module" src="${normalizePath(
|
|
246
|
+
`${entry}`
|
|
247
|
+
)}"><\/script>
|
|
248
|
+
</body>`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
function getPage({ pages = [], entry, template = DEFAULT_TEMPLATE, inject = {} }, name, viteConfig) {
|
|
254
|
+
let page;
|
|
255
|
+
if (isMpa(viteConfig) || pages?.length) {
|
|
256
|
+
page = getPageConfig(name, pages, DEFAULT_TEMPLATE);
|
|
257
|
+
} else {
|
|
258
|
+
page = createSpaPage(entry, template, inject);
|
|
259
|
+
}
|
|
260
|
+
return page;
|
|
261
|
+
}
|
|
262
|
+
function isMpa(viteConfig) {
|
|
263
|
+
const input = viteConfig?.build?.rollupOptions?.input ?? void 0;
|
|
264
|
+
return typeof input !== "string" && Object.keys(input || {}).length > 1;
|
|
265
|
+
}
|
|
266
|
+
function removeEntryScript(html, verbose = false) {
|
|
267
|
+
if (!html) {
|
|
268
|
+
return html;
|
|
269
|
+
}
|
|
270
|
+
const root = parse(html);
|
|
271
|
+
const scriptNodes = root.querySelectorAll("script[type=module]") || [];
|
|
272
|
+
const removedNode = [];
|
|
273
|
+
scriptNodes.forEach((item) => {
|
|
274
|
+
removedNode.push(item.toString());
|
|
275
|
+
item.parentNode.removeChild(item);
|
|
276
|
+
});
|
|
277
|
+
verbose && removedNode.length && consola.warn(`vite-plugin-html: Since you have already configured entry, ${dim(
|
|
278
|
+
removedNode.toString()
|
|
279
|
+
)} is deleted. You may also delete it from the index.html.
|
|
280
|
+
`);
|
|
281
|
+
return root.toString();
|
|
282
|
+
}
|
|
283
|
+
function createSpaPage(entry, template, inject = {}) {
|
|
284
|
+
return {
|
|
285
|
+
entry,
|
|
286
|
+
filename: "index.html",
|
|
287
|
+
template,
|
|
288
|
+
injectOptions: inject
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function getPageConfig(htmlName, pages, defaultPage) {
|
|
292
|
+
const defaultPageOption = {
|
|
293
|
+
filename: defaultPage,
|
|
294
|
+
template: `./${defaultPage}`
|
|
295
|
+
};
|
|
296
|
+
const page = pages.filter((page2) => {
|
|
297
|
+
return path.resolve("/" + page2.template) === path.resolve("/" + htmlName);
|
|
298
|
+
})?.[0];
|
|
299
|
+
return page ?? defaultPageOption ?? void 0;
|
|
300
|
+
}
|
|
301
|
+
function createRewire(reg, page, baseUrl, proxyUrlKeys) {
|
|
302
|
+
return {
|
|
303
|
+
from: new RegExp(`^/${reg}*`),
|
|
304
|
+
to({ parsedUrl }) {
|
|
305
|
+
const pathname = parsedUrl.path;
|
|
306
|
+
const excludeBaseUrl = pathname.replace(baseUrl, "/");
|
|
307
|
+
const template = path.resolve(baseUrl, page.template);
|
|
308
|
+
if (excludeBaseUrl.startsWith("/static")) {
|
|
309
|
+
return excludeBaseUrl;
|
|
310
|
+
}
|
|
311
|
+
if (excludeBaseUrl === "/") {
|
|
312
|
+
return template;
|
|
313
|
+
}
|
|
314
|
+
const isApiUrl = proxyUrlKeys.some(
|
|
315
|
+
(item) => pathname.startsWith(path.resolve(baseUrl, item))
|
|
316
|
+
);
|
|
317
|
+
return isApiUrl ? parsedUrl.path : template;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const htmlFilter = createFilter(["**/*.html"]);
|
|
323
|
+
|
|
324
|
+
function getOptions(minify) {
|
|
325
|
+
return {
|
|
326
|
+
collapseWhitespace: minify,
|
|
327
|
+
keepClosingSlash: minify,
|
|
328
|
+
removeComments: minify,
|
|
329
|
+
removeRedundantAttributes: minify,
|
|
330
|
+
removeScriptTypeAttributes: minify,
|
|
331
|
+
removeStyleLinkTypeAttributes: minify,
|
|
332
|
+
useShortDoctype: minify,
|
|
333
|
+
minifyCSS: minify
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
async function minifyHtml(html, minify$1) {
|
|
337
|
+
if (typeof minify$1 === "boolean" && !minify$1) {
|
|
338
|
+
return html;
|
|
339
|
+
}
|
|
340
|
+
let minifyOptions = minify$1;
|
|
341
|
+
if (typeof minify$1 === "boolean" && minify$1) {
|
|
342
|
+
minifyOptions = getOptions(minify$1);
|
|
343
|
+
}
|
|
344
|
+
return await minify(html, minifyOptions);
|
|
345
|
+
}
|
|
346
|
+
function createMinifyHtmlPlugin({
|
|
347
|
+
minify = true
|
|
348
|
+
} = {}) {
|
|
349
|
+
return {
|
|
350
|
+
name: "vite:minify-html",
|
|
351
|
+
// apply: 'build',
|
|
352
|
+
enforce: "post",
|
|
353
|
+
async generateBundle(_, outBundle) {
|
|
354
|
+
if (minify) {
|
|
355
|
+
for (const bundle of Object.values(outBundle)) {
|
|
356
|
+
if (bundle.type === "asset" && htmlFilter(bundle.fileName) && typeof bundle.source === "string") {
|
|
357
|
+
bundle.source = await minifyHtml(bundle.source, minify);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
consola.wrapConsole();
|
|
366
|
+
function createHtmlPlugin(userOptions = {}) {
|
|
367
|
+
return [createPlugin(userOptions), createMinifyHtmlPlugin(userOptions)];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export { createHtmlPlugin };
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@linglongos/vite-plugin-html",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Fork of vite-plugin-html with Vite 8 support, EJS template and HTML minification for index.html",
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./dist/index.cjs",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"README.md",
|
|
19
|
+
"README.zh_CN.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"dev": "pnpm unbuild --stub",
|
|
23
|
+
"build": "pnpm unbuild",
|
|
24
|
+
"prepublishOnly": "npm run build",
|
|
25
|
+
"prepack": "pnpm unbuild"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"vite",
|
|
29
|
+
"html",
|
|
30
|
+
"minify",
|
|
31
|
+
"vite-plugin"
|
|
32
|
+
],
|
|
33
|
+
"author": "Vben",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/vbenjs/vite-plugin-html",
|
|
38
|
+
"directory": "packages/core"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/vbenjs/vite-plugin-html/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/vbenjs/vite-plugin-html/tree/master/#readme",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@rollup/pluginutils": "^4.2.0",
|
|
46
|
+
"colorette": "^2.0.16",
|
|
47
|
+
"connect-history-api-fallback": "^2.0.0",
|
|
48
|
+
"consola": "^2.15.3",
|
|
49
|
+
"dotenv": "^16.0.0",
|
|
50
|
+
"dotenv-expand": "^8.0.2",
|
|
51
|
+
"ejs": "^3.1.6",
|
|
52
|
+
"tinyglobby": "^0.2.9",
|
|
53
|
+
"fs-extra": "^10.0.1",
|
|
54
|
+
"html-minifier-terser": "^6.1.0",
|
|
55
|
+
"node-html-parser": "^5.3.3",
|
|
56
|
+
"pathe": "^0.2.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"vite": ">=2.0.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@babel/types": "^7.17.0",
|
|
63
|
+
"@types/ejs": "^3.1.0",
|
|
64
|
+
"@types/fs-extra": "^9.0.13",
|
|
65
|
+
"@types/html-minifier-terser": "^6.1.0",
|
|
66
|
+
"@types/node": "^22.0.0",
|
|
67
|
+
"typescript": "^4.6.2",
|
|
68
|
+
"vite": "^8.0.0"
|
|
69
|
+
}
|
|
70
|
+
}
|