From 57e80f055ed7f1249052928d2263c8b289c4901b Mon Sep 17 00:00:00 2001 From: Hans Chan Date: Tue, 4 Mar 2025 11:04:05 +0800 Subject: [PATCH 1/2] fix: replace vite env variables in source attr --- src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/index.ts b/src/index.ts index bae7437..b5c2377 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,6 +57,10 @@ function injectHTML(pluginConfig?: InjectHTMLConfig): Plugin { `injectHTML: Source attribute '${sourceAttr}' missing in\r\n${tag}`, ); } + // replace %VITE_ENV_VARIABLES% in url + Object.entries(config?.env || {}).forEach(([key, value]) => { + url = url.replace(new RegExp(`%\\s*${key}\\s*%`, 'gsi'), `${value}`); + }); let root = config.root; From 6d77e8882fe0df57c6bf81c979cf888713473c4e Mon Sep 17 00:00:00 2001 From: Hans Chan Date: Thu, 6 Mar 2025 17:14:01 +0800 Subject: [PATCH 2/2] refactor: use htmlEnvHook implemented by vite --- src/htmlEnvHook.ts | 48 ++++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 20 ++++++++----------- 2 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 src/htmlEnvHook.ts 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 b5c2377..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) { @@ -57,10 +61,6 @@ function injectHTML(pluginConfig?: InjectHTMLConfig): Plugin { `injectHTML: Source attribute '${sourceAttr}' missing in\r\n${tag}`, ); } - // replace %VITE_ENV_VARIABLES% in url - Object.entries(config?.env || {}).forEach(([key, value]) => { - url = url.replace(new RegExp(`%\\s*${key}\\s*%`, 'gsi'), `${value}`); - }); let root = config.root; @@ -142,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, }, }; }