UNPKG

vite-plugin-generate-file

Version:
169 lines (164 loc) 5.52 kB
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 };