diff --git a/src/htmlEnvHook.ts b/src/htmlEnvHook.ts new file mode 100644 index 0000000..2d44d82 --- /dev/null +++ b/src/htmlEnvHook.ts @@ -0,0 +1,48 @@ +import path from 'path' +import { IndexHtmlTransformHook, normalizePath, ResolvedConfig, resolveEnvPrefix } from "vite" + +/** + * Support `%ENV_NAME%` syntax in html files + * @description Taken from vite/src/node/plugins/html.ts + * @link https://github.com/vitejs/vite/blob/c9e086d35ac35ee1c6d85d48369e8a67a2ba6bfe/packages/vite/src/node/plugins/html.ts#L1194 + */ +export default function htmlEnvHook(config: ResolvedConfig): IndexHtmlTransformHook { + const pattern = /%(\S+?)%/g + const envPrefix = resolveEnvPrefix({ envPrefix: config.envPrefix }) + const env: Record = { ...config.env } + + // account for user env defines + for (const key in config.define) { + if (key.startsWith(`import.meta.env.`)) { + const val = config.define[key] + if (typeof val === 'string') { + try { + const parsed = JSON.parse(val) + env[key.slice(16)] = typeof parsed === 'string' ? parsed : val + } catch { + env[key.slice(16)] = val + } + } else { + env[key.slice(16)] = JSON.stringify(val) + } + } + } + return (html, ctx) => { + return html.replace(pattern, (text, key) => { + if (key in env) { + return env[key] + } else { + if (envPrefix.some((prefix) => key.startsWith(prefix))) { + const relativeHtml = normalizePath( + path.relative(config.root, ctx.filename), + ) + config.logger.warn( + `(!) ${text} is not defined in env variables found in /${relativeHtml}. Is the variable mistyped?`, + ) + } + + return text + } + }) + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index bae7437..0caeac2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ -import { normalizePath, Plugin, ResolvedConfig } from 'vite'; +import { IndexHtmlTransformContext, normalizePath, Plugin, ResolvedConfig } from 'vite'; import path from 'path'; import fs from 'fs'; +import htmlEnvHook from './htmlEnvHook'; const attrNameExpr = '[a-z0-9_-]+'; const attrDataExpr = '[^"]*'; @@ -35,11 +36,14 @@ function injectHTML(pluginConfig?: InjectHTMLConfig): Plugin { const fileList = new Set(); - async function renderSnippets(code: string, codePath: string) { + async function renderSnippets(code: string, ctx: IndexHtmlTransformContext) { if (!config) { return code; } + const replaceHtmlEnv = htmlEnvHook(config); + code = (await replaceHtmlEnv(code, ctx)) as string; + const codePath = ctx.path; const matches = code.matchAll(tagMatcher); for (const match of matches) { @@ -138,14 +142,10 @@ function injectHTML(pluginConfig?: InjectHTMLConfig): Plugin { }, transformIndexHtml: { enforce: 'pre', - transform(html, ctx) { - return renderSnippets(html, ctx.path); - }, + transform: renderSnippets, // ^ Keeping for Vite below version 4.0.0 order: 'pre', - handler(html, ctx) { - return renderSnippets(html, ctx.path); - }, + handler: renderSnippets, }, }; }