Package: django-webpack-loader
django-webpack-loaderIntegrate Webpack bundles in Django templates by using a simple template tag:{%loadrender_bundlefromwebpack_loader%}<html><head>{%render_bundle'main''css'%}</head></html>Behind the scenes, Django Webpack Loader consumes astats filegenerated bywebpack-bundle-trackerand lets you use the generated bundles in Django.Achangelogis available.CompatibilityGenerally, Python, Django, and Node LTS releases will be supported until EOL. Checktests/tox.inifor details.Versions not listed intests/tox.inimay still work, but maintainers will not test them, nor solve issues with them.Examples below are in Webpack 5.Installnpminstall--save-devwebpack-bundle-tracker

pipinstalldjango-webpack-loaderConfigurationFor kick-starting a full example project with opinionated development and production settings, you can check thedjango-react-boilerplate. For a more flexible configuration, keep reading.Configuringwebpack-bundle-trackerBefore configuringdjango-webpack-loader, let's first configure what's necessary onwebpack-bundle-trackerside. Update your Webpack configuration file (it's usually onwebpack.config.jsin the project root). Make sure your file looks like this (adapt to your needs):constpath=require("path");constwebpack=require("webpack");constBundleTracker=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 storagesfilename:"[name]-[contenthash].js",},plugins:[newBundleTracker({path:__dirname,filename:"webpack-stats.json"}),],};The configuration above expects theindex.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 thestats file with the information regarding the bundles and assets(webpack-stats.json) will be stored in the project root. You may addwebpack-stats.jsonto your.gitignore.Configuring the Django settings fileFirst of all, addwebpack_loadertoINSTALLED_APPS.INSTALLED_APPS=(...'webpack_loader',...)Below is the recommended setup for the Django settings file when usingdjango-webpack-loader.STATICFILES_DIRS=(os.path.join(BASE_DIR,'assets'),)WEBPACK_LOADER={'DEFAULT':{'BUNDLE_DIR_NAME':'webpack_bundles/','CACHE':notDEBUG,'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 inSTATICFILES_DIRS.For that setup, we're using theDEBUGvariable 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, asdjango-webpack-loaderwill read the stats file only once and store the assets paths in memory. IfCACHE=False, we'll always read the stats file to get the assets paths.TheSTATS_FILEparameter represents the output file produced bywebpack-bundle-tracker. Since in the Webpack configuration file we've named itwebpack-stats.jsonand 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 onPOLL_INTERVAL).⚠️ In production (DEBUG=False), we'll only fetch the stats file once, soPOLL_INTERVALis ignored.IGNOREis 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 assetsUsing Webpack, you must generate the frontend bundle along with the stats file usingwebpack-bundle-trackerbefore usingdjango-webpack-loaderin Django templates. Note you'll probably want different configurations in development vs. production. The pipeline should look like this: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:# in one shellnpxwebpack--mode=development--watch# in another shellpythonmanage.pyrunserverCheckthe full example for development here.Aditionally, hot reload is available through a specific config. Checkthis section.⚠️ For compiling and serving the frontend assets in production, checkthis section.UsageIn order to render the frontend code into the Django templates, we use therender_bundletemplate tag.Its behavior is to accept a string with the name of an entrypoint from the stats file (in our case, we're usingmain, which isthe default) and it'll proceed to include all files under that entrypoint. You can read more about the entrypoints concepthere.⚠️ You can also check an example on how to use multipleentryvalueshere.Below is the basic usage forrender_bundlewithin a template:{%loadrender_bundlefromwebpack_loader%}<html><head>{%render_bundle'main''css'%}</head></html>That will render the proper<script>and<link>tags needed in your template.Using in testsTo run tests whererender_bundleshows up, since we don't havewebpack-bundle-trackerat that point to generate the stats file, the calls to render the bundle will fail. The solution is to use theFakeWebpackLoaderin your test settings:WEBPACK_LOADER['DEFAULT']['LOADER_CLASS']='webpack_loader.loaders.FakeWebpackLoader'Using in ProductionThe recommended apporach is to have a production pipeline that generates the frontend bundle along with the stats file during thedeployment phase. We recommend keeping the generated bundles and the stats file outside the version control. In other words, addwebpack-stats.jsonandassets/webpack_bundles/to your.gitignore.Assuming static files is properly configured using Django built-ins or something likedjango-storages, a simple production deployment can use Django's owncollectstatic. Remember the Django settings values ofSTATICFILES_DIRS,BUNDLE_DIR_NAME,STATS_FILE, and Webpack'soutput.pathmust all be compatible:// webpack.config.jsmodule.exports={// ...context:__dirname,output:{// Emit bundle files at "assets/webpack_bundles/":path:path.resolve(__dirname,"assets/webpack_bundles/"),publicPath:"auto",// necessary for CDNs/S3/blob storagesfilename:"[name]-[contenthash].js",},plugins:[// Emit 'webpack-stats.json' in project root for Django to find it:newBundleTracker({path:__dirname,filename:"webpack-stats.json"}),],};# app/settings.pyBASE_DIR=...# set to project rootSTATICFILES_DIRS=(# make Django collect all "assets/" and "assets/webpack_bundles"# to be served at "my-static-url.com/asset-name.png"# and "my-static-url.com/webpack_bundles/main.js"os.path.join(BASE_DIR,'assets'),)WEBPACK_LOADER={'DEFAULT':{# Bundle directory, like in "my-static-url.com/webpack_bundles/main.js":'BUNDLE_DIR_NAME':'webpack_bundles/',# Absolute path to where 'webpack-stats.json' is in Django project root:'STATS_FILE':os.path.join(BASE_DIR,'webpack-stats.json'),# ...}}In your deployment script, you must first run your Webpack build in production-mode, before callingcollectstatic:NODE_ENV=production webpack --progress --bail --mode=production
python manage.py collectstatic --noinputThis means we're building the assets and, since we havewebpack-bundle-trackerin our Webpack building pipeline, thewebpack-stats.jsonstats file is also populated. If you followed the default configuration, thewebpack-stats.jsonwill be at Django's project root (BASE_DIR) and therender_bundletemplate tag will be able to use it.However, production usage for this package isfairly flexible, as the entire Django-Webpack integration depends only on thewebpack-stats.jsonfile.⚠️ Heroku is one platform that automatically runs collectstatic for you, so you need to set theDISABLE_COLLECTSTATIC=1environment var and manually run collectstatic after running Webpack. In Heroku, this is achieved with apost_compilehook. Here'san example.Advanced UsageHot reloadHot reload (Hot Module Replacement)is critical for a improving the development workflow. In case you wish to enable for your project, please check outthis example, in particular howwebpack.config.jsis configured. The key is to set thepublicPathanddevServer.Dynamic ImportsIn case you wish to useDynamic Imports, please check outthis example, in particular howwebpack.config.jsis configured.Extra options forwebpack-bundle-trackerCheckwebpack-bundle-trackerREADMEfor all supported options, such as relative paths, integrity hashes, timestamp logging, etc.ExtraWEBPACK_LOADERsettings in DjangoSet those extra settings inside like this:WEBPACK_LOADER={'DEFAULT':{# settings go here}TIMEOUTis the number of seconds webpack_loader should wait for Webpack to finish compiling before raising an exception.0,Noneor leaving the value out of settings disables timeoutsINTEGRITYis flag enablingSubresource Integrityon rendered<script>and<link>tags. Integrity hash is get from stats file and configuration on side ofBundleTracker, whereconfiguration optionintegrity: trueis required.LOADER_CLASSis the fully qualified name of a python class as a string that holds the custom Webpack loader. This is where behavior can be customized as to how the stats file is loaded. Examples include loading the stats file from a database, cache, external URL, etc. For convenience,webpack_loader.loaders.WebpackLoadercan be extended. Theload_assetsmethod is likely where custom behavior will be added. This should return the stats file as an object.Here's a simple example of loading from an external URL:importrequestsfromwebpack_loader.loadersimportWebpackLoaderclassExternalWebpackLoader(WebpackLoader):defload_assets(self):url=self.config['STATS_URL']returnrequests.get(url).json()SKIP_COMMON_CHUNKS(Default:False) is a flag which prevents already generated chunks from being included again in the same page. This should only happen if you use more than one entrypoint per Django template (multiplerender_bundlecalls). By enabling this, you can get the same default behavior of theHtmlWebpackPlugin. The same caveats apply as when usingskip_common_chunksonrender_bundle, see that section below for more details.Rendering by file extensionrender_bundlealso takes a second argument which can be a file extension to match. This is useful when you want to render different types for files in separately. For example, to render CSS in head and JS at bottom we can do something like this:{%loadrender_bundlefromwebpack_loader%}<html><head>{%render_bundle'main''css'%}</head><body>....{%render_bundle'main''js'%}</body></head>Using preloadTheis_preload=Trueoption in therender_bundletemplate tag can be used to addrel="preload"link tags:{%loadrender_bundlefromwebpack_loader%}<html><head>{%render_bundle'main''css'is_preload=True%}{%render_bundle'main''js'is_preload=True%}{%render_bundle'main''css'%}</head><body>{%render_bundle'main''js'%}</body></html>Accessing other webpack assetswebpack_statictemplate tag provides facilities to load static assets managed by Webpack in Django templates. It is like Django's built instatictag but for Webpack assets instead.In the example below,logo.pngcan be any static asset shipped with any npm package:{%loadwebpack_staticfromwebpack_loader%}<!-- render full public path of logo.png --><imgsrc="{%webpack_static'logo.png'%}"/>The public path is based onwebpack.config.jsoutput.publicPath.Please note that this approach will use the original asset file, and not a post-processed one from the Webpack pipeline, in case that file had gone through such flow (e.g.: You've imported an image on the React side and used it there, the file used within the React components will probably have a hash string on its name, etc. This processed file will be different than the one you'll grab withwebpack_static).Useskip_common_chunksonrender_bundleYou can use the parameterskip_common_chunks=Trueorskip_common_chunks=Falseto override the globalSKIP_COMMON_CHUNKSsetting for a specific bundle.In order for this option to work,django-webpack-loaderrequires therequestobject to be in the template context. Therequestobject is passed by default via thedjango.template.context_processors.requestcontext processor, so make sure you have that.If you don't haverequestin the context for some reason (e.g. usingTemplate.renderorrender_to_stringdirectly without passing the request), you'll get warnings on the console and the common chunks will remain duplicated.Appending file extensionsThesuffixoption can be used to append a string at the end of the file URL. For instance, it can be used if your Webpack configuration emits compressed.gzfiles.{%loadrender_bundlefromwebpack_loader%}<html><head><metacharset="UTF-8"><title>Example</title>{%render_bundle'main''css'%}</head><body>{%render_bundle'main''js'suffix='.gz'%}</body></html>Multiple Webpack configurationsdjango-webpack-loaderalso supports multiple Webpack configurations. Assuming you have different Webpack configs, each with a differentoutput.path, the following configuration defines 2 Webpack stats files in settings and uses theconfigargument in the template tags to influence which stats file to load the bundles from:WEBPACK_LOADER={'DEFAULT':{'BUNDLE_DIR_NAME':'bundles/','STATS_FILE':os.path.join(BASE_DIR,'webpack-stats.json'),},'DASHBOARD':{'BUNDLE_DIR_NAME':'dashboard_bundles/','STATS_FILE':os.path.join(BASE_DIR,'webpack-stats-dashboard.json'),}}{%loadrender_bundlefromwebpack_loader%}<html><body>....{%render_bundle'main''js''DEFAULT'%}{%render_bundle'main''js''DASHBOARD'%}<!-- or render all files from a bundle -->{%render_bundle'main'config='DASHBOARD'%}<!-- the following tags do the same thing -->{%render_bundle'main''css''DASHBOARD'%}{%render_bundle'main'extension='css'config='DASHBOARD'%}{%render_bundle'main'config='DASHBOARD'extension='css'%}<!-- add some extra attributes to the tag -->{%render_bundle'main''js''DEFAULT'attrs='async charset="UTF-8"'%}</body></head>File URLs instead of HTML tagsIf you need the URL to an asset without the HTML tags, theget_filestemplate tag can be used. A common use case is specifying the URL to a custom CSS file for a Javascript plugin.get_filesworks exactly likerender_bundleexcept it returns a list of matching files and lets you assign the list to a custom template variable.Each object in the returned list has 2 properties:name, which is the name of a chunk from the stats file;url, which can be:ThepublicPathif the asset has one;Thepathto the asset in the static files storage, if the asset doesn't have apublicPath.For example:{%loadget_filesfromwebpack_loader%}{%get_files'editor''css'aseditor_css_files%}CKEDITOR.config.contentsCss = '{{editor_css_files.0.url}}';<!-- or list down name and url for every file --><ul>{%forcss_fileineditor_css_files%}<li>{{css_file.name}}:{{css_file.url}}</li>{%endfor%}</ul>Jinja2 ConfigurationIf you need to output your assets in a jinja template, we provide a Jinja2 extension that's compatible withdjango-jinja.To install the extension, add it to theTEMPLATESconfiguration in the["OPTIONS"]["extension"]list.fromdjango_jinja.builtinsimportDEFAULT_EXTENSIONSTEMPLATES=[{"BACKEND":"django_jinja.backend.Jinja2","OPTIONS":{"extensions":DEFAULT_EXTENSIONS+["webpack_loader.contrib.jinja2ext.WebpackExtension",],}}]Then in your base jinja template, do:{{ render_bundle('main') }}Note:get_filesin Jinja2 is calledwebpack_get_files.Migrating from version < 1.0.0In order to usedjango-webpack-loader>=1.0.0, you must ensure thatwebpack-bundle-tracker@1.0.0is being used on the JavaScript side. It's recommended that you always keep at least minor version parity across both packages for full compatibility.ContributingThis project includes a Makefile that provides several useful commands for building, installing, and publishing the project. Please feel free to open PRs or create issues!Available Commandsclean: Removes generated files and directories.build: Cleans the project and builds the distribution packages.test: Run the tests.install: Installs the project's build dependencies. Will initialize a virtual environment if one does not exist.publish: Builds the distribution packages and publishes them to the specified repository.register: Registers the package on the specified repository.To execute a command, runmake <command>in the project's root directory.Virtual Environment SettingsENV: The name of the virtual environment. (Default:venv)REPOSITORY: The repository to publish the distribution packages to. (Default:pypi)Special ThanksDjango Webpack Loader was originally created byOwais Loneand received contributions from more than 50 developers since its inception, as well as many others who assisted with issues, comments, articles, talks, etc. Thanks for everyone who's been part of Django Webpack Loader community!Commercial SupportThis project is currently maintained byVinta Softwareand is used in products of Vinta's clients. We are always looking for exciting work, so if you need any commercial support, feel free to get in touch:contact@vinta.com.br