# django-webpack-loader [![Build Status](https://circleci.com/gh/django-webpack/django-webpack-loader/tree/master.svg?style=svg)](https://circleci.com/gh/django-webpack/django-webpack-loader/tree/master) [![Coverage Status](https://coveralls.io/repos/github/django-webpack/django-webpack-loader/badge.svg?branch=master)](https://coveralls.io/github/django-webpack/django-webpack-loader?branch=master) ![pyversions](https://img.shields.io/pypi/pyversions/django-webpack-loader) ![djversions](https://img.shields.io/pypi/djversions/django-webpack-loader) Integrate Webpack bundles in Django templates by using a simple template tag: ```HTML+django {% load render_bundle from webpack_loader %} {% render_bundle 'main' 'css' %} ``` Behind the scenes, Django Webpack Loader consumes a **stats file** generated by [webpack-bundle-tracker](https://github.com/django-webpack/webpack-bundle-tracker) and lets you use the generated bundles in Django. A [changelog](CHANGELOG.md) is available. ## Compatibility Generally, Python, Django, and Node LTS releases will be supported until EOL. Check `tests/tox.ini` for details. Versions not listed in `tests/tox.ini` may still work, but maintainers will not test them, nor solve issues with them. Examples below are in Webpack 5. ## Install ```bash npm install --save-dev webpack-bundle-tracker pip install django-webpack-loader ``` ## Configuration For kick-starting a full example project with opinionated development and production settings, you can check the [`django-react-boilerplate`](https://github.com/vintasoftware/django-react-boilerplate/). For a more flexible configuration, keep reading. ### Configuring `webpack-bundle-tracker` Before configuring `django-webpack-loader`, let's first configure what's necessary on `webpack-bundle-tracker` side. Update your Webpack configuration file (it's usually on `webpack.config.js` in the project root). Make sure your file looks like this (adapt to your needs): ```javascript const path = require("path"); const webpack = require("webpack"); const BundleTracker = require("webpack-bundle-tracker"); module.exports = { context: __dirname, entry: "./assets/js/index", output: { path: path.resolve(__dirname, "assets/webpack_bundles/"), publicPath: "auto", // necessary for CDNs/S3/blob storages filename: "[name]-[contenthash].js", }, plugins: [ new BundleTracker({ path: __dirname, filename: "webpack-stats.json" }), ], }; ``` The configuration above expects the `index.js` (the app entrypoint file) to live inside the `/assets/js/` directory (this guide going forward will assume that all frontend related files are placed inside the `/assets/` directory, with the different kinds of files arranged within its subdirectories). The generated compiled files will be placed inside the `/assets/webpack_bundles/` directory and the **stats file with the information regarding the bundles and assets** (`webpack-stats.json`) will be stored in the project root. You may add `webpack-stats.json` to your `.gitignore`. ### Configuring the Django settings file First of all, add `webpack_loader` to `INSTALLED_APPS`. ```python INSTALLED_APPS = ( ... 'webpack_loader', ... ) ``` Below is the recommended setup for the Django settings file when using `django-webpack-loader`. ```python STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'assets'), ) WEBPACK_LOADER = { 'DEFAULT': { 'BUNDLE_DIR_NAME': 'webpack_bundles/', 'CACHE': not DEBUG, 'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'), 'POLL_INTERVAL': 0.1, 'IGNORE': [r'.+\.hot-update.js', r'.+\.map'], } } ``` Note that you must set the path where you're keeping your static assets and Webpack bundles in `STATICFILES_DIRS`. For that setup, we're using the `DEBUG` variable provided by Django. Since in a production environment (`DEBUG = False`) the assets files won't constantly change, we can safely cache the results (`CACHE=True`) and optimize our flow, as `django-webpack-loader` will read the stats file only once and store the assets paths in memory. If `CACHE=False`, we'll always read the stats file to get the assets paths. The `STATS_FILE` parameter represents the output file produced by `webpack-bundle-tracker`. Since in the Webpack configuration file we've named it `webpack-stats.json` and stored it on the project root, we must replicate that setting on the backend side. During development, the stats file will change often, therefore we want to always poll for its updated version (every 0.1s, as defined on `POLL_INTERVAL`). > ⚠️ In production (`DEBUG=False`), we'll only fetch the stats file once, so `POLL_INTERVAL` is ignored. `IGNORE` is a list of regular expressions. If a file generated by Webpack matches one of the expressions, the file will not be included in the template. ### Compiling the frontend assets Using Webpack, you must generate the frontend bundle along with the stats file using `webpack-bundle-tracker` before using `django-webpack-loader` in Django templates. Note you'll probably want different configurations in development vs. production. The pipeline should look like this: ```mermaid flowchart TD A("Run webpack") A --> |CSS, JS, imgs, fonts| B(Collect compiled assets) A --> |webpack-stats.json| C(Read on Django templates) ``` In development, we can simply do: ```bash # in one shell npx webpack --mode=development --watch # in another shell python manage.py runserver ``` Check [the full example for development here](https://github.com/django-webpack/django-webpack-loader/tree/master/examples/simple). Aditionally, hot reload is available through a specific config. Check [this section](#hot-reload). > ⚠️ For compiling and serving the frontend assets in production, check [this section](#using-in-production). ## Usage In order to render the frontend code into the Django templates, we use the `render_bundle` template tag. Its behavior is to accept a string with the name of an entrypoint from the stats file (in our case, we're using `main`, which is [the default](https://webpack.js.org/concepts/entry-points/#single-entry-shorthand-syntax)) and it'll proceed to include all files under that entrypoint. You can read more about the entrypoints concept [here](https://webpack.js.org/concepts/entry-points/). > ⚠️ You can also check an example on how to use multiple `entry` values [here](https://github.com/django-webpack/django-webpack-loader/tree/master/examples/code-splitting). Below is the basic usage for `render_bundle` within a template: ```HTML+Django {% load render_bundle from webpack_loader %} {% render_bundle 'main' 'css' %} ``` That will render the proper `