vite-plugin-generate-html
Version:
A Vite plugin to generate separate output files for JavaScript and CSS bundles with customizable attributes.
88 lines • 4.56 kB
JavaScript
import { promises as fsPromises } from "fs";
function generateHtmlFiles({ publicDir = "/dist/", jsEntryFile, cssEntryFile, output = [], chunks = [], }) {
if (!jsEntryFile) {
throw new Error("Configuration error: 'jsEntryFile' is required.");
}
if (!cssEntryFile) {
throw new Error("Configuration error: 'cssEntryFile' is required.");
}
if (!Array.isArray(output)) {
throw new Error("Configuration error: 'output' must be an array.");
}
const defaultScriptElementAttributes = ['type="module"'];
const defaultLinkElementAttributes = ['rel="stylesheet"', 'media="all"'];
return {
name: "vite-plugin-generate-html",
async generateBundle(_options, bundle) {
// Filter entry scripts based on the provided chunks or include all by default
const entryScripts = Object.values(bundle)
.filter((chunk) => chunk.type === "chunk" && chunk.isEntry)
.filter((chunk) => {
if (chunks.length > 0) {
return chunk.name && chunks.includes(chunk.name);
}
return true;
});
if (entryScripts.length === 0) {
throw new Error("No application entry points found. Please define at least one entry point in your Vite configuration.");
}
// Generate <script> tags
try {
const scripts = entryScripts
.map((chunk) => {
// Use default attributes if no output configuration is provided
if (output.length === 0) {
return `<script ${defaultScriptElementAttributes.join(" ")} src="${publicDir}${chunk.fileName}"></script>`;
}
// Find matching entry in the output configuration
const matchingEntry = output.find((entry) => entry[chunk.name]);
if (!matchingEntry) {
throw new Error(`Output configuration error: No matching key found for entry point "${chunk.name}".`);
}
const scriptElementAttributes = matchingEntry[chunk.name].attrs;
if (!Array.isArray(scriptElementAttributes)) {
throw new Error(`Output configuration error: 'attrs' for entry point "${chunk.name}" must be an array.`);
}
return `<script ${scriptElementAttributes.join(" ")} src="${publicDir}${chunk.fileName}"></script>`;
})
.join("\n");
await fsPromises.writeFile(jsEntryFile, scripts);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to write <script> elements to '${jsEntryFile}': ${error.message}`);
}
throw new Error(`Failed to write <script> elements to '${jsEntryFile}'.`);
}
// Generate <link> tags
try {
const links = entryScripts
.filter((chunk) => chunk.viteMetadata.importedCss.size > 0)
.map((chunk) => {
let linkAttrs = defaultLinkElementAttributes;
// Find matching entry in the output configuration
const matchingEntry = output.find((entry) => entry[chunk.name]);
if (matchingEntry) {
if (!Array.isArray(matchingEntry[chunk.name].linkAttrs)) {
throw new Error(`Output configuration error: 'linkAttrs' for entry point "${chunk.name}" must be an array.`);
}
linkAttrs = matchingEntry[chunk.name].linkAttrs;
}
return Array.from(chunk.viteMetadata.importedCss)
.map((fileName) => `<link href="${publicDir}${fileName}" ${linkAttrs.join(" ")} />`)
.join("\n");
})
.join("\n");
await fsPromises.writeFile(cssEntryFile, links);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to write <link> elements to '${cssEntryFile}': ${error.message}`);
}
throw new Error(`Failed to write <link> elements to '${cssEntryFile}'.`);
}
},
};
}
export default generateHtmlFiles;
//# sourceMappingURL=index.js.map