import type { HtmlTagDescriptor, PluginOption } from 'vite'; type Options = { inject?: { data?: Record; tags?: HtmlTagDescriptor[]; }; }; export default function htmlPlugin({ inject }: Options = {}): { name: string; transformIndexHtml: { order: 'pre'; handler: (html: string) => Promise; }; } { return { name: 'vite:simple-html:ejs', transformIndexHtml: { order: 'pre', handler: async (html: string) => { const { data, tags } = inject || {}; let result = html; // Replace ejs variables if (data) { for (const [key, value] of Object.entries(data)) { result = result.replaceAll(new RegExp(`<%= ${key} %>`, 'g'), value); } } // Inject meta tags if (tags) { for (const tag of tags) { const { tag: tagName, attrs, injectTo = 'head' } = tag; let tagString = `<${tagName}${ attrs ? ` ${Object.entries(attrs || {}) .map(([key, value]) => `${key}="${value}"`) .join(' ')}` : '' }>`; if (tagName !== 'link' && tagName !== 'meta') { tagString += ``; } switch (injectTo) { case 'head': result = result.replace(/<\/head>/, `${tagString}`); break; case 'head-prepend': result = result.replace(//, `${tagString}`); break; case 'body': result = result.replace(/<\/body>/, `${tagString}`); break; case 'body-prepend': result = result.replace(//, `${tagString}`); break; default: throw new Error(`Unknown injectTo value: ${injectTo satisfies never}`); } } } return result; }, }, } satisfies PluginOption; }