How to set up Vue.js with Django

Getting Vue.js and Django to work together can be challenging, especially when sychronising the build .js files from Vue with the static folder in Django. There are various ways to go about it. The most popular of methods utilise the django-webpack-loader, where the Django library identifies the build files created by the Vue project. Here we are going to try a different approach, one that requires just a tiny amount of tinkering to get your Django + Vue project up and running.

#Installing Django

Before we install Django, we will set up a virtual environment for our Django project. Access the directory of your choice using the command line interface. With the cmd line we will create a new directory called djangovue and change to it.

mkdir djangovue
cd djangovue

To create a virtual environment, we will run the command python -m venv <name of your choice>. For this tutorial we will name our virtual environment env.

python -m venv env

This creates an env folder with our virtual environment settings. To activate our virtual environment, we will need to access the activate script which resides in the directory env/Scripts/. In the cmd line type

env\Scripts\activate

and you should see (env) prepended to your project directory like below.

(env) C:\djangovue>

Next we will install Django itself by running the command

pip install django

With django now installed, let's create a django project by entering the command

django-admin startproject djangosite

Now we have a folder called djangosite. The folder structure should look something like this.

|-env
|-djangosite
  |-djangosite
  |-manage.py

Change directory to the djangosite with cd djangosite and run the command python manage.py runserver, which will run django's development server. Visit the url http://127.0.0.1:8000/ or http://localhost:8000/ and we have our django website running.

django welcome page

#Installing Vue.js

Creating a Vue.js project will be slightly simpler. Open another cmd window for handling node.js operations. We will first install vue-cli with the command:

npm install -g @vue/cli

In our root djangovue folder, we will create our Vue project by running:

vue create vuesite

We will go with the default configuration. After the project is created, enter command cd vuesite and run npm run serve. Our vue side of the project will be available to us at http://localhost:8080/. The folder structure for reference looks like this.

|-env
|-djangosite
|-vuesite

django vue final look

#Configuring The Django Side

Now, our aim will be to get the front-page from http://localhost:8080/ (vue side) to show up in http://localhost:8000/ (django side).

Create a templates folder in djangosite. And then add an index.html file inside the newly created templates folder.

|-env
|-djangosite
  |-djangosite
    |-settings.py
  |-templates 
    |-index.html
|-vuesite

And in settings.py, configure your template settings by adding the location of your templates folder.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')], # add this
        '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',
            ],
        },
    },
]

We will also create a directory for static files called static, which will house the build files from the Vue project. Django will look for the javascript files here.

|-env
|-djangosite
  |-djangosite
    |-settings.py
    |-urls.py
  |-templates 
  |-static
|-vuesite

Again, in the settings.py file we will tell Django the location of the static directory. At the end of the settings.py file add:

STATIC_URL = '/static/'

# add this below STATIC_URL
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]

In urls.py, we will add a generic template view for our home page.

from django.contrib import admin
from django.urls import path

# add this
from django.views.generic import TemplateView



urlpatterns = [
    path('admin/', admin.site.urls),

    # add this
    path("", TemplateView.as_view(template_name='index.html')),
]

Let's add some content to our index.html file.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <p>We have created an Index.html page.</p>
</body>
</html>

When you now visit the url http://localhost:8000/, we should see the above content from index.html.

django new page

#Configuring The Vue Side

While working on the development end of Vue projects, there's a lot of abstraction and unless one goes looking, the .js files that run our project are hidden. They are, however, available to you in the dist folder, when you run the command npm run build.

What we need to do is to move these files to the static folder inside the djangosite directory. For that, we will create a vue.config.js file in the vuesite directory.

|-env
|-djangosite
|-vuesite
  |-dist
  |-node_modules
  |-public
  |-src
  |-package.json
  |-vue.config.js // create this file

Inside the vue.config.js file, we will direct Vue to place the build files in a folder of our choice.

module.exports = {
    outputDir: '../djangosite/static',
}

The .. means we go a directory up to the root, make our way to djangosite and then to the static folder. Let's run the command npm run build again. And voila, we have build files from the vuesite in our static folder over at the djangosite. However, running npm run build on every save isn't very ideal. What if we could watch for the save and then trigger the creation of a build file on every ctrl + s action? For that, we have a handy little vue-plugin called vue-cli-plugin-build-watch.

To install the plugin, run vue add vue-cli-plugin-build-watch and then start your app with npm run build-watch. The plugin will create a single app.js file on every save. If you are using vue-router, there will be code-splitting based on router components (code splitting is advised in production, but you can comment it out during development - settings available in router.js).

#Making It Work

In the templates/index.html file over at djangosite, we will make the following edits

<div id="app">

</div>

{% load static %}
<script src="{% static 'app.js' %}"></script>

<!-- or just -->
<script src="/static/app.js"></script>

In the vuesite/src/App.vue file, we will make a few edits to make sure things are working properly.

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png"> <!-- delete this line -->
    <HelloWorld msg="I'm building a Django + Vue.js application."/> <!-- edit this line -->
  </div>
</template>

Reload the url http://localhost:8000 and the edit from the Vue.js project should reflect on the django side.

django vue final look

And there you should have it, your project's Vue.js and Django parts are in sync. Happy coding!