A Vite plugin that automatically scans your static assets directory, generates a type-safe TypeScript module with all asset paths, directory-aware types, and a helper function to get asset URLs. It validates asset references during build and updates live during development.
- 🚀 Automatic Recursive Scanning: Scans a directory (default:
public
) for all static assets. - 🛡 Type-Safe API: Generates a union type
StaticAssetPath
of all valid asset paths. - 📁 Directory-Aware Types: Generates
StaticAssetDirectory
and a powerfulFilesInFolder<Dir>
generic for directory-specific asset typing. - 🔗 Helper Function: Provides
staticAssets()
to get the URL for an asset, with runtime validation. - 🛠 Highly Configurable: Customize directory, output file, ignore patterns, debounce, directory depth, empty directory handling, leading slash, and more.
- 🔄 Live Updates: Watches the directory in development mode and regenerates types on changes.
- 🧭 Validation: Validates asset references and directory references during build, with detailed error messages.
- ⚡ Fast: Minimal overhead, optimized for large projects.
Built with Bun – the ultra-fast JavaScript runtime & toolkit
Import the generated function and types:
import { staticAssets, StaticAssetPath, StaticAssetDirectory, FilesInFolder } from './static-assets';
// Use the helper function
const logoUrl = staticAssets('images/logo.svg');
// Type-safe variables
const assetPath: StaticAssetPath = 'fonts/roboto.woff2';
const dir: StaticAssetDirectory = 'images/';
// Type-safe list of files directly inside 'icons/brands/'
type Icons = FilesInFolder<'icons/brands/'>;
// use Icons type in your code
type Brands = {
icon: Icons,
name: string
}
// Create a list of brands with their icons and names
// get autocompletion and type checking!
const brands: Brands[] = [
{
icon: "icons/brands/coke.svg",
name: "Coke"
},
{
icon: "icons/brands/pepsi.svg",
name: "Pepsi"
},
{
icon: "icons/brands/rc-cola.svg",
name: "RC Cola"
},
{
icon: "icons/brands/dr-pepper.svg",
name: "Dr Pepper"
},
]
# npm
npm install --save-dev vite-static-assets-plugin
# yarn
yarn add -D vite-static-assets-plugin
# bun
bun add -d vite-static-assets-plugin
# pnpm
pnpm add -D vite-static-assets-plugin
Add the plugin to your Vite config:
import { defineConfig } from 'vite';
import staticAssetsPlugin from 'vite-static-assets-plugin';
export default defineConfig({
plugins: [
staticAssetsPlugin({
// Optional configuration (defaults shown):
directory: 'public',
outputFile: 'src/static-assets.ts',
ignore: ['.DS_Store'],
debounce: 200,
enableDirectoryTypes: true,
maxDirectoryDepth: 5,
allowEmptyDirectories: false,
addLeadingSlash: true,
})
]
});
The plugin generates a TypeScript file (default: src/static-assets.ts
) containing:
A union of all asset paths:
export type StaticAssetPath =
'images/logo.svg' |
'images/banner.jpg' |
'fonts/roboto.woff2';
A union of all directories containing assets, including '.'
for the root:
export type StaticAssetDirectory =
'.' |
'fonts/' |
'images/' ;
A generic type representing only the files directly inside a directory:
// Example: all files directly inside 'images/' (not nested)
type ImageFiles = FilesInFolder<'images/'>;
// 'logo.svg' | 'banner.jpg'
A function that returns the URL for an asset, with validation:
export function staticAssets(path: StaticAssetPath): string;
If you pass an invalid path, it throws an error at runtime and TypeScript will catch it at compile time.
Use it in your components:
<img src={staticAssets('images/logo.svg')} alt="Logo" />
Works with any frontend framework that uses Vite: React, Vue, Svelte, Angular, Solid, Lit, and more.
Option | Type | Default | Description |
---|---|---|---|
directory |
string |
'public' |
Directory to scan for static assets |
outputFile |
string |
'src/static-assets.ts' |
Path to generate the TypeScript module |
ignore |
string[] |
['.DS_Store'] |
Glob patterns to ignore |
debounce |
number |
200 |
Debounce time (ms) for file watcher events |
enableDirectoryTypes |
boolean |
true |
Generate directory-aware types (StaticAssetDirectory , FilesInFolder ) |
maxDirectoryDepth |
number |
5 |
Maximum directory nesting level for directory type generation |
allowEmptyDirectories |
boolean |
false |
Allow referencing empty directories in validation |
addLeadingSlash |
boolean |
true |
Add a leading slash to generated asset URLs |
- Scans the specified directory recursively, ignoring patterns.
-
Generates a TypeScript file with:
-
StaticAssetPath
union of all asset paths. -
StaticAssetDirectory
union of directories. -
FilesInFolder<Dir>
generic. -
staticAssets()
function.
-
- Watches the directory in development mode, regenerating on changes.
- Validates asset references and directory references during build.
- Throws errors with detailed info if assets or directories are missing.
- If you reference a missing asset in
staticAssets()
, the plugin throws a build-time error with details (even if you're skipping TS typechecking before build). - If you reference a directory (via
FilesInFolder
or in code) that is empty or missing, it throws an error unlessallowEmptyDirectories: true
. - Errors include the file path, missing asset/directory, and suggestions.
- Please note that this message is shown in case you actually skip TS typechecking before build. In case you're not typechecking before build (which is recommended), the error will be thrown at build time and you'll see the full error message in the terminal.
- The generated file is TypeScript-ready (as long as you set
outputFile
in yourvite.config.ts
to folder that is visible to your project). - Enjoy auto-completion, type checking, and refactoring support for your static assets.
This project uses Vitest:
# Run all tests
npm test
# Watch mode
npm run test:watch
# Coverage
npm run test:coverage
Tests are in packages/plugin/tests/
and cover core functions and plugin behavior.
MIT
Contributions, issues, and feature requests are welcome! Please open an issue or pull request.