How to integrate Vue into an existing Django project

Django is a python web development framework that was initially released in 2005. It will be of no surprise that there are django projects as old as 10 years, some of us might have even inherited such projects. The method shown in this tutorial is proven to work on Django 1.8 and above. Little modifications might be necessary for a lower version of Django.

This integration will be making use of a js package, laravel-mix which is used in the Laravel project for integrating Vue.

Enough said, let’s get stuff done.

Assuming your project has the following structure;

--django-project
    --django-project
        settings.py
        urls.py
    --static
    --templates
        base.html

You should first create a package.json file in our project directory, and it should have the following content

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run development -- --watch",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.19",
        "bootstrap": "^4.0.0",
        "cross-env": "^6.0",
        "jquery": "^3.2",
        "laravel-mix": "^5.0.1",
        "lodash": "^4.17.13",
        "popper.js": "^1.12",
        "resolve-url-loader": "^2.3.1",
        "sass": "^1.20.1",
        "sass-loader": "7.*",
        "vue": "^2.5.17",
        "vue-template-compiler": "^2.6.10"
    },
}

This contains the necessary dependencies to get you up and running. After creating this file, you can now run yarn install or npm install depending on what package manager you use.

In your project directory, create a resources folder, it should have the following structure;

--resources/
    --js/
        --components/
        app.js
        bootstrap.js
    --sass
        app.scss

Next, you have to create a webpack.mix.js file in your project directory with the following content;

const mix = require('laravel-mix');


mix.js('resources/js/app.js', 'assets/js/vue-app.js')
   .sass('resources/sass/app.scss', 'assets/css/vue-app.css');

The code in this file takes the app.js file in the resources directory, processes it and places the compiled js file into vue-app.js, same with the app.scss file.  The assumption made here is that the assets folder is one of the places python manage.py collectstatic looks for static files.

You need to place some code into our app.js and bootstrap.js file

app.js

require('./bootstrap');

window.Vue = require('vue');

/**
 * The following block of code may be used to automatically register your
 * Vue components. It will recursively scan this directory for the Vue
 * components and automatically register them with their "basename".
 *
 * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
 */

// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))

Vue.component('example-component', require('./components/ExampleComponent.vue').default);

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

const app = new Vue({
    el: '#app',
});

Components that you create are registered in this file using the syntax

Vue.component('example-component', require('./components/ExampleComponent.vue').default);

This means that the component, ExampleComponent will be rendered in your HTML using the markup <example-component></example-component>

bootstrap.js

window._ = require('lodash');

/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

try {
    window.Popper = require('popper.js').default;
    window.$ = window.jQuery = require('jquery');

    require('bootstrap');
} catch (e) {}

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

You can now create a sample component in resources/js/components. You should name the file ExampleComponent.vue

ExampleComponent.vue

<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Example Component</div>

                    <div class="card-body">
                        I'm an example component.
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        mounted() {
            console.log('Component mounted.')
        }
    }
</script>

 

So how do you bring all of this into your django app? Remember you created a base.html file in your templates directory. This is assuming that other templates inherit from the base.html file, or in other words, base.html is a layout file.

So your base.html file looks this way

<!DOCTYPE html>
<html>
    <head>
        <title>Django vue</title>
    </head>
    <body>
        <div id="app">
            {% block body %}
            {% endblock %}
        </div>
        <script src="{% static 'js/vue-app.js' %}"></script>
    </body>
</html>

Lets now create an index.html file

{% extends 'base.html' %}
{% block body %}
<example-component></example-component>
{% endblock %}

ExampleComponent will be rendered where <example-component></example-component> is placed.

The assumption made here is that your index route does this return render(request, 'index.html') or in some other way, renders the index.html page

To get all of this cooked up and ready for consumption, run npm run dev or yarn run dev in the command line, depending on what package manager you use. This will compile your vue components into a js file.

Now go to your browser and visit your index url, you should have this nicely displayed

The bundle size of the vue-app.js file might be a bit large. You should consider removing imports that you do not need.

Also remember to add node_modules/ to your .gitignore file

 

Disclaimer: Most of the code written here was not created by me, they were taken from the Laravel project and adapted to work in django with little modifications. I claim no ownership to the code.

Leave a Reply

Your email address will not be published. Required fields are marked *