vite-plugin-generate-html
Version:
A Vite plugin to generate separate output files for JavaScript and CSS bundles with customizable attributes.
242 lines (179 loc) • 5.94 kB
Markdown
# Vite Plugin Generate HTML
A Vite plugin that writes generated `<script>` and `<link>` tags to separate files during the build.
The plugin reads Vite/Rollup output entry chunks, uses their final hashed asset filenames, and writes:
- one file containing `<script>` tags for JavaScript entry chunks
- one file containing `<link>` tags for CSS imported by those entry chunks
This is useful when your application shell is rendered outside Vite, for example in `.html`, `.cshtml` (Razor), `.php`, or another server-rendered template, but you still need references to Vite's hashed build assets.
It is inspired by Webpack's `HtmlWebpackPlugin` and is intended for similar use cases in Vite projects where generated asset tags need to be written into external template files.
---
## Installation
```bash
npm install --save-dev vite-plugin-generate-html
```
## Requirements
- Node.js 18 or newer
- npm 8 or newer
---
## Usage
```ts
// vite.config.ts
import { resolve } from "node:path";
import { defineConfig } from "vite";
import generateHtmlFiles from "vite-plugin-generate-html";
export default defineConfig({
build: {
rollupOptions: {
input: {
app: resolve(__dirname, "src/main.ts"),
},
},
},
plugins: [
generateHtmlFiles({
publicDir: "/dist/",
jsEntryFile: resolve(__dirname, "../templates/javascript.html"),
cssEntryFile: resolve(__dirname, "../templates/css.html"),
}),
],
});
```
If `src/main.ts` imports CSS:
```ts
import "./styles.css";
```
the generated files can look like this after a Vite build.
`javascript.html`:
```html
<script type="module" src="/dist/app.abc123.js"></script>
```
`css.html`:
```html
<link href="/dist/app.abc123.css" rel="stylesheet" media="all" />
```
The plugin overwrites both configured output files on each build.
---
## Options
```ts
interface VitePluginGenerateHtmlOptions {
/**
* URL prefix added before generated JavaScript and CSS filenames.
*
* @default "/dist/"
*/
publicDir?: string;
/**
* File path where generated `<script>` tags are written.
*/
jsEntryFile: string;
/**
* File path where generated `<link>` tags are written.
*/
cssEntryFile: string;
/**
* Custom attributes for generated tags by entry chunk name.
*/
output?: Array<
Record<
string,
{
attrs: string[];
linkAttrs: string[];
}
>
>;
/**
* Limit generation to specific entry chunk names.
* By default, all entry chunks are handled.
*/
chunks?: string[];
}
```
### `publicDir`
`publicDir` is used as a URL prefix for generated asset references. It is not read from disk.
For example, with `publicDir: "/assets/"` and an output chunk named `app.abc123.js`, the generated script tag uses:
```html
<script type="module" src="/assets/app.abc123.js"></script>
```
### `jsEntryFile`
Required. The file path where generated `<script>` tags are written.
### `cssEntryFile`
Required. The file path where generated `<link>` tags are written.
Only CSS imported by handled Vite entry chunks is included. If a handled entry chunk has no imported CSS, no link tag is generated for that chunk.
### `output`
Use `output` to customize attributes for specific entry chunk names.
```ts
generateHtmlFiles({
publicDir: "/dist/",
jsEntryFile: resolve(__dirname, "../templates/javascript.html"),
cssEntryFile: resolve(__dirname, "../templates/css.html"),
output: [
{
app: {
attrs: ['type="module"', "defer", 'data-entry="app"'],
linkAttrs: ['rel="stylesheet"', 'media="all"'],
},
},
],
});
```
Generated output:
```html
<script type="module" defer data-entry="app" src="/dist/app.abc123.js"></script>
```
```html
<link href="/dist/app.abc123.css" rel="stylesheet" media="all" />
```
When `output` is provided, each handled entry chunk must have a matching key for script generation. If you only want to configure some entries, combine `output` with `chunks`.
Default attributes are used when `output` is omitted:
- `<script>`: `type="module"`
- `<link>`: `rel="stylesheet" media="all"`
### `chunks`
Use `chunks` to generate files for only specific entry chunk names.
```ts
generateHtmlFiles({
publicDir: "/dist/",
jsEntryFile: resolve(__dirname, "../templates/admin-javascript.html"),
cssEntryFile: resolve(__dirname, "../templates/admin-css.html"),
chunks: ["admin"],
});
```
This is helpful when a Vite build has multiple entry points and you want separate generated files for different pages or templates.
---
## Multiple Entry Points
You can use the plugin more than once to write separate files for different entry chunks.
```ts
plugins: [
generateHtmlFiles({
publicDir: "/dist/",
jsEntryFile: resolve(__dirname, "../templates/app-js.html"),
cssEntryFile: resolve(__dirname, "../templates/app-css.html"),
chunks: ["app"],
}),
generateHtmlFiles({
publicDir: "/dist/",
jsEntryFile: resolve(__dirname, "../templates/admin-js.html"),
cssEntryFile: resolve(__dirname, "../templates/admin-css.html"),
chunks: ["admin"],
output: [
{
admin: {
attrs: ['type="module"', 'data-entry="admin"'],
linkAttrs: ['rel="stylesheet"', 'media="all"'],
},
},
],
}),
];
```
---
## Errors
The plugin throws an error when:
- `jsEntryFile` is missing
- `cssEntryFile` is missing
- `output` is not an array
- no handled entry chunks are found
- `output` is provided but a handled entry chunk has no matching configuration
- `attrs` or `linkAttrs` is not an array for a matching entry
---
## License
This project is licensed under the [MIT License](./LICENSE).