Skip to main content

Transparently use webpack with django

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 <https://github.com/owais/webpack-bundle-tracker>`__
and lets you use the generated bundles in django.

Maintainers
-----------

In order to overcome the lack of support for Markdown on PyPi, building
this package can use `pandoc <http://pandoc.org/installing.html>`__
along with `pypandoc <https://pypi.python.org/pypi/pypandoc>`__ to
convert the README.md into a Restructured Text format compatible with
PyPI. This requires installing ``pandoc`` for your operating system
(installation instructions on the pandoc site), and ``pypandoc`` which
will be installed if you:

::

pip install -r requirements-dev.txt

before uploading to PyPI.

If pandoc or pypandoc fails, the README.md file will be uploaded as it
was before this enhancement.

Compatibility
-------------

Test cases cover Django>=1.6 on Python 2.7 and Python>=3.3. 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
-------

.. code:: bash

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

pip install django-webpack-loader

Configuration
-------------

Assumptions
~~~~~~~~~~~

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

.. code:: python

import sys
import os

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

Assuming ``assets/`` is in ``settings.STATICFILES_DIRS`` like

.. code:: python

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

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

.. code:: javascript

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
~~~~~~~~~~~~~~~~~~~~~

.. code:: python

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
^^^^^

.. code:: python

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
^^^^^^^^^^^^^^^^^

.. code:: python

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 you
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

.. code:: html

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

STATS\_FILE
^^^^^^^^^^^

.. code:: python

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

.. code:: javascript

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 <https://github.com/owais/django-webpack-loader/tree/master/examples>`__,
read `my detailed blog
post <http://owaislone.org/blog/webpack-plus-reactjs-and-django/>`__ or
check `webpack docs <http://webpack.github.io/>`__.

Settings
~~~~~~~~

Add ``webpack_loader`` to ``INSTALLED_APPS``

::

INSTALLED_APPS = (
...
'webpack_loader',
)

Templates
~~~~~~~~~

.. code:: html+django

{% 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,

.. code:: html+django

{% load render_bundle from webpack_loader %}

<html>
<head>
{% render_bundle 'main' 'css' %}
</head>
<body>
....
{% render_bundle '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.

.. code:: python

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'),
}
}

.. code:: html+django

{% 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,

.. code:: html+django

{% 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.

.. code:: html+django

{% load webpack_static from webpack_loader %}

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

>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.

.. code:: python

>>> 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``

.. code:: javascript

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``

.. code:: python

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 <https://github.com/niwinz/django-jinja>`__ module and Django 1.8.

To install the extension add it to the django\_jinja ``TEMPLATES``
configuration in the ``["OPTIONS"]["extension"]`` list.

.. code:: python

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

Then in your base jinja template:

.. code:: html

{{ render_bundle('main') }}

--------------

Enjoy your webpack with django :)

.. |Join the chat at https://gitter.im/owais/django-webpack-loader| image:: https://badges.gitter.im/Join%20Chat.svg
:target: https://gitter.im/owais/django-webpack-loader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
.. |Build Status| image:: https://travis-ci.org/owais/django-webpack-loader.svg?branch=master
:target: https://travis-ci.org/owais/django-webpack-loader
.. |Coverage Status| image:: https://coveralls.io/repos/owais/django-webpack-loader/badge.svg?branch=master&service=github
:target: https://coveralls.io/github/owais/django-webpack-loader?branch=master

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-webpack-loader-0.5.0.tar.gz (12.2 kB view details)

Uploaded Source

Built Distribution

django_webpack_loader-0.5.0-py2.py3-none-any.whl (17.3 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django-webpack-loader-0.5.0.tar.gz.

File metadata

File hashes

Hashes for django-webpack-loader-0.5.0.tar.gz
Algorithm Hash digest
SHA256 7094bcd8cc40c9824e5b482ce8ff9e8ae09e1982e5d08e078e5fe2411fb40a03
MD5 c55d4b7d6f4d06d681132c47ebfa4d41
BLAKE2b-256 2e7f2e1779c26687351ecc61216404f21a996bf8ca8ef4f8c5a8a029c5941c6e

See more details on using hashes here.

File details

Details for the file django_webpack_loader-0.5.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for django_webpack_loader-0.5.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 0a8536e36a30d719018cd4c5da6e9d2377771134e713c14e617bb484b4f0acce
MD5 84c5de47c0c2214779384dc19cbca13a
BLAKE2b-256 6a1d3680c3cd7bf5a35a0ed451201fbdd93d7b17e63045d97bb8e2d4ba754e5f

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