Integrating Django and VueJs with Vue CLI 3 and Webpack Loader

A walk-through integrating Django as a backend to a running Vue App (with Vuetify) and Vue CLI 3

There are several articles on the web going through Django, the most popular python web framework, as a backend with frontend frameworks (React, Angular, VueJs, etc.). Still, I have not found any articles that cover integration of Django and Vue, using the Vue CLI 3 and Webpack Loader.

This method is not unique and there are other ways to do it without Webpack Loader, it’s not necessary to use Django to render a VueJs frontend, you could just make the Vue App consume Django Rest Framework JSON responses without rendering templates from Django, but with this method, it’s possible to run the whole scope as one production server. Though two developing servers will be needed, as we will see.

The Problem

Vue CLI 3 handles webpack configuration with an abstraction, by means of the vue.config.js file, this means no “ejecting”. It is an easier way to handle the woes of webpack configuration, and it is just as customizable as ejecting (see webpack-chain).

The problem that we have is that Django Webpack Loader uses the output.PublicPath webpack constant to redirect the path to the bundle, with the path that webpack-bundle-tracker generated in webpack-stats.json. And with the Vue CLI 3 there is a recommendation:

“…you should always use baseUrl instead of modifying webpack output.publicPath.”

This recommendation should not be ignored. And this can also lead to path problems. Actually, calls for a configuration workaround in order to Django Webpack Loader to correctly render the bundle generated by webpack and tracked by webpack-bundle-tracker. As we will see…

Let’s begin.

I am assuming that you already have NPM, Python 3, pip and virtualenv installed. And that you have basic understanding of Django and NPM package handling.

Create a virtual environment, install Django and create a Django Application

We begin by setting up a simple Django App.

Create Virtual Enviroment and Django Project

Let’s start by creating a virtual environment to our django application and activating it. On your virtual environments folder:

virtualenv django-vue
cd django-vue
source bin/activate

Install django in the virtual environment:

pip3 install django

Now, in your projects folder create a folder for this project:

django-admin startproject myproject
cd myproject

Create a file on you root folder called requirements.txt:

Django==2.1.3
django-webpack-loader==0.6.0
pytz==2018.7

Install the project requirements:

pip install -r requirements.txt

The next step is configuring your database, as this is not the point of this tutorial, we’re just creating a admin user and migrating default database settings:

python manage.py createsuperuser
Username (leave blank to use 'yourname'): admin
Email address:
admin@myproject.com
Password:
Password (again):
python manage.py migrate

You can run:

python manage.py runserver

Navigate you browser to http://127.0.0.1:8000, you should see django’s default page:

Mapping Urls, Views and Folders

Now let’s define folder structure on Django’s myproject/settings.py.

  1. Create a folder in your root directory called templates, set it as your templates folder.
  2. We should map the folder where we are going to build the Vue App.

To accomplish this, just add these two lines after the BASE_DIR line.

TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')
FRONTEND_DIR = os.path.join(BASE_DIR, 'frontend')

Also in settings.py, TEMPLATES should look like this:

TEMPLATES = [    
{
'BACKEND':
'django.template.backends.django.DjangoTemplates',
'DIRS': [TEMPLATES_DIR,],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages',
],
},
},
]

In your templates folder add a html file called application.html with this content:

{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>Django Vue Integration</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons">
</head>
<body>
<noscript>
<strong>We're sorry but frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<app></app>
</div>
{% render_bundle 'app' %}
<!-- built files will be auto injected -->
</body>
</html>

Let’s map the url to our vue application, your urls.py should look like this:

from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path("",
TemplateView.as_view(template_name="application.html"),
name="app",
),
]

Configuring Django Webpack Loader

Add webpack_loader to INSTALLED_APPS on settings.py:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'webpack_loader',
]

Add this configuration to the end of your myproject/settings.py file.

WEBPACK_LOADER = {
'DEFAULT': {
'CACHE': DEBUG,
'BUNDLE_DIR_NAME': '/bundles/', # must end with slash
'STATS_FILE': os.path.join(FRONTEND_DIR, 'webpack-stats.json'),
}
}

Installing and creating the Vue App

Install Vue CLI

To install Vue with NPM:

sudo npm install -g @vue/cli

Check that you’re running the correct version:

vue --version

It should output a 3.x version.

Now let’s create our Vue App with default configuration:

vue create frontend

If it crashes, use sudo.

Just select the default settings, or configure it to your necessity.

Add Vuetify

Now let’s add Material Design framework Vuetify, and this is how easy it is to work with Vue CLI 3. Just type:

cd frontend
vue add vuetify

Select the default settings or choose your own. This is an amazing UI library.

You should install the node dependencies, still in frontend folder type:

npm install

We’ll also need to install the webpack bundle tracker and add it to your package.json as a development dependence:

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

Now if you run (still on frontend folder):

npm run serve

And navigate to http://localhost:8080/. You should see the Vuetify default page:

But this is not what we want, this is a simple Vue app, we want to render the Vue application in Django, so we need to route the webpack bundle correctly.

Configuring webpack and devServer

Create file vue.config.js and add to your frontend folder with this content that we’ll get into in a second:

const BundleTracker = require("webpack-bundle-tracker");

module.exports = {
baseUrl: "http://0.0.0.0:8080/",
outputDir: './dist/',

chainWebpack: config => {

config.optimization
.splitChunks(false)

config
.plugin('BundleTracker')
.use(BundleTracker, [{filename: '../frontend/webpack-stats.json'}])

config.resolve.alias
.set('__STATIC__', 'static')

config.devServer
.public('http://0.0.0.0:8080')
.host('0.0.0.0')
.port(8080)
.hotOnly(true)
.watchOptions({poll: 1000})
.https(false)
.headers({"Access-Control-Allow-Origin": ["\*"]})
}
};

Now let’s explain what is in this file, this is the core webpack configuration in just a few lines (!!!), everything else is under the hood (checkout Vue inspect here).

We are changing the baseUrl constant to the path “http://0.0.0.0:8080”. because that’s where django-webpack-loader will redirect the path to the bundle, so we end up with a final url that’s plain weird (“http://0.0.0.0:8080/http://0.0.0.0:8080”). That’s the workaround, we set the devServer public url back to http://0.0.0.0:8080. And we’re done.

We’re setting split vendor chunks to false in order to webpack generate only one javascript file.

And we’re configuring the bundle tracker plugin to generate the webpack-stats.json in the project frontend folder. This is where the WEBPACK_LOADER config in settings.py should point to.

The other options we’ll help us later when we’re dealing with hot reload and docker.

Running the Vue bundle in Django DevServer:

We need two terminals:

First we run:

cd frontend
npm run serve

Than, in another terminal, this should have your virtual environment activated:

python manage.py runserver

Now navigate to http://127.0.0.1:8000, and you should see the Vue App instead of django’s default page. Cool eh? This means that the VueJs applications is being rendered through Django.

On Part Two, I plan on explaining how to do Vue-Django work with LiveReload development using Gulp.

On Part Three, let’s dockerize the whole application with docker-compose.

The source code for this project is in:

Repository for this article, click here.

References: