Skip to content

assetManifest ​

Automatically scan files in the output directory after Vite build and generate an asset manifest. Supports three output formats: Vite standard, Webpack-compatible, and custom. Also supports entry grouping, runtime injection, and custom formatting.

Import ​

typescript
// Submodule import (recommended)
import { assetManifest } from '@meng-xi/vite-plugin/plugins/copy/asset-manifest'
import type { AssetManifestOptions, ManifestOutputFormat, AssetMap, AssetGroup, AssetManifestResult, CustomFormatter } from '@meng-xi/vite-plugin/plugins/copy/asset-manifest'

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

Quick Start ​

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

export default defineConfig({
	plugins: [assetManifest()]
})

Options ​

OptionTypeDefaultDescription
outputFormat'vite' | 'webpack' | 'custom''vite'Manifest output format
outputFilestring'manifest.json'Manifest output filename, relative to build output directory
publicPathstring'/'Public path prefix prepended to all asset paths
groupByEntrybooleanfalseWhether to group assets by entry point

Inherits BasePluginOptions: enabled, verbose, errorStrategy

Advanced Options ​

OptionTypeDefaultDescription
includeExtensionsstring[][]File extensions to include; empty means include all
injectRuntimebooleanfalseWhether to inject manifest as a runtime global variable
runtimeGlobalNamestring'__ASSET_MANIFEST__'Runtime global variable name
customFormatterCustomFormatter | nullnullCustom formatter, only used when outputFormat is custom
excludeExtensionsstring[]['.map', '.gz', '.br']File extensions to exclude; takes precedence over include
excludePathsstring[][]Path patterns to exclude

Output Format (outputFormat) ​

ValueDescription
viteVite standard format; keys are original paths, values are hashed output paths
webpackWebpack-compatible format with entries and assets nested structure
customCustom format generated via customFormatter callback

Type Exports ​

AssetMap ​

Asset mapping where keys are original asset paths and values are hashed output paths.

typescript
interface AssetMap {
	[key: string]: string
}

AssetGroup ​

Asset information grouped by entry point.

PropertyTypeDescription
entrystringEntry name
assets{ js: string[], css: string[], other: string[] }Asset categories for the entry

AssetManifestResult ​

Vite standard format manifest output.

PropertyTypeDescription
versionstringManifest version, always '1.0'
timestampstringGeneration timestamp (ISO 8601 format)
publicPathstringPublic path prefix
assetsAssetMapAsset mapping
groupsAssetGroup[]Entry-grouped asset info (only present when groupByEntry is enabled)

WebpackManifestOutput ​

Webpack-compatible format manifest output.

PropertyTypeDescription
entriesWebpackEntryAsset[]Asset info for all entry points
assetsAssetMapAsset mapping (same as vite format)

WebpackEntryAsset ​

Entry asset info in Webpack-compatible format.

PropertyTypeDescription
namestringEntry name
filesstring[]List of output file paths for the entry

CustomFormatter ​

Custom formatter function type.

typescript
type CustomFormatter = (manifest: AssetMap) => Record<string, any>

Examples ​

Basic Usage ​

typescript
assetManifest()

Webpack-Compatible Format ​

typescript
assetManifest({
	outputFormat: 'webpack'
})

Custom Output Filename ​

typescript
assetManifest({
	outputFile: 'assets-manifest.json'
})

Group by Entry ​

typescript
assetManifest({
	groupByEntry: true
})

Grouping strategy:

  • HTML files, JS files starting with entry- or main, and root-level JS files are identified as entries
  • Chunk files sharing a directory prefix or name prefix with an entry are associated with that entry (longest match)
  • Unassociated assets are placed in the _shared group

Runtime Injection ​

Inject the manifest as a global variable, accessible at runtime via window.__ASSET_MANIFEST__:

typescript
assetManifest({
	injectRuntime: true,
	runtimeGlobalName: '__ASSET_MANIFEST__'
})

// Runtime code
const manifest = window.__ASSET_MANIFEST__
console.log(manifest['assets/index.js']) // '/assets/index-abc123.js'

Injection characteristics:

  • Uses Object.defineProperty to define a read-only, non-configurable global property
  • Uses Object.freeze to freeze the mapping, preventing runtime tampering
  • Escapes </script> in JSON strings to prevent XSS attacks

Custom Formatter ​

typescript
assetManifest({
	outputFormat: 'custom',
	customFormatter: assetMap => ({
		files: Object.keys(assetMap),
		mappings: assetMap
	})
})

Custom Public Path ​

typescript
assetManifest({
	publicPath: 'https://cdn.example.com/'
})
// Output: { "assets/index.js": "https://cdn.example.com/assets/index-abc123.js" }

File Filtering ​

typescript
assetManifest({
	includeExtensions: ['.js', '.css'],
	excludeExtensions: ['.map', '.gz', '.br', '.woff2'],
	excludePaths: ['assets/images', 'assets/fonts']
})

Filter priority: excludeExtensions > includeExtensions > excludePaths

Production Only ​

typescript
assetManifest({
	enabled: process.env.NODE_ENV === 'production'
})

Output Examples ​

Vite Format ​

json
{
	"version": "1.0",
	"timestamp": "2026-06-07T10:30:00.000Z",
	"publicPath": "/",
	"assets": {
		"assets/index.js": "/assets/index-abc123.js",
		"assets/index.css": "/assets/index-def456.css",
		"favicon.ico": "/favicon.ico"
	}
}

Webpack Format ​

json
{
	"entries": [
		{
			"name": "index",
			"files": ["/assets/index-abc123.js", "/assets/index-def456.css"]
		}
	],
	"assets": {
		"assets/index.js": "/assets/index-abc123.js",
		"assets/index.css": "/assets/index-def456.css"
	}
}

Entry Grouping (Vite Format + groupByEntry) ​

json
{
	"version": "1.0",
	"timestamp": "2026-06-07T10:30:00.000Z",
	"publicPath": "/",
	"assets": {
		"assets/index.js": "/assets/index-abc123.js",
		"assets/about.js": "/assets/about-xyz789.js"
	},
	"groups": [
		{
			"entry": "index",
			"assets": {
				"js": ["/assets/index-abc123.js"],
				"css": [],
				"other": []
			}
		},
		{
			"entry": "about",
			"assets": {
				"js": ["/assets/about-xyz789.js"],
				"css": [],
				"other": []
			}
		}
	]
}

Notes ​

  • The plugin runs in the writeBundle phase (enforce: 'post'), ensuring scanning happens after all build artifacts are written
  • Automatically excludes source maps (.map) and compressed files (.gz, .br)
  • Automatically excludes the manifest output file itself to avoid circular references
  • Extracts original key names from hashed file paths (e.g., index-abc123.js → index.js), with hash pattern being 6-20 hex characters
  • When multiple files map to the same original key (key collision), the full hashed relative path is used as the key to avoid data loss
  • runtimeGlobalName must be a valid JavaScript identifier and cannot be a built-in property (e.g., __proto__, constructor, prototype)
  • Runtime injection is performed in writeBundle (not transformIndexHtml) because manifest data depends on scanning the output directory, which is only complete at writeBundle time

Released under the MIT License.