Skip to content

htmlInject

HTML content injection plugin that injects HTML content into target HTML files during the Vite build process based on configured rules. Supports multiple injection positions (head/body start/end, before/after/replace selector), conditional injection, template variable replacement, and security filtering.

Import Methods

typescript
// Submodule import (recommended)
import { htmlInject } from '@meng-xi/vite-plugin/plugins/html-inject'
import type { HtmlInjectOptions, InjectRule, InjectPosition, InjectCondition, SecurityConfig, InjectionLogEntry } from '@meng-xi/vite-plugin/plugins/html-inject'

// Barrel import
import { htmlInject } from '@meng-xi/vite-plugin'

Quick Start

typescript
import { defineConfig } from 'vite'
import { htmlInject } from '@meng-xi/vite-plugin'

export default defineConfig({
	plugins: [
		htmlInject({
			rules: [
				{
					id: 'meta-description',
					content: '<meta name="description" content="{{appName}}">',
					position: 'head-end',
					templateVars: { appName: 'My Application' }
				},
				{
					id: 'analytics',
					content: '<script src="/analytics.js"></script>',
					position: 'body-end',
					condition: { type: 'env', value: 'PRODUCTION' },
					allowScriptInjection: true
				}
			]
		})
	]
})

Options

OptionTypeDefaultDescription
targetFilestring'index.html'Target HTML file path
rulesInjectRule[]RequiredInjection rules array
securitySecurityConfigSee belowSecurity configuration
templateVarsRecord<string, string>-Global template variables
logInjectionbooleantrueOutput injection logs
enabledbooleantrueEnable plugin
verbosebooleantrueShow detailed logs
errorStrategy'throw' | 'log' | 'ignore''throw'Error handling strategy

InjectRule

OptionTypeDefaultDescription
idstring-Rule unique identifier for logging
contentstringRequiredHTML content to inject
positionInjectPositionRequiredInjection position
selectorstring-Selector string (required for selector positions)
selectorMatch'string' | 'regex''string'Selector match mode
prioritynumber100Priority, lower values execute first
conditionInjectCondition-Injection condition
templateVarsRecord<string, string>-Rule-level template variables (override global)
allowScriptInjectionbooleanfalseWhether to allow injecting scripts and dangerous content

InjectPosition

ValueDescription
head-startAfter the <head> tag opens
head-endBefore the </head> tag
body-startAfter the <body> tag opens
body-endBefore the </body> tag
before-selectorBefore the specified selector
after-selectorAfter the specified selector
replace-selectorReplace the matched selector content

InjectCondition

OptionTypeDescription
type'env' | 'file-contains' | 'custom'Condition type
valuestring | ((...args: any[]) => boolean)Condition value
negatebooleanWhether to negate, default false

Condition Types

TypeValue TypeDescription
envstringBased on environment variable
file-containsstringBased on HTML file content
custom(...args: any[]) => booleanBased on custom function

SecurityConfig

OptionTypeDefaultDescription
blockDangerousTagsbooleantrueBlock dangerous tags (script, iframe, etc.)
blockDangerousAttributesbooleantrueBlock dangerous attributes (onclick, onload, etc.)
allowedTagsstring[]-Allowed tags whitelist
blockedTagsstring[]-Custom blocked tags list
blockedAttributesstring[]-Custom blocked attributes list

InjectionLogEntry

OptionTypeDescription
ruleIdstringRule identifier
positionInjectPositionInjection position
selectorstringSelector used
injectedbooleanWhether injection succeeded
reasonstringReason for injection failure
timestampnumberLog timestamp

Examples

Basic Injection

typescript
htmlInject({
	rules: [
		{
			id: 'meta-viewport',
			content: '<meta name="viewport" content="width=device-width, initial-scale=1.0">',
			position: 'head-end'
		}
	]
})

Template Variables

Use syntax in content to reference variables. Rule-level templateVars override global templateVars:

typescript
htmlInject({
	templateVars: {
		appName: 'My App',
		version: '1.0.0'
	},
	rules: [
		{
			id: 'meta-description',
			content: '<meta name="description" content="{{appName}} v{{version}}">',
			position: 'head-end'
		},
		{
			id: 'custom-meta',
			content: '<meta name="author" content="{{author}}">',
			position: 'head-end',
			templateVars: { author: 'MengXi Studio' }
		}
	]
})

Conditional Injection

typescript
htmlInject({
	rules: [
		{
			id: 'analytics',
			content: '<script src="/analytics.js"></script>',
			position: 'body-end',
			condition: { type: 'env', value: 'PRODUCTION' },
			allowScriptInjection: true
		},
		{
			id: 'debug-banner',
			content: '<div class="debug-banner">Debug Mode</div>',
			position: 'body-start',
			condition: { type: 'env', value: 'DEBUG' }
		},
		{
			id: 'conditional-meta',
			content: '<meta name="robots" content="noindex">',
			position: 'head-end',
			condition: { type: 'env', value: 'STAGING', negate: true }
		}
	]
})

Selector Injection

typescript
htmlInject({
	rules: [
		{
			id: 'before-app',
			content: '<div class="wrapper">',
			position: 'before-selector',
			selector: '<div id="app">'
		},
		{
			id: 'after-app',
			content: '</div>',
			position: 'after-selector',
			selector: '<div id="app">'
		},
		{
			id: 'replace-placeholder',
			content: '<div class="real-content">Loaded</div>',
			position: 'replace-selector',
			selector: '<div class="placeholder">'
		}
	]
})

Regex Selector

typescript
htmlInject({
	rules: [
		{
			id: 'replace-old-meta',
			content: '<meta name="description" content="New Description">',
			position: 'replace-selector',
			selector: '<meta\\s+name="description"[^>]*>',
			selectorMatch: 'regex'
		}
	]
})

Priority Control

Rules execute in ascending order of priority. Lower values have higher priority:

typescript
htmlInject({
	rules: [
		{ id: 'charset', content: '<meta charset="UTF-8">', position: 'head-start', priority: 1 },
		{ id: 'viewport', content: '<meta name="viewport" content="...">', position: 'head-end', priority: 10 },
		{ id: 'analytics', content: '<script>...</script>', position: 'body-end', priority: 100 }
	]
})

Security Configuration

typescript
htmlInject({
	security: {
		blockDangerousTags: true,
		blockDangerousAttributes: true,
		allowedTags: ['iframe'],
		blockedTags: ['object'],
		blockedAttributes: ['data-custom']
	},
	rules: [
		{
			id: 'trusted-iframe',
			content: '<iframe src="/widget.html"></iframe>',
			position: 'body-end'
		}
	]
})

Custom Target File

typescript
htmlInject({
	targetFile: 'src/views/home.html',
	rules: [
		{
			id: 'home-specific',
			content: '<div class="home-banner">Welcome</div>',
			position: 'body-start'
		}
	]
})

Notes

  • Default security configuration blocks dangerous tags like <script>, <iframe>, <object> and event attributes like onclick, onload
  • To inject scripts, you must set allowScriptInjection: true. Ensure the injected content is from a trusted source
  • targetFile defaults to matching all index.html files, supports relative paths and filename matching
  • Rules execute in ascending order of priority. Rules with the same priority execute in array order
  • Template variables use syntax. Rule-level variables override global variables
  • condition.negate: true negates the condition result

Released under the MIT License.