Getting Started with Webpack and Django

This walkthrough is aimed at providing a starter template for weaving Webpack into your front end Django workflow. Our goal is to create a project template that allows us to keep all of our source under version control, process our front end code locally with Webpack, and push everything out to production from Git.

Fire up a cup of tea, get ready for some command line use, and let's run through what we're going to do.

removed-gloves

Or just skip all of this and grab my project template from GitHub.
django-webpack-scaffolding.

Set Up Our Development Environment
Go Over Our Production Workflow
Next Steps

For additional details on using Django with Webpack and for further integration with ReactJS see Owais Lone's excellent article.

Requirements: Some understanding of Django, Python, Node, and Git. See this article for an overview of Git if you haven't used it.


Getting Started

Webpack's advantages are many. Chiefly it will process Sass (I've included Sass loaders, but you can also use Less.) Additionally, we can start using ES6 Javascript syntax and framework goodies like ReactJS. When we're ready, Webpack will wrap everything up into a beautifully uglified package.

Technically, we don't need Node on our production server since we're building locally and following Django's normal collectstatic process.

But for your dev setup, make sure you have Node, NPM, and Virtualenv installed.

node -v
should yield > v4.2.2
npm -v
should yield > 2.14.7
virtualenv --version
should yeild > 13.1.0

Node installation
Virtualenv installation (OSX)


Create a New Virtualenv

You know those clear plastic boxes with lots of little compartments for organizing nuts and bolts and screws? That's what a Virtualenv does. They keep our Python dependencies together in one place.

Open a new Terminal window and create a new virtualenv. I like to create them in a master projects folder called: ~/virtualenvs. Feel free to change this and do whatever you want, and feel free to replace projectname with the name of your project.

For Django 1.9 we're going to use Python 3.

virtualenv -p python3 projectname && cd projectname

This should give you a folder structure like this:

~/virtualenvs/projectname
├── bin
├── include
└── lib

And then we need to activate the virtualenv using the command:

source bin/activate

Install Django

With an active virtualenv we can now install Django. (We need to install Django first in order to use the django-admin command.)

pip install django==1.9.6

Start from the Template

Now we can build our project from the template. The startproject command accepts a parameter called --template that will grab the project from Git. By all means, please replace projectname in the command with the name of your project. ( We're still in the same virtualenv folder .)

django-admin startproject projectname --template=https://github.com/toymakerlabs/django-webpack-scaffolding/archive/master.zip --extension=js,json

>Troubleshooting Tip If you have many virtualenvs, sometimes DJANGO_SETTINGS_MODULE can stick from another project.

...
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2224, in _find_and_load_unlocked
ImportError: No module named 'xxyyzz'

If Django throws an error like the above, try echo $DJANGO_SETTINGS_MODULE. If it is not a blank space, run deactivate and make sure DJANGO_SETTINGS_MODULE is not set in bin/activate or set it to a blank space ""
(see here)

When installed, our virtualenv directory should look like this:

~/virtualenvs/projectname/
├── bin
├── include
├── lib
├── pip-selfcheck.json
└── projectname

Install Django Dependencies

Now we need to install Django dependencies. (In this case, django-webpack-loader.)

cd projectname
pip install -r requirements.txt

Once running, Django Webpack Loader will look for the presence of a webpack-stats.json file, which will tell Django where to find our static files depending on the environment we're in.



Update Virtualenv's 'bin/activate' Script

I like to use a split-settings configuration in my Django projects. Splitting the settings file allows us to change the environment we're working in from within the virtualenv. This saves us from needing two separate settings files that are outside of version control.

Open ../bin/activate in your editor of choice and paste the following at the bottom of your file (change projectname to the name of your project)

DJANGO_SETTINGS_MODULE="projectname.config.settings_development"
export DJANGO_SETTINGS_MODULE

Then activate the environment again to apply the settings change.

source ../bin/activate

>Tip:
Verify the value of DJANGO_SETTINGS_MODULE by echoing it in the terminal: echo $DJANGO_SETTINGS_MODULE. It should print: projectname.config.settings_development


Install Node Dependencies

Now we need to install Webpack and Webpack's supporting modules. My Django project template includes a package.json file that will allow us to install everything through npm.

npm install

(Npm will warn you that you need to update package.json with your description, version, and repo. Go ahead and do that at your leisure.)

If everything installed correctly, you should have a wall of text in the terminal but no big red error-looking stuff.

>Note: We can skip this step for production since we're building our production JS locally and committing it to source.


Nice We're getting there. Now is a good time for a refill.

george


Build an Initial Bundle

Package.json contains some npm shortcut commands that assist in building our asset bundles and running the dev server. Let's test our Webpack config by making an initial build.

npm run build

This command creates a folder called /static_src/bundles which is like the staging area for Webpack. Static assets are served locally by Webpack Dev Server from this directory.

The npm run build command will also create webpack-stats.json, which will tell Django how to assemble the URLs of our static assets.

The basic workflow is to run npm run build when you're in a good spot and ready to commit code changes.


Start Webpack

Let's kick the tires and fire up Webpack Dev Server. The dev server will monitor our files for changes and continuously build automatically.

npm run watch

The terminal should output a few messages, the first should let you know that the dev server is running on 0.0.0.0:3000 If everything worked, it should look like this:

Listening at 0.0.0.0:3000
Hash: 58222d8f24ef0415d367
Version: webpack 1.13.0
...
webpack: bundle is now VALID.

Valid bundle! Yas!


Run the Django Development Server

We need to leave Webpack Dev Server running in order for it to serve our static files. So open up a new terminal window and activate the environment (The new window should open to the same projectname directory. If not, cd there.)

source ../bin/activate

We might as well create an initial migration first, since Django will give us a warning.

python manage.py migrate

Now let's run the dev server!

python manage.py runserver

We should get this output if it's working:

Django version 1.9.6, using settings 'projectname.config.settings_development'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

nice job


Check it in the browser

Open your browser and paste:http://127.0.0.1:8000/

chrome

POW! Congrats! You're rocking with Webpack and Django!

This is a basic index view, but we can see that Webpack Dev Server is serving our static assets. One thing to remember: Webpack Dev Server is serving the assets from memory, so fear not if you don't see actual changes to the files in /static_src/js/ and /static_src/css/

When we run npm run build it will write our changes to our static files to /static_src/bundles/ The bundles folder also contains a map file, which is useful for debugging.


Development Workflow Overview Recap
  1. Open an new terminal and run npm run watch.
  2. Open another window and start the Django dev server.
  3. Develop. Develop. Develop.
  4. When you're ready to commit, pause webpack dev server and run npm run build
  5. Profit

Create a Production Bundle

Since part of our workflow involves committing everything to source, we need to create a production bundle and commit webpack-stats-production.json before we push our project.

Head back over to the terminal running Node and enter ^c to cancel the watching process.

Now we can run:

npm run build-production

This will create a new folder under /static/dist/ with our minified production bundles, and our webpack-stats-production.json file that will tell our production Django how to grab our static files.


* Optional: Test the Production Bundle Locally

If you're keen to give it ago, we can test the production bundle locally by making a few changes to projectname/config/settings_development.py

First set debug to False and ALLOWED_HOSTS to ***

########## DEBUG CONFIGURATION
DEBUG = False
ALLOWED_HOSTS = ['*']
########## END DEBUG CONFIGURATION

And then collect static. The collectstatic commmand will grab all of our static assets and copy them to the STATIC_ROOT defined in our settings.

python manage.py collectstatic

Now lets run the dev server again, only with the --insecure flag. The insecure flag tells django to to continue to serve assets with the dev server, even with debug=False. (Please dont do this on production >.<)

python manage.py runserver --insecure

Open the browser and head to http://127.0.0.1:8000.

If we look in the browser console, we should see that our static assets are serving from /static/dist/, and not from http://localhost:3000/

Now let's Flip debug back on in settings_development before we forget!

DEBUG = True
ALLOWED_HOSTS = []

And you may ask yourself, how did I get here?

Yes, that's from the Talking Heads. Let's take a second to go through our virtualenv folder and see what we've created.

~/virtualenvs/projectname/
├── projectname
//Webpack config and Django settings are stored here under /config/
 
├── manage.py
├── node_modules
├── package.json
├── server.js 
//Starts our Webpack Dev Server using the command: npm run watch

├── static
│   ├── dist
│   └── js
//Static is in our STATICFILES_DIRS setting. We can still use Django's method of including static files, but Webpack won't compress the files in here. Handy for legacy code or shims.

├── static_src
│   ├── bundles
│   ├── css
│   └── js
//This is where we develop our front end code. Webpack will bundle up everything in here through use of import or require (es6 vs es5.) /static_src/ is not in STATICFILES_DIRS because I thought it's good not to have the unminified bundles collected to production static root. 

├── staticfiles
│   ├── admin
│   ├── dist
│   └── js
//Staticfiles is our static root. This is just a temporary location for the example. Ideally this would be in your web root of Nginx or Apache, like: /var/www/static/, 

├── templates
│   ├── base.html
│   └── index.html
├── webpack-stats-prod.json
└── webpack-stats.json
// Webpack stats files are used by the django-webpack-loader templatetag to choose which static files to render depending on the environment

Production Workflow

Now that we have everything we need, it's a good time to initialize a new project repository from the projectname directory, commit, and push it.

Recommend Production Stack

For production environments, I recommend Postgres, Gunicorn, and Nginx. Our friends at Digital Ocean have a fantastic guide for getting a production environment up and running. See: How to set up Django with Postgres, Nginx, and Gunicorn

If you follow the article, skip the step: "Create the Django Project" and instead, clone the project we created, and adjust projectname/config/settings-production.py

However there are many ways of running Django in production. Your production setup will likely differ from mine, so let's talk workflow.


Production Workflow Overview

Let's say we've squashed a bug in the front end. Before we deploy to production, we need to tell Webpack to bundle and compress our static assets.

npm run build-production

This command sends our compressed assets to our static distribution folders in
static/dist/js/ and static/dist/css. It will also update webpack-stats-production.json which Django Webpack Loader uses to determine which static files to use based on our Webpack config.

When our build passes, we're ready.

  1. Run npm run build-production to create production static bundles.
  2. Commit everything to your repo
  3. Push to your repository
  4. Log in to production
  5. Pull from Git
  6. Run python manage.py collectstatic for static file changes to take effect.

I put up my test example in Git here Feel free to take a peek!


Where To Go From Here

Now that we have a starter project template, we can start adding cool things like Django Rest Framework and ReactJS.

Django Rest Framework
ReactJS
Django and ReactJS

Thanks for following along! Enjoy working with Django and Webpack.