- Introduction
- Setup Webpack Project with Django
- Load Webpack bundles in Django
- Linting in Webpack
- Load Webpack hash bundle in Django
- Code splitting with Webpack
- How to config HMR with Webpack and Django
- How to use HtmlWebpackPlugin to load Webpack bundle in Django
If you want a quick start with Webpack and Django, please check python-webpack-boilerplate
Objective
In the previous chapter, we have learned to use django-webpack-loader
to help us load Webpack bundle files in Django like this {% render_bundle 'app' 'js' %}
In this blog, I will show you another way to do this without ANY Django 3-party package?
By the end of this chapter, you should be able to:
- Learn what is
HtmlWebpackPlugin
and how it works. - Use
HtmlWebpackPlugin
and Django Template inheritance to load Webpack bundle
HtmlWebpackPlugin
Let's first check webpack/webpack.common.js
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({ patterns: [{ from: Path.resolve(__dirname, '../public'), to: 'public' }] }),
new HtmlWebpackPlugin({
template: Path.resolve(__dirname, '../src/index.html'),
}),
new BundleTracker({filename: './webpack-stats.json'}),
],
Notes:
- In the plugins, we see
HtmlWebpackPlugin
- The
HtmlWebpackPlugin
will generate an HTML5 file for you, which includes all the webpack bundles in the body usingscript
tags. - If you have any CSS assets in Webpack's output, then these will be included with tags in the element of generated HTML.
(frontend)$ npm run start
Check src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>webpack starterkit</title>
</head>
<body>
<h1>webpack starter</h1>
<p>✨ A lightweight foundation for your next webpack based frontend project.</p>
</body>
</html>
Notes:
- The above file has no links for
js
andcss
files
Let's check build/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>webpack starterkit</title>
<link href="http://localhost:9091/css/app.css" rel="stylesheet"></head>
<body>
<h1>webpack starter</h1>
<p>✨ A lightweight foundation for your next webpack based frontend project.</p>
<script src="http://localhost:9091/js/jquery.js"></script><script src="http://localhost:9091/js/vendors.js"></script><script src="http://localhost:9091/js/app.js"></script></body>
</html>
Notes:
- The
script
andlink
tags has been added afternpm run build
- We do not need to config which files to be imported, the plugin and Webpack would do that for us.
Workflow
Here is the workflow:
- We use
HtmlWebpackPlugin
to help us generate afrontend_base.html
, which containscss
andjs
links from Webpack. - In Django, we use Template inheritance to make all Django templates to inherit from the above
frontend_base.html
So the relationship would seem like this:
frontend_base.html build by Webpack
base.html Django base template
index.html
blog.html
about.html
Custom insertion
Actually, HtmlWebpackPlugin already contains example to show people how to do this.
Let's check custom-insertion-position
It has index.ejs
<!DOCTYPE html>
<html>
<head>
<%= htmlWebpackPlugin.tags.headTags %>
<title>Custom insertion example</title>
</head>
<body>
All scripts are placed here:
<%= htmlWebpackPlugin.tags.bodyTags %>
<script>console.log("Executed after all other scripts")</script>
</body>
</html>
<%= htmlWebpackPlugin.tags.headTags %>
would inject css links<%= htmlWebpackPlugin.tags.bodyTags %>
would inject js links.ejs
means Embedded JavaScript templating, and you can check https://ejs.co/ to learn more.
frontend_base.html
Create src/index.ejs
{% block html %}
{% block css %}
<%= htmlWebpackPlugin.tags.headTags %>
{% endblock %}
{% block js %}
<%= htmlWebpackPlugin.tags.bodyTags %>
{% endblock %}
{% endblock %}
Notes:
- In
ejs
, it would only process code wrapped by<%= %>
- So code like
{% block js %}
would be treated as text, and still exists in the final html.
Let's update webpack/webpack.common.js
plugins: [
new CleanWebpackPlugin({dangerouslyAllowCleanPatternsOutsideProject: true}),
new CopyWebpackPlugin({ patterns: [{ from: Path.resolve(__dirname, '../public'), to: 'public' }] }),
new HtmlWebpackPlugin({
template: Path.resolve(__dirname, '../src/index.ejs'),
filename: Path.resolve(__dirname, '../../django_webpack_app/templates/frontend-base.html'),
inject:false,
}),
new BundleTracker({filename: './webpack-stats.json'}),
],
Notes:
- We deleted the previous HtmlWebpackPlugin from the
plugins
- We added a new
HtmlWebpackPlugin
, which compile fromsrc/index.ejs
and output to the Django templates directory. inject: false,
should be added so HtmlWebpackPlugin would not inject automatically.- In
CleanWebpackPlugin
, we pass{dangerouslyAllowCleanPatternsOutsideProject: true, dry: false}
to solveCannot delete files/folders outside the current working directory
error.
$ npm run start
In django_webpack_app/templates, we can see files
./django_webpack_app/templates
├── frontend-base.html
└── index.html
Check django_webpack_app/templates/frontend-base.html
{% block html %}
{% block css %}
<link href="http://localhost:9091/css/app.css" rel="stylesheet">
{% endblock %}
{% block js %}
<script src="http://localhost:9091/js/jquery.js"></script><script src="http://localhost:9091/js/vendors.js"></script><script src="http://localhost:9091/js/app.js"></script>
{% endblock %}
{% endblock %}
Django Template inheritance
Create django_webpack_app/templates/base.html
{% extends 'frontend-base.html' %}
{% block html %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{% block css %}
{{ block.super }}
{# we can add more css here #}
{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
{% block js %}
{{ block.super }}
{# we can add more js here #}
{% endblock %}
</body>
</html>
{% endblock %}
Notes:
- At the top, we
{% extends 'frontend-base.html' %}
- We put the html code at the
{% block html %}
, to override thehtml block
infrontend-base.html
- In
{% block css %}
, we use{{ block.super }}
to get content from the parent templatefrontend-base.html
. So css links would be inserted here. We can even add more css links as we like. - The
{% block js %}
works in the same way.
Update django_webpack_app/templates/index.html
{% extends 'base.html' %}
{% block content %}
<div class="jumbotron">
<div class="container">
<h1 class="display-3">Hello, world!</h1>
<p>This is a template for a simple marketing or informational website. It includes a large callout called a
jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a></p>
</div>
</div>
{% endblock %}
Notes:
- At the top, we
{% extends 'base.html' %}
- We fill the
{% block content %}
Now if we check the page in Django server, the js and css should work without any issues.
Conclusion
- The
django_webpack_app/templates/frontend-base.html
should be generated byHtmlWebpackPlugin
, please remember to add it togitignore
- With this solution, we do not need
django-webpack-loader
or other 3-party Django packages. - Some open source projects also use this strategy, for example, you can check django-vue-cli-webpack-demo
- Introduction
- Setup Webpack Project with Django
- Load Webpack bundles in Django
- Linting in Webpack
- Load Webpack hash bundle in Django
- Code splitting with Webpack
- How to config HMR with Webpack and Django
- How to use HtmlWebpackPlugin to load Webpack bundle in Django
If you want a quick start with Webpack and Django, please check python-webpack-boilerplate