/* function formatting: * for your static HTML constructor function, * return the pure HTML that you'd like to add export function createHeader () { return `

This is my header!

` } * if generating an element using DOM manipulations such as document.createElement * you must pass "document" as a parameter export function createToolbar(document) { const wrapper = document.createElement("nav"); const navbarLinks = ["/index.html", "/about.html", "/etc.html"] for (const link of navbarLinks) { const element = document.createElement("a") element.innerHTML = link element.href = link.substring(1, link.length - 5); wrapper.appendChild("element"); } return wrapper.outerHTML } * NOTE - you cant return a document fragment or a div! it has to be a string, * so use .innerHTML or .outerHTML when you return the object! */ /* options formatting: [DIRECTORY] - file path to the static return function [FUNCTION NAME] - if multiple functions present in one file, the name of the specific function [PLACEHOLDER] - where do you want the HTML to appear? ex. "#toolbar-placeholder" plugins: [viteVanillaPrerenderer({ moduleGroups: [ // if there are multiple "export function functionName() {}"s in one file { path: [DIRECTORY], modules: [ { fname: [FUNCTION NAME], selector: [PLACEHOLDER] }, { fname: [FUNCTION NAME], selector: [PLACEHOLDER] }, ] }, // if there's only one function in the file path { path: [DIRECTORY], selector: [PLACEHOLDER], fname: [FUNCTION NAME] }, ] }) ] additional functionality: * for any given fname, you can set "outer: true" if you'd like to replace the outerHTML instead of the innerHTML * if your js file has export ***default*** function fName() {...}, then you don't need an fname * if you have multiple placeholders you want to fill, you can make [PLACEHOLDER] an array! - first, your input function must return an array of strings of the same length as your [PLACEHOLDER] array - then, you map them in parallel with each other! - index[0] of your returned array will be appended to index[0] of your placeholder array! * any questions or anything feel free to email me askdasybells@protonmail.com! * hopefully one day i can make proper documentation for this and actually publish it or something :) */ // THE ACTUAL CODE: import { JSDOM } from "jsdom"; import { resolve } from "path"; export default function viteVanillaPrerenderer(options) { const moduleGroups = options?.moduleGroups || []; return { name: "vite-vanilla-prerenderer", async transformIndexHtml(html, ctx) { if (moduleGroups.length === 0) { return html; } const dom = new JSDOM(html); const document = dom.window.document; function appendToSelectors(module, renderFunction, groupPath) { if (Array.isArray(module.selector)) { const renderedArray = renderFunction(document); if (!Array.isArray(renderedArray)) { console.error( `[Vite-Vanilla-Prerenderer] Error: function from ${groupPath} did not return an array.` ); return; } module.selector.forEach((selector, index) => { if (index < renderedArray.length) { const element = document.querySelector(`${selector}`); if (!element) { return; } element.innerHTML = renderedArray[index]; } }); } else if (module.selector) { const element = document.querySelector(module.selector); if (!element) { return; } const renderedHtml = renderFunction(document); if (module.outer) { element.outerHTML = renderedHtml; } else { element.innerHTML = renderedHtml; } } } for (const group of moduleGroups) { try { if (!group.path) { console.warn( `[Vite-Vanilla-Prerenderer] Skipping a group in config because it's missing 'path'.` ); continue; } const scriptPath = resolve(process.cwd(), group.path); const loadedModule = await import(scriptPath); if (group.modules) { group.modules.forEach((module) => { const moduleName = module.fname || "default"; const renderFunction = loadedModule[moduleName]; if (typeof renderFunction === "function") { appendToSelectors(module, renderFunction, group.path); } else { console.warn( `[Vite-Vanilla-Prerenderer] Export ${moduleName} not found in ${group.path}.` ); } }); } else if (group.selector) { const moduleName = group.fname || "default"; const renderFunction = loadedModule[moduleName]; if (typeof renderFunction === "function") { appendToSelectors(group, renderFunction, group.path); } else { console.warn( `[Vite-Vanilla-Prerenderer] Export ${moduleName} not found in ${group.path}.` ); } } } catch (error) { console.error( `[Vite-Vanilla-Prerenderer] Failed to process module group for path '${group.path}'. Error: ${error.message}` ); } } return dom.serialize(); }, }; }