I've seen this post with ejs. But how do I achieve the same with webpack?
I tried using the nunjucks-loader in conjunction with html-webpack-plugin
, but I get the following error: [nunjucks-loader] non-web targets are not supported
.
Here's my code:
Here's the config:
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
//template: './client/index.html',
filename: 'index.html',
inject: 'body',
template: 'nunjucks-html-loader!./client/templates/index.njk',
});
module: {
loaders: [
{
test: /\.html$/,
use: ['html-loader']
},
{
test: /\.|njk|nunjucks$/,
use: ['nunjucks-loader']
}]
};
This may be long, but please, bear with me:
The problem is that the nunjucks-loader passes it as a JavaScript file (According to the first paragraph).
Instead, use the nunjucks-html-loader.
Install it by using either npm or yarn: First, we install nunjucks-html-loader:
npm i nunjucks-html-loader -D
OR
yarn add nunjucks-html-loader -D
I also recommend installing (this is optional) webpack-glob-folder-entries
(more on this)
npm i webpack-glob-folder-entries -D
OR
yarn add webpack-glob-folder-entries -D
Then, if we consider we have the following folder structure:
- client/
-templates/
-index.njk
-layout.njk
-_partials/
- webpack.config.js
And inside index.njk we have something like this:
<!-- index.nunjucks -->
{% extends "layout.njk" %}
{% block content %}
<h1> Here comes my content that is injected to layout.njk!</h1>
{% endblock %}
We can just configure webpack, with the following settings:
//#1: Define the HTML Webpack Plugin:
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
filename: 'index.html',
inject: 'body',
// Here is part of the magic, we get the index.njk but we tell
// webpack to pass it through the nunjucks-html-loader
template: 'nunjucks-html-loader!./client/templates/index.njk',
});
// Optional, but highly recommended. Create a returnEntries:
// Webpack doesn't support glob paths. For the nunjucks-html-loader
// we need each path to be specified for it to work (YES, even subdirectories!)
function returnEntries(globPath){
let entries = glob_entries(globPath, true);
let folderList = new Array();
for (let folder in entries){
folderList.push(path.join(__dirname, entries[folder]));
}
return folderList;
}
module.exports = {
// You should not have this the same. This is from my site. Go down to see the important part:
entry: './client/index.js',
output: {
filename: production ? '[name]-[hash].js' : 'bundle.js',
path: __dirname + '/dist',
publicPath: 'dist/' //Important!!! : https://github.com/webpack/webpack/issues/1426
},
// #2 We load the HTMLWebpackPluginConfig
plugins: [
HtmlWebpackPluginConfig,
extractTextPlugin
],
resolve: {
extensions: ['.Webpack.js', '.web.js', '.ts', '.js', '.tsx']
},
// HERE is the important part
module: {
loaders: [
{
// HTML LOADER
// Super important: We need to test for the html
// as well as the nunjucks files
test: /\.html$|njk|nunjucks/,
use: ['html-loader',{
loader: 'nunjucks-html-loader',
options : {
// Other super important. This will be the base
// directory in which webpack is going to find
// the layout and any other file index.njk is calling.
searchPaths: [...returnEntries('./client/templates/**/')]
// Use the one below if you want to use a single path.
// searchPaths: ['./client/templates'],
}
}]
}
]
}
}
Then just run webpack
, and you're good to go 😄.
Note:
searchPaths: ['./client/templates'],
Is important. Here's the base path that Webpack is going to use to look for any file that index.njk is calling. Try messing with the path a little bit to understand how it works. But do not remove it.
In addition, webpack does not support glob directories. I wrote a helper function using webpack-glob-folder-entries
that gives me the list of all the sub-folders that nunjucks-html-loader can look. Please understand, that if you do not specify the folder (even if it's a sub-directory), it will not work).
In other words, if you want to use the _partials folder (as the one above), and you don't specify it as './client/templates/_partials', the loader will not pick it up!
Also,
test: /\.html$|njk|nunjucks/,
Is not used for the index.njk but for the files that index.njk calls, in this case layout.njk. Failing to include the njk or nunjucks extension will not load layout.njk and it will give you an error.