django-webpack-loaderTransparently use webpack with django

联合创作 · 2023-09-22 21:46

django-webpack-loader

Build Status Coverage Status pyversions djversions

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>=2.0 on Python>=3.5. 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 django-webpack-loader

Migrating from version < 1.0.0

In order to use django-webpack-loader>=1.0.0, you must ensure that webpack-bundle-tracker@1.0.0 is being used on the JavaScript side. It's recommended that you always keep at least minor version parity across both packages, for full compatibility.

This is necessary because the formatting of webpack-stats.json that webpack-bundle-tracker outputs has changed starting at version 1.0.0-alpha.1. Starting at django-webpack-loader==1.0.0, this is the only formatting accepted here, meaning that other versions of that package don't output compatible files anymore, thereby breaking compatibility with older webpack-bundle-tracker releases.


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': [r'.+\.hot-update.js', r'.+\.map'],
        'LOADER_CLASS': 'webpack_loader.loader.WebpackLoader',
    }
}

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

>>> 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 src="/static/bundles/main.js" ></script>',
 '<link 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.

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

Then in your base jinja template:

{{ render_bundle('main') }}


Enjoy your webpack with django :)

Alternatives to Django-Webpack-Loader

Below are known projects that attempt to solve the same problem:

Note that these projects have not been vetted or reviewed in any way by me. These are not recommendation. Anyone can add their project to this by sending a PR.

浏览 5
点赞
评论
收藏
分享

手机扫一扫分享

编辑
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑
举报