Webpack loader for the Pug templates.
The pug loader resolves paths and webpack aliases for extends
/include
/require()
in a pug template and compiles it to HTML or into a template function.
Features
- supports Webpack 5 and Pug 3
- supports all features and options of original
pugjs/pug-loader
- up to 4x faster than original
pugjs/pug-loader
at webpack starting - up to 8x faster than original
pugjs/pug-loader
at webpack watching during compile changes in dependencies - supports Webpack
resolve.alias
, work fine with and without the prefixes ~
or @
, e.g. for the defined alias Components
this works:
extends Components/layout.pug
extends ~Components/layout.pug
extends @Components/layout.pug
include Components/mixins.pug
include ~Components/mixins.pug
include @Components/mixins.pug
include:markdown-it Components/readme.md
- const colors = require('Components/data/colors.json')
img(src=require('Components/images/image.jpeg'))
const tmpl = require('Components/index.pug');
- compiling a pug into a templated function, e.g.:
const tmpl = require('template.pug');
const html = tmpl({ key: "value" })
- rendering a pug into HTML at compile time (using loader method
'render'
or query parameter ?pug-render
), e.g.:
const html = require('template.pug?pug-render');
- rendering into a pure HTML (method
'html'
) to processing the HTML in additional loader, e.g. in html-load``r
- support for passing custom data to templates at compile time using loader option or query parameters, e.g.:
const html = require('template.pug?pug-render&{"key":"value"}');
- supports watching of changes in all dependencies
- all features have integration tests processed through a webpack runner
Why use this particular pug loader instead of the original one?
- the original
pugjs/pug-loader
is outdated and not maintained more - the original
pugjs/pug-loader
has error by npm install
see issue:
npm ERR! Found: pug@3.0.2 ... pug-loader@2.4.0" has incorrect peer dependency "pug@^2.0.0"
- this pug loader can render a pug into HTML without additional loader
- this pug loader resolve a path in an embedded resource
- this pug loader support Webpack
resolve.alias
also without the prefix ~
- this pug loader is many times faster than the original
pugjs/pug-loader
- this pug loader watch all change in all dependencies
Install
Webpack config
Options
Usage in Pug templates
Usage in JavaScript
Usage method compile
in JavaScript
Usage method render
in JavaScript
Usage method html
in JavaScript
Usage with Angular Component
Passing data into template
Usage embedded resources
More examples of usages
Install
npm install @webdiscus/pug-loader --save-dev
Webpack config
For usage pug templates only in javascript is enough add to a webpack config:
{
module: {
rules: [
{
test: /\.pug$/,
loader: '@webdiscus/pug-loader',
}
]
}
}
Or you can define the resolveLoader.alias
to use the pug-loader
as default pug loader name:
{
resolveLoader: {
alias: {
'pug-loader': '@webdiscus/pug-loader'
}
},
...
module: {
rules: [
{
test: /\.pug$/,
loader: 'pug-loader',
}
]
}
}
For processing an embedded resource see usage embedded resources.
For rendering pug templates into static HTML is needed the HtmlWebpackPlugin.
The complete example of the webpack config file:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const basePath = path.resolve(__dirname);
const pugLoaderOptions = {};
module.exports = {
resolve: {
alias: {
Components: path.join(basePath, 'src/lib/components/ui/'),
Images: path.join(basePath, 'src/images/'),
Templates: path.join(basePath, 'src/templates/'),
}
},
resolveLoader: {
alias: {
'pug-loader': '@webdiscus/pug-loader'
}
},
entry: {
'script': './src/js/script.js',
},
output: {
path: path.join(basePath, 'public'),
filename: '[name].js',
assetModuleFilename: 'assets/images/[hash][ext][query]',
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(basePath, '/src/templates/index.pug'),
filename: './public/index.html',
inject: false
}),
],
module: {
rules: [
{
test: /\.pug$/,
loader: 'pug-loader',
options: pugLoaderOptions
},
{
test: /\.(png|jpg|jpeg)/,
type: 'asset/resource'
}
]
}
};
Options of original pug-loader
See original description of options
doctype
Type: string
Default: html
Specifies the type of document. See available doctypes.
pretty
Type: boolean
Default: false
This option is deprecated by pugjs and always is false
. Don't use it.
filters
Type: object
Default: undefined
Hash table of custom filters.
Filters let to use other languages in Pug templates.
self
Type: boolean
Default: false
Use the self
as namespace for the local variables in template. It will speed up the compilation, but for access to variable, e.g. myVariable
, you must write self.myVariable
.
compileDebug
Type: boolean
Default: false
Includes the function source in the compiled template to improve error reporting.
globals
Type: Array<string>
Default: []
Add a list of global names to make accessible in templates.
plugins
Type: Array<Object>
Default: []
Plugins allow to manipulate pug tags, template content in compile process.
How it works see in source of pug.
Additional options of this implementation
method
Type: string
Default: compile
Values:
compile
the pug template compiles into a template function and in JavaScript can be called with variables to render into an HTML at runtime.
Use this method, if the template have variables passed from JavaScript at runtime. see usagerender
the pug template renders into an HTML at compile time and exported as a string.
All required resource will be processed by the webpack and separately included as added strings wrapped as a function.
Use this method, if the template does not have variables passed from JavaScript at runtime. The method generates the most compact and fastest code. see usage >>html
the template renders into a pure HTML string at compile time. The method need an addition loader to handles the HTML.
Use this method if the rendered HTML needs to be processed by another loader, e.g. by html-loader
see usage >>
Embedded resources such as img(src=require('./image.jpeg'))
handles at compile time by the webpack using asset/resource.
data
Type: Object
Default: {}
The custom data will be passed in all pug templates, it can be useful by pass global data.
Usage
The example of simple file structure of an application under the path /srv/vhost/sample.com/
:
.
├--public/
├--lib/
| └--components/
| ├--ui/
| | ├--layout.pug
| | ├--mixins.pug
| | └--colors.json
| ...
├--src/
| ├--images/
| | ├--image.jpeg
| | ├--image1.jpeg
| | ├--image2.jpeg
| | └--image3.jpeg
| ├--js/
| | ├--script.js
| | └--data.json
| └--templates/
| ├--index.pug
| └--mixins.pug
| ├--widget.pug
└--webpack.config.js
The source Pug templates from src/templates/
after compilation are saved as HTML files in public/
.
Usage in Pug templates
File ./src/templates/index.pug
extends Components/layout.pug
include Components/mixins.pug
block content
- const colors = require('Components/colors.json')`
.color-container
+show-colors(colors)
File ./lib/components/ui/layout.pug
html
head
block head
body
block content
File ./lib/components/ui/mixins.pug
mixin show-colors(colors)
each color in colors
div(style=`background-color:${color.hex};`)= color.name
File ./lib/components/ui/colors.json
[
{
"name": "red",
"hex": "#f00"
},
{
"name": "green",
"hex": "#0f0"
},
{
"name": "blue",
"hex": "#00f"
}
]
In the sample above uses Webpack alias Components
instand of relative path ../../lib/components/ui/
.
Usage in JavaScript
This pug loader resolve all paths and aliases in Pug templates required from JavaScript.
For example, see the file structure of the application above, the pug template can be loaded in JavaScript via require().
The result of require() is a template function, where the argument is an object of variableName:value
, which are available in the pug template.
File ./src/js/script.js
:
const widgetTemplate = require('Templates/widget.pug');
const locals = {
text: 'Hello World!',
colors: [
{
"name": "red",
"hex": "#f00"
},
{
"name": "green",
"hex": "#0f0"
},
{
"name": "blue",
"hex": "#00f"
}
]
}
const html = widgetTemplate(locals);
console.log(html);
File ./src/templates/widget.pug
:
//- 'Templates' is webpack alias
include ~Templates/mixins
h2 Pug demo widget
//- the variables 'text' and `colors` are passed from 'script.js'
+widget(text, colors)
File ./src/templates/mixins.pug
:
mixin widget(text, colors)
.widget
p= text
each color in colors
div(style=`color:${color.hex};`)= color.name
The result of console.log(html)
:
<h2>Pug demo widget</h2>
<div class='widget'>
<p>Hello World!</p>
<div style="color:#f00">red</div>
<div style="color:#0f0">green</div>
<div style="color:#00f">blue</div>
</div>
See the simple web app example >>
Usage methods compile
, render
or html
in JavaScript
Method compile
(default)
In JavaScript the required template will be compiled into template function.
In webpack config add to module.rules
:
{
test: /\.pug$/,
loader: 'pug-loader',
options: {
method: 'compile'
}
}
In JavaScript, the result of require () is a template function. Call the template function with some variables to render it то HTML:
const tmpl = require('template.pug');
const html = tmpl({ key: 'value' });
You can apply the method render
to single template using the query parameter ?pug-render
:
const html = require('template.pug?pug-render&{"key":"value"}');
Note: if the query parameter pug-render
is set, then will be used rendering for this template, independent of the loader option method
.
Variables passed in template with method render
will be used at compile time.
Method render
This method will render the pug into HTML at compile time.
In webpack config add to module.rules
:
{
test: /\.pug$/,
loader: 'pug-loader',
options: {
method: 'render'
}
}
In JavaScript the result of require() is an HTML string:
const html = require('template.pug');
Method html
This method will render the pug to pure HTML and should be used with an additional loader to handle HTML.
In webpack config add to module.rules
:
{
test: /\.pug$/,
use: [
{
loader: 'html-loader',
options: {
esModule: false,
},
},
{
loader: 'pug-loader',
options: {
method: 'html',
},
},
],
}
In JavaScript the result of require() is an HTML string:
const html = require('template.pug');
Usage scenario 1: pug loader configured for compiling (defaults)
Webpack config:
{
test: /\.pug$/,
loader: 'pug-loader'
}
JavaScript:
const tmpl = require('template.pug');
const html = tmpl({...});
const html2 = require('template2.pug?pug-render');
Usage scenario 2: pug loader configured for rendering
Webpack config:
{
test: /\.pug$/,
loader: 'pug-loader',
options: {
method: 'render'
}
}
JavaScript:
const html = require('template.pug');
const tmpl2 = require('template2.pug?pug-compile');
const html2 = tmpl2({...});
Usage with Angular Component
For usage pug-loader with Angular is needed to customize the webpack config.
Install packages:
npm i --saveDev @webdiscus/pug-loader pug-plugin-ng
in pug-loader can be used optional a plugin, e.g. pug-plugin-ng, to allow unquoted syntax of Angular: [(bananabox)]="val"
Create the file webpack.config.js
in root directory of angular project:
module.exports = {
resolveLoader: {
alias: {
'pug-loader': '@webdiscus/pug-loader',
},
},
module: {
rules: [
{
test: /\.pug$/,
loader: 'pug-loader',
options: {
method: 'render',
doctype: 'html',
plugins: [require('pug-plugin-ng')],
},
},
{
test: /\.(png|jpg|jpeg)/,
type: '`asset/resource`',
},
],
},
};
Bind the file webpack.config.js
in the Angular config file angular.json
:
{
...
"projects": {
...
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"aot": true,
"customWebpackConfig": {
"path": "./webpack.config.js"
},
...
},
...
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "<app-name>:build"
},
...
},
...
}
}
},
}
In a component file, e.g. ./src/app/app.component.ts
set the templateUrl
with pug file:
import { Component } from '@angular/core';
const templateVars = '{"description": "Use pug template with Angular."}';
@Component({
selector: 'app-root',
styleUrls: ['./app.component.css'],
templateUrl: './app.component.pug?' + templateVars,
})
export class AppComponent {
title = 'ng-app';
}
Create a pug template, e.g. ./src/app/app.component.pug
:
h1 Hello Pug!
p Description: #{description}
See the source files of this example >>
Alternative usage with additional html-loader
Install the html-loader
:
npm i --saveDev html-loader
If your templates use the html-loader
, then modify the webpack.config.js
file:
module.exports = {
resolveLoader: {
alias: {
'pug-loader': '@webdiscus/pug-loader',
},
},
module: {
rules: [
{
test: /\.pug$/,
use: [
{
loader: 'html-loader',
options: {
esModule: false,
},
},
{
loader: 'pug-loader',
options: {
method: 'html',
doctype: 'html',
plugins: [require('pug-plugin-ng')],
},
},
],
},
{
test: /\.(png|jpg|jpeg)/,
type: 'asset/resource',
},
],
},
};
See the source files of this example >>
Passing data into template
By default, the pug file is compiled as template function, into which can be passed an object with template variables.
const tmpl = require('template.pug');
const html = tmpl2({
key: 'value',
foo: 'bar',
});
But how pass variables in template which is rendered into HTML?
const html = require('template.pug');
Variables can be passed with query parameters, e.g.:
const html = require('template.pug?key=value&foo=bar');
or as a JSON object, e.g.:
const html = require('template.pug?{"key":"value","foo":"bar"}');
Using the method render
and JSON object:
const html = require('template.pug?pug-render&{"key":"value","foo":"bar"}');
Usage of query parameters is legal and official documented feature of webpack loader.
To pass variables global, in all templates at compile time use loader option data
:
{
test: /\.pug$/,
loader: 'pug-loader',
options: {
data: {
key: 'value',
foo: 'bar'
}
}
}
The variables will be passed in all templates independent of the method.
Usage embedded resources
For processing image resources in templates with webpack use the require()
function:
img(src=require('./path/to/image.jpeg'))
To handles embedded resources in pug is needed the webpack module asset/resource
:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg)/,
type: 'asset/resource'
},
...
]
},
};
More information about asset-modules see here.
Known issues / features by usage embedded resources
Due to the peculiarities of the pug compiler,
the interpolation of the argument to the require()
function depends on its string and variable parts.
Use a relative path only in the string before the variable.
The variable must contain only the filename without specifying a path.
Examples of incorrect usage:
- filename = './image.jpeg'
img(src=require(filename))
- filename = '../relative/path/to/resource/image.jpeg'
img(src=require(filename))
Examples of correct usage:
- filename = 'image.jpeg'
img(src=require(filename))
- filename = 'image.jpeg'
img(src=require('../relative/path/to/resource/' + filename))
The example of dynamically generating embedded resources in template:
- files = ['image1.jpeg', 'image2.jpeg', 'image3.jpeg']
each file in files
img(src=require('../images/' + file))
The example of webpack alias used in the table below:
resolve: {
alias: {
SourceImages: path.join(__dirname, 'src/images/'),
},
}
Examples for using embedded resources:
Code | @webdiscus/pug-loader | pugjs/pug-loader | Note |
---|
img(src=require('image.jpeg')) | OK | fail | |
img(src=require('./image.jpeg')) | OK | OK | |
img(src=require('./images/image.jpeg')) | OK | OK | |
img(src=require('../images/image.jpeg')) | OK | OK | |
img(src=require('SourceImages/image.jpeg')) | OK | OK | Usage of the webpack alias to images directory. |
- file = 'image.jpeg'
img(src=require('SourceImages/' + file)) | OK | OK | |
- file = 'image.jpeg'
img(src=require(`SourceImages/${file}`)) | OK | OK | |
- file = 'image.jpeg'
img(src=require(file)) | OK | fail | |
- file = 'image.jpeg' img(src=require(`${file}`)) | OK | fail | |
- file = 'image.jpeg'
img(src=require('./' + file)) | OK | OK | |
- file = './image.jpeg'
img(src=require(file)) | fail | fail | Don't use ./ in variable of filename. |
- file = './image.jpeg'
img(src=require('' + file)) | fail | OK | Don't use ./ in variable of filename. |
- file = 'images/image.jpeg'
img(src=require(file)) | OK | fail | |
- file = 'image.jpeg'
img(src=require('./images/' + file)) | OK | OK | |
- file = 'image.jpeg'
img(src=require(`./images/${file}`)) | OK | OK | |
- file = '../images/image.jpeg'
img(src=require(file)) | fail | fail | Don't use a path in a variable. |
- file = 'image.jpeg'
img(src=require('../images/' + file)) | OK | OK | Define a path separately as string and add to she the variable contained only a filename. |
- file = 'image.jpeg'
img(src=require(`../images/${file}`)) | OK | OK | |
Include the template from sub directory: include mixins
img(src=require('./image.jpeg')) | OK | fail | when use a mixin and require on same file, then pugjs/pug-loader can't resolve the file in require(). |
More examples of usages see in test cases.
Important: in examples used name of loader as pug-loader
, because it is defined as alias at resolveLoader:
{
resolveLoader: {
alias: {
'pug-loader': '@webdiscus/pug-loader'
}
},
}
License
ISC