Skip to main content

Transparently use webpack with django. Forked from https://github.com/scdekov/django-webpack-loader

Project description

django-webpack-loader

Join the chat at https://gitter.im/owais/django-webpack-loader Build Status Coverage Status


Read http://owaislone.org/blog/webpack-plus-reactjs-and-django/ for a detailed step by step guide on setting up webpack with django using this library.

Use webpack to generate your static bundles without django's staticfiles or opaque wrappers.

Django webpack loader consumes the output generated by webpack-bundle-tracker and lets you use the generated bundles in django.

A changelog is also available.

Compatibility

Test cases cover Django>=1.6 on Python 2.7 and Python>=3.4. 100% code coverage is the target so we can be sure everything works anytime. It should probably work on older version of django as well but the package does not ship any test cases for them.

Install

npm install --save-dev webpack-bundle-tracker

pip install django4-webpack-loader

Configuration


Assumptions

Assuming BASE_DIR in settings refers to the root of your django app.

import sys
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Assuming assets/ is in settings.STATICFILES_DIRS like

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'assets'),
)

Assuming your webpack config lives at ./webpack.config.js and looks like this

var path = require("path");
var webpack = require("webpack");
var BundleTracker = require("webpack-bundle-tracker");

module.exports = {
  context: __dirname,
  entry: "./assets/js/index",
  output: {
    path: path.resolve("./assets/webpack_bundles/"),
    filename: "[name]-[hash].js"
  },

  plugins: [new BundleTracker({ filename: "./webpack-stats.json" })]
};

Default Configuration

WEBPACK_LOADER = {
    'DEFAULT': {
        'CACHE': not DEBUG,
        'BUNDLE_DIR_NAME': 'webpack_bundles/', # must end with slash
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
        'POLL_INTERVAL': 0.1,
        'TIMEOUT': None,
        'IGNORE': ['.+\.hot-update.js', '.+\.map']
    }
}

CACHE

WEBPACK_LOADER = {
    'DEFAULT': {
        'CACHE': not DEBUG
    }
}

When CACHE is set to True, webpack-loader will read the stats file only once and cache the result. This means web workers need to be restarted in order to pick up any changes made to the stats files.


BUNDLE_DIR_NAME

WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'bundles/' # end with slash
    }
}

BUNDLE_DIR_NAME refers to the dir in which webpack outputs the bundles. It should not be the full path. If ./assets is one of your static dirs and webpack generates the bundles in ./assets/output/bundles/, then BUNDLE_DIR_NAME should be output/bundles/.

If the bundle generates a file called main-cf4b5fab6e00a404e0c7.js and your STATIC_URL is /static/, then the <script> tag will look like this

<script
  type="text/javascript"
  src="/static/output/bundles/main-cf4b5fab6e00a404e0c7.js"
/>

STATS_FILE

WEBPACK_LOADER = {
    'DEFAULT': {
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
    }
}

STATS_FILE is the filesystem path to the file generated by webpack-bundle-tracker plugin. If you initialize webpack-bundle-tracker plugin like this

new BundleTracker({ filename: "./webpack-stats.json" });

and your webpack config is located at /home/src/webpack.config.js, then the value of STATS_FILE should be /home/src/webpack-stats.json


IGNORE

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.


POLL_INTERVAL

POLL_INTERVAL is the number of seconds webpack_loader should wait between polling the stats file. The stats file is polled every 100 miliseconds by default and any requests to are blocked while webpack compiles the bundles. You can reduce this if your bundles take shorter to compile.

NOTE: Stats file is not polled when in production (DEBUG=False).


TIMEOUT

TIMEOUT is the number of seconds webpack_loader should wait for webpack to finish compiling before raising an exception. 0, None or leaving the value out of settings disables timeouts.


Usage


Manually run webpack to build assets.

One of the core principles of django-webpack-loader is to not manage webpack itself in order to give you the flexibility to run webpack the way you want. If you are new to webpack, check one of the examples, read my detailed blog post or check webpack docs.

Settings

Add webpack_loader to INSTALLED_APPS

INSTALLED_APPS = (
    ...
    'webpack_loader',
)

Templates

render_bundle

{% load render_bundle from webpack_loader %}

{% render_bundle 'main' %}

render_bundle will render the proper <script> and <link> tags needed in your template.

render_bundle also 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,

{% load render_bundle from webpack_loader %}

<html>
  <head>
    {% render_bundle 'main' 'css' %}
  </head>
  <body>
    ....
    {% render_bundle 'main' 'js' %}
  </body>
</head>

render_entrypoint (Available only when using Webpack v.4 or newer)

{% load render_entrypoint from webpack_loader %}

{% render_entrypoint 'index' %}

render_entrypoint will render all the proper <script> and <link> tags needed in your template for that endpoint. Using this, you can make use of webpack 4 code splitting features. Example webpack config:

module.exports = {
  ...,
  entry: {
    index: "./myapp/static/src/pages/index.js",
    contact_us: "./myapp/static/src/pages/contact_us.js",
  },
  ...,
  plugins: [new BundleTracker({ filename: "./webpack-stats.json" })]
};

Just as render_bundle, render_entrypoint also takes a second argument which can be a file extension to match, and can be used in a similar way,

{% load render_entrypoint from webpack_loader %}

<html>
  <head>
    {% render_entrypoint 'main' 'css' %}
  </head>
  <body>
    ....
    {% render_entrypoint 'main' 'js' %}
  </body>
</head>

Multiple webpack projects

Version 2.0 and up of webpack loader also supports multiple webpack configurations. The following configuration defines 2 webpack stats files in settings and uses the config argument 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'),
    }
}
{% load render_bundle from webpack_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 chatset="UTF-8"'%}
  </body>
</head>

File URLs instead of html tags

If you need the URL to an asset without the HTML tags, the get_files template tag can be used. A common use case is specifying the URL to a custom css file for a Javascript plugin.

get_files works exactly like render_bundle except it returns a list of matching files and lets you assign the list to a custom template variable. For example,

{% get_files 'editor' 'css' as editor_css_files %}
CKEDITOR.config.contentsCss = '{{ editor_css_files.0.publicPath }}';

<!-- or list down name, path and download url for every file -->
<ul>
{% for css_file in editor_css_files %}
    <li>{{ css_file.name }} : {{ css_file.path }} : {{ css_file.publicPath }}</li>
{% endfor %}
</ul>

Refer other static assets

webpack_static template tag provides facilities to load static assets managed by webpack in django templates. It is like django's built in static tag but for webpack assets instead.

In the below example, logo.png can be any static asset shipped with any npm or bower package.

{% load webpack_static from webpack_loader %}

<!-- render full public path of logo.png -->
<img src="{% webpack_static 'logo.png' %}"/>

The public path is based on webpack.config.js output.publicPath.


From Python code

If you want to access the webpack asset path information from your application code then you can use the function in the webpack_loader.utils module.

>>> utils.get_files('main')
[{'url': '/static/bundles/main.js', u'path': u'/home/mike/root/projects/django-webpack-loader/tests/assets/bundles/main.js', u'name': u'main.js'},
 {'url': '/static/bundles/styles.css', u'path': u'/home/mike/root/projects/django-webpack-loader/tests/assets/bundles/styles.css', u'name': u'styles.css'}]
>>> utils.get_as_tags('main')
['<script type="text/javascript" src="/static/bundles/main.js" ></script>',
 '<link type="text/css" href="/static/bundles/styles.css" rel="stylesheet" />']

How to use in Production

It is up to you. There are a few ways to handle this. I like to have slightly separate configs for production and local. I tell git to ignore my local stats + bundle file but track the ones for production. Before pushing out newer version to production, I generate a new bundle using production config and commit the new stats file and bundle. I store the stats file and bundles in a directory that is added to the STATICFILES_DIR. This gives me integration with collectstatic for free. The generated bundles are automatically collected to the target directory and synched to S3.

./webpack_production.config.js

var config = require("./webpack.config.js");
var BundleTracker = require("webpack-bundle-tracker");

config.output.path = require("path").resolve("./assets/dist");

config.plugins = [new BundleTracker({ filename: "./webpack-stats-prod.json" })];

// override any other settings here like using Uglify or other things that make sense for production environments.

module.exports = config;

settings.py

if not DEBUG:
    WEBPACK_LOADER.update({
        'BUNDLE_DIR_NAME': 'dist/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats-prod.json')
    })



You can also simply generate the bundles on the server before running collectstatic if that works for you.

Extra

Jinja2 Configuration

If you need to output your assets in a jinja template we provide a Jinja2 extension that's compatible with the Django Jinja module and Django 1.8.

To install the extension add it to the django_jinja TEMPLATES configuration in the ["OPTIONS"]["extension"] list.

TEMPLATES = [
    {
        "BACKEND": "django_jinja.backend.Jinja2",
        "OPTIONS": {
            "extensions": [
                "django_jinja.builtins.extensions.DjangoFiltersExtension",
                "webpack_loader.contrib.jinja2ext.WebpackExtension",
            ],
        }
    }
]

Then in your base jinja template:

{{ render_bundle('main') }}


Enjoy your webpack with django :)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-webpack4-loader-0.0.1.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

django_webpack4_loader-0.0.1-py2.py3-none-any.whl (13.9 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django-webpack4-loader-0.0.1.tar.gz.

File metadata

  • Download URL: django-webpack4-loader-0.0.1.tar.gz
  • Upload date:
  • Size: 11.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0 requests/2.18.4 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.0 CPython/3.5.5

File hashes

Hashes for django-webpack4-loader-0.0.1.tar.gz
Algorithm Hash digest
SHA256 4a04c3a1decf0154af707e674fa870b106d16432d1526510db4e5d7ef5613361
MD5 3f15f734bae5e9e20c186cef0505f306
BLAKE2b-256 06f26a01a060a74bd5b275450d8d0affbac3e23786a634e1c447a873fa759af9

See more details on using hashes here.

File details

Details for the file django_webpack4_loader-0.0.1-py2.py3-none-any.whl.

File metadata

  • Download URL: django_webpack4_loader-0.0.1-py2.py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0 requests/2.18.4 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.0 CPython/3.5.5

File hashes

Hashes for django_webpack4_loader-0.0.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 2cd1ea199c066b00c857f89269ff12686f9c4b1d8e2c23de7a26d2ee651233eb
MD5 b7161dea7a503a128a76339f45c3f39d
BLAKE2b-256 b5de89b13ade29bb58e9546597353eaca3c20b7796c22406fa6a739d20d8693b

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page