angular-vite-pug
v0.1.31
Published
Pug support for @analogjs/vite-plugin-angular (JIT and AOT)
Downloads
155
Readme
angular-vite-pug
Pug support for @analogjs/vite-plugin-angular with zero-config JIT (dev) and AOT (build).
Why
- Pug in Angular with Vite: Use
templateUrl: './view.pug'in your components. - JIT and AOT: Works in dev (HMR) and in production builds. No manual loaders needed.
- Drop-in: Minimal changes to your
vite.config.ts.
Requirements
- Node 18+
- Vite 5+
@analogjs/vite-plugin-angular1.19+
Install
pnpm add -D angular-vite-pug @analogjs/vite-plugin-angular vite
# or
npm i -D angular-vite-pug @analogjs/vite-plugin-angular viteThis package includes small patch-package fixes that will apply on install.
Quick start
Use angular-vite-pug in your vite.config.ts and keep using templateUrl: './cmp.pug' in components.
// vite.config.ts
import { defineConfig } from 'vite';
import angularVitePug from 'angular-vite-pug';
export default defineConfig({
plugins: [
// Auto-detects mode:
// - dev/serve → JIT (fast HMR)
// - build → AOT (resource transformer)
angularVitePug(),
],
});Component usage:
// example.component.ts
@Component({
selector: 'app-example',
templateUrl: './example.pug',
// styleUrls: ['./example.scss']
})
export class ExampleComponent {}Your Pug file can be colocated:
// example.pug
div.example
h1 Hello from PugAdvanced config (Nx monorepo, tsconfig paths, Sass include paths)
// vite.config.ts
import path from 'node:path';
import { defineConfig } from 'vite';
import angularVitePug from 'angular-vite-pug';
export default defineConfig(async () => {
const { default: viteTsconfigPaths } = await import('vite-tsconfig-paths');
return {
plugins: [
angularVitePug({
// Force mode if you need to:
// jit: true, // always JIT
// jit: false, // always AOT
}),
viteTsconfigPaths({
projects: [
path.resolve(__dirname, 'tsconfig.json'),
// path.resolve(__dirname, '../../tsconfig.base.json'),
],
}),
],
css: {
preprocessorOptions: {
sass: {
quietDeps: true,
logger: { warn: () => {} },
loadPaths: [
path.resolve(__dirname, 'src/styles'),
],
},
},
},
};
});JIT vs AOT: how it works
- JIT (development / serve)
- Automatically inlines or references the compiled HTML for
templateUrl: './view.pug'. - Watches Pug files for HMR-friendly updates.
- Automatically inlines or references the compiled HTML for
- AOT (build / production)
- Uses an Angular resource transformer to compile Pug to HTML during the build pipeline.
- No runtime dependency on Pug in the final bundle.
You can force a mode if needed:
angularVitePug({ jit: true }); // force JIT
angularVitePug({ jit: false }); // force AOTYou can also pass through options to the underlying Angular plugin if required:
angularVitePug({
angularOptions: {
// any options supported by @analogjs/vite-plugin-angular
},
});Optional: import raw Pug as a string in dev
If you prefer to import Pug templates directly as strings (e.g., for small inline templates), you can do:
import template from './snippet.pug?raw';
@Component({
selector: 'app-inline',
template,
})
export class InlineComponent {}Troubleshooting
These are the concrete issues we hit in real Nx/Vite monorepos and how we fixed them.
pnpm hoisting vs. vendored deps
- pnpm can hoist/dedupe dependencies so your package’s
node_modulesmay not contain the expected copy. - We ship patched
@analogjs/vite-plugin-angularand Pug deps as runtime dependencies and try to resolve them from inside this package first. If they are hoisted, we fall back to the workspace copy. - Logs at startup will show which Analog plugin is used:
- “using VENDORED analog at …/angular-vite-pug/node_modules/@analogjs/vite-plugin-angular/…” ⇒ OK, patched plugin is in use.
- “using WORKSPACE analog at …/node_modules/@analogjs/vite-plugin-angular/…” ⇒ Workspace copy is used.
- pnpm can hoist/dedupe dependencies so your package’s
Vite importing package source (src) instead of dist
- In dev, Vite may prefer TypeScript sources if a package publishes
src/. - Symptom: your logs look like they come from an older unpatched file or from
src/index.tsinstead ofdist/index.js. - Fix: we no longer publish
src/in the package to ensure consumers always loaddist/.
- In dev, Vite may prefer TypeScript sources if a package publishes
TypeScript transformer crashes in AOT
- Symptom: “Cannot read properties of undefined (reading 'map')” or similar TS stack traces during transform.
- Cause: custom TS transformers running in AOT can collide with Angular’s emit pipeline or with a different TS instance.
- Fix: we only register the Pug TS transformer for JIT (dev). For AOT we rely on resource transformers.
Multiple TypeScript instances / version drift
- Symptom: cryptic transformer errors like “statements is not iterable”.
- Cause: different parts of the toolchain using different
typescriptversions/instances. - Fix: align TS version across the workspace (e.g.
pnpm.overrides: { typescript: "5.8.3" }). Avoid mixing global/local TS.
Nx not actually using Vite
- Symptom: changes in
vite.config.tsseem ignored. - Fix: ensure
project.jsonuses@nx/vite:buildand@nx/vite:dev-serverand points to the correctvite.config.ts.
- Symptom: changes in
ESM vs CJS config issues
- Symptom: “Dynamic require of 'fs' is not supported” when
vite.config.mtsis loaded. - Fix: use
vite.config.ts(CommonJS evaluation by Nx) or migrate fully to ESM-safe imports.
- Symptom: “Dynamic require of 'fs' is not supported” when
Node version/chalk error with Nx
- Symptom: “chalk.cyan is not a function”.
- Fix: use Node LTS (e.g. v20). Some Nx versions are incompatible with Node 24 at the time of writing.
Angular runtime requirements
- AOT requires Zone.js. Add this to your app entry:
import 'zone.js'; - JIT in dev requires the compiler:
if (process.env.NODE_ENV === 'development') { import('@angular/compiler'); }
- AOT requires Zone.js. Add this to your app entry:
Pug template references (#ref) and Angular NG0301
- Symptom: “NG0301: Export of name '#myRef' not found!”.
- Cause: Pug emitting
#ref="..."as valued attribute instead of a boolean attribute. - Fix: we ship patches for
pug-code-gen/pug-lexerto output#refas boolean and accept Angular bracket/paren tokens.
AOT Pug not converting / raw Pug in templates
- Ensure the Analog plugin receives
resourceTransformersand treats.pugas a template resource. - This package patches the Analog plugin to accept
resourceTransformersand adds.pugtoresourceExtensionsduring AOT. - Dev HMR: we include an auxiliary Vite plugin that watches
.pugfiles and triggers full reload to refresh AOT resources.
- Ensure the Analog plugin receives
Vite optimized cache masking changes
- Symptom: after upgrades, old behavior persists.
- Fix: clear Vite caches: delete
.vitedirs under the app and rerun the dev server.
Patches not applying / version mismatch
pnpm.patchedDependenciesandpatch-packagemust target exact versions; otherwise hunks fail.- We embed patches and depend on the precise versions we patch. Avoid mixing external patches in the consumer.
Diagnostics: confirm what’s running
- On startup you should see logs from
angular-vite-pug:pkgDir,pkgRoot, whether vendored Analog exists, and which path is used.pug-code-gen at ...pointing to the copy inside this package when vendored is active.
- If you still see workspace paths for Analog, pnpm hoisting moved the dependency; functionally OK (patches are applied in our vendored copy), but consider aligning dependency layout if you need strict isolation.
- On startup you should see logs from
Disable error overlay temporarily
- If the Vite overlay blocks you, set in your app’s
vite.config.ts:export default defineConfig({ server: { hmr: { overlay: false } }, // ... });
- If the Vite overlay blocks you, set in your app’s
License
MIT
