A Vite plugin for a seamless, zero-config Pug integration in multi-page applications (MPA).
This plugin automatically detects your .pug pages, compiles them on-the-fly in the dev server with support for "pretty URLs" (e.g., /about), and builds them into a clean, nested directory structure for production.
- 🚀 Zero-Config MPA: Automatically detects all
.pugfiles in your source directory to create a multi-page application without manual configuration. - ⚡️ Pretty URLs & Dev Server: Intercepts requests to clean URLs (like
/aboutor/contact) and serves the correctly compiled Pug file on-the-fly. - 🔄 Hot Module Replacement (HMR): Full-page reloads when any
.pugfile (including partials viaincludeorextends) is changed. - 🧩 Vite Alias Support: Use Vite aliases from your
resolve.aliasconfig directly in Pugincludeorextendsstatements. - 🌐 Global Data: Pass global variables and data to all your Pug templates using the
localsoption. - 📦 Vite-Native Asset Handling: Let Vite handle your assets naturally. Just link your scripts and styles (
<script src="/main.ts">) in Pug, and Vite will bundle and inject them correctly. - 🔧 Extensible: Pass custom options directly to the Pug compiler via
pugOptions.
npm install @mish.dev/vite-convert-pug-in-html -DThe plugin requires pug to be installed in your project:
npm install pug -DAdd the plugin to your vite.config.ts. For most projects, no options are required.
The plugin automatically scans your project's root directory (by default, src if you've set root: 'src') for .pug files to build your application.
- It ignores any file starting with
_(e.g.,_layout.pug), treating them as partials. src/index.pugbecomes the site's root (/).src/pages/about.pugbecomes accessible at/about.src/pages/contact/index.pugbecomes accessible at/contact.
Recommended Project Structure:
.
├── src/
│ ├── components/
│ │ └── _header.pug
│ ├── pages/
│ │ ├── about.pug
│ │ └── contact/
│ │ └── index.pug
│ ├── templates/
│ │ └── _layout.pug
│ ├── index.pug
│ └── main.ts
└── vite.config.ts
vite.config.ts:
import { defineConfig } from 'vite';
import { viteConvertPugInHtml } from '@mish.dev/vite-convert-pug-in-html';
export default defineConfig({
// Tell Vite that your source code is in the 'src' directory
root: 'src',
plugins: [
// That's it! No options needed for a standard setup.
viteConvertPugInHtml(),
],
build: {
// Make sure Vite builds to the project root, not inside 'src'
outDir: '../dist',
},
});When you run vite build, the plugin automatically generates:
dist/index.html(fromsrc/index.pug)dist/about/index.html(fromsrc/pages/about.pug)dist/contact/index.html(fromsrc/pages/contact/index.pug)
In the dev server, you can access these pages at /, /about, and /contact.
Forget manual replacements. Just link your TypeScript/JavaScript entry point directly in your main layout file. Vite will handle the rest.
src/templates/_layout.pug:
doctype html
html
head
title My Awesome Site
// Vite will automatically inject the compiled CSS here
body
block content
// Just point to your TS/JS entry file.
// Vite will bundle it and add the correct hashed path on build.
script(src="/main.ts" type="module")Use the locals option to make data available in all your Pug templates. This is the perfect place for site-wide constants, helper functions, or environment variables.
vite.config.ts:
import { defineConfig } from 'vite';
import { viteConvertPugInHtml } from '@mish.dev/vite-convert-pug-in-html';
export default defineConfig({
root: 'src',
plugins: [
viteConvertPugInHtml({
locals: {
SITE_NAME: 'My Awesome Company',
PHONE: '+1 (800) 555-1234',
CURRENT_YEAR: new Date().getFullYear(),
},
}),
],
build: {
outDir: '../dist',
},
});src/templates/_layout.pug:
doctype html
html
head
//- Variables from `locals` are globally available
title= SITE_NAME
body
block content
footer
p © #{CURRENT_YEAR} #{SITE_NAME}
p Call us at: #{PHONE}The plugin automatically uses aliases from your resolve.alias config, making includes clean and maintainable.
vite.config.ts:
import { defineConfig } from 'vite';
import { viteConvertPugInHtml } from '@mish.dev/vite-convert-pug-in-html';
import { resolve } from 'path';
export default defineConfig({
root: 'src',
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
plugins: [viteConvertPugInHtml()],
build: {
outDir: '../dist',
},
});src/pages/about.pug:
extends @/templates/_layout.pug
block content
//- Use the '@' alias to include a component
include @/components/_header.pug
h1 About Us- Type:
PugOptions(frompug) - Default:
{}
An object of options passed directly to pug.render(). Use this for advanced Pug features like filters or custom doctypes.
viteConvertPugInHtml({
pugOptions: {
pretty: true, // Make the output HTML readable (default)
},
}),- Type:
Record<string, any> - Default:
{}
An object of global variables that will be available in all your Pug templates. This is merged with pugOptions before rendering.