vite-plugin-generate-file
Version:
Generate extra file to dist folder.
169 lines (164 loc) • 5.52 kB
JavaScript
import fs, { writeFileSync, readFileSync } from 'node:fs';
import path, { resolve, relative } from 'node:path';
import { Buffer } from 'node:buffer';
import pc from 'picocolors';
import yaml from 'js-yaml';
import ejs from 'ejs';
import * as mime from 'mime-types';
function ensureDirectoryExistence(filePath) {
const dirname = path.dirname(filePath);
if (fs.existsSync(dirname)) {
return;
}
ensureDirectoryExistence(dirname);
fs.mkdirSync(dirname);
}
function trimBasePath(filename, base) {
if (!base || base === "/") {
return filename;
}
const basePath = `${path.resolve(base)}/`;
if (filename.startsWith(basePath)) {
return filename.slice(basePath.length - 1);
}
return filename;
}
const listTemplate = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>Generate File List</title>\n<body>\n<h1>Generate File List</h1>\n<div>\n <ul>\n <% Object.keys(generateFiles).forEach(key => { %>\n <li><a href='<%= key %>'><%= generateFiles[key].output %></a></li>\n <% }) %>\n </ul>\n</div>\n</body>\n</html>\n";
let config;
let distPath;
const generateFileMap = /* @__PURE__ */ new Map();
function normalizeOption(option) {
const generateFileOption = {
output: "./output.txt",
type: "json",
template: "",
...option
};
const fullPath = resolve(distPath, generateFileOption.output);
const relativePath = `/${relative(distPath, fullPath)}`;
const contentType = generateFileOption.contentType || mime.lookup(generateFileOption.output || "") || "text/plain";
return {
...generateFileOption,
contentType,
fullPath,
relativePath
};
}
function generateContent(option) {
if (!option.type) {
return Buffer.from("", "utf-8");
}
if (option.type === "json") {
if (option.data) {
return Buffer.from(JSON.stringify(option.data), "utf-8");
}
return Buffer.from("", "utf-8");
}
if (option.type === "yaml") {
if (option.data) {
return Buffer.from(yaml.dump(option.data), "utf-8");
}
return Buffer.from("", "utf-8");
}
if (option.type === "template") {
const templatePath = resolve(config.root, option.template);
const templateContent = readFileSync(templatePath, { encoding: "utf8" });
return Buffer.from(ejs.render(templateContent, typeof option.data === "object" && option.data !== null ? option.data : {}), "utf-8");
}
if (option.type === "raw") {
if (option.data) {
if (Buffer.isBuffer(option.data)) {
return option.data;
}
if (typeof option.data === "string") {
return Buffer.from(option.data, "utf-8");
}
}
return Buffer.from("", "utf-8");
}
console.warn(`Unknown type [${option.type}]`);
return Buffer.from("", "utf-8");
}
function generateFile(option) {
const filePath = option.fullPath;
const fileContent = generateContent(option);
ensureDirectoryExistence(filePath);
writeFileSync(filePath, fileContent, { flag: "w" });
console.log(`Generate File to ${pc.green(filePath)}`);
}
function configureServer(server) {
server.middlewares.use("/__generate_file_list", (req, res) => {
res.writeHead(200, { "Content-Type": "text/html" });
res.write(
ejs.render(listTemplate, {
generateFiles: Object.fromEntries(generateFileMap)
})
);
res.end();
});
server.middlewares.use((req, res, next) => {
const uri = new URL(req.originalUrl, `http://${req.headers.host}`);
const pathname = uri.pathname;
const base = server.config.base || "/";
const trimmedPathname = trimBasePath(pathname, base);
if (generateFileMap.has(pathname) || generateFileMap.has(trimmedPathname)) {
const option = generateFileMap.get(pathname) || generateFileMap.get(trimmedPathname);
const content = generateContent(option);
res.writeHead(200, {
"Content-Type": option.contentType
});
res.write(content);
res.end();
} else {
next();
}
});
const _print = server.printUrls;
server.printUrls = () => {
let host = `${config.server.https ? "https" : "http"}://localhost:${config.server.port || "80"}`;
const url = server.resolvedUrls?.local[0];
if (url) {
try {
const u = new URL(url);
host = `${u.protocol}//${u.host}`;
} catch (error) {
console.warn("Parse resolved url failed:", error);
}
}
_print();
const colorUrl = (url2) => pc.green(url2.replace(/:(\d+)\//, (_, port) => `:${pc.bold(port)}/`));
console.log(
` ${pc.green("\u279C")} ${pc.bold("Generate File List")}: ${colorUrl(
`${host}/__generate_file_list/`
)}`
);
};
}
function PluginGenerateFile(options) {
return {
name: "vite-plugin-generate-file",
configResolved(resolvedConfig) {
config = resolvedConfig;
distPath = resolve(config.root, config.build.outDir);
if (Array.isArray(options)) {
options.forEach((option) => {
const simpleOption = normalizeOption(option);
generateFileMap.set(simpleOption.relativePath, simpleOption);
});
} else {
const simpleOption = normalizeOption(options);
generateFileMap.set(simpleOption.relativePath, simpleOption);
}
},
closeBundle() {
if (config.command === "serve") {
return;
}
for (const option of generateFileMap.values()) {
generateFile(option);
}
},
configureServer
};
}
export { PluginGenerateFile as default };