Integrating Django as a backend to a running Vue App.
The version of Vue 3 has been available for some time now!
While I’m writing this post the 3.2 version has just been released.
Let’s begin.
I am assuming that you have already the powerful version manager asdf installed. And that you have basic understanding of Django and Nodejs package handling.
Create a virtual environment with Nodejs, yarn, python 3, PostgreSQL, Django and create a Django Application
You will need a compiler.
Ubuntu:
- sudo apt install linux-headers-$(uname -r) build-essential
On Ubuntu, you will need libreadline
- sudo apt-get install libreadline-dev
On Ubuntu 20.04, you will need curl and zlib
- sudo apt-get install zlib1g-dev curl
asdf plugin-add nodejs
asdf plugin-add yarn
asdf plugin-add python
asdf plugin-add postgres
# Import the Node.js release team's OpenPGP keys to main keyring:
bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring
# create virtual env for all
mkdir venv-django
cd venv-django
# install all latest versions
~/venv-django asdf install nodejs latest
~/venv-django asdf install yarn latest
~/venv-django asdf install python latest
~/venv-django asdf install postgres latest
# set .tool-versions in your virtual env
# if you don't remember the latest version you can use
# `asdf list postgres` for example
~/venv-django asdf local nodejs 14.2.0
~/venv-django asdf local yarn 1.22.4
~/venv-django asdf local python 3.8.2
~/venv-django asdf local postgres 12.2
# check if all good
cat .tool-versions
~/venv-django node -v
v14.2.0
~/venv-django yarn -v
1.22.4
~/venv-django python --version
Python 3.8.2
~/venv-django postgres --version
postgres (PostgreSQL) 12.2
# start postgres
pg_ctl start
# create database
~/venv-django createdb django
#test connection
~/venv-django psql -d django
django=# exit
Now, you should be ready to create the project backend:
~/venv-django pip install django
# reshim v-env
~/venv-django asdf reshim
# create Django project
~/venv-django django-admin startproject mysite
~/venv-django cd mysite
Configure django to use postgres
~/venv-django pip install psycopg2-binary
# mysite/mysite/settings.py
. . .
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'django',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '',
}
}
. . .
Run migrations
~/venv-django/mysite python manage.py migrate
test backend server: ~/venv-django/mysite python manage.py runserver
and navigate to http://127.0.0.1:8000/
At this point, you should see:
Hit CONTROL-C, and now, you should be ready to create the frontend project:
~/venv-django/mysite mkdir frontend && cd frontend
# init the frontend project and hit enter for all questions
~/venv-django/mysite/frontend yarn init
yarn init v1.22.4
question name (frontend):
question version (1.0.0):
question description:
question entry point (index.js):
question repository url:
question author:
question license (MIT):
question private:
success Saved package.json
Done in 3.56s.
Install the dependencies:
~/venv-django/mysite/frontend yarn add vue@next webpack-bundle-tracker@0.4.3
~/venv-django/mysite/frontend yarn add --dev yarn vue-loader@v16.8.2 webpack-cli webpack webpack-dev-server typescript ts-loader @vue/compiler-sfc
Create a webpack.config.js in your frontend directory:
// frontend/webpack.config.js
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const BundleTracker = require('webpack-bundle-tracker');
module.exports = (env = {}) => {
return {
mode: env.prod ? 'production' : 'development',
devtool: env.prod ? 'source-map' : 'cheap-module-eval-source-map',
entry: path.resolve(__dirname, './src/main.ts'),
output: {
path: path.resolve(__dirname, './dist'),
},
module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader'
},
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/],
}
},
]
},
resolve: {
extensions: ['.ts', '.js', '.vue', '.json'],
alias: {
'vue': '@vue/runtime-dom'
}
},
plugins: [
new VueLoaderPlugin(),
new BundleTracker({
filename: './webpack-stats.json'
publicPath: 'http://0.0.0.0:8080/'
})
],
devServer: {
headers: {
"Access-Control-Allow-Origin":"\*"
},
public: 'http://0.0.0.0:8080',
inline: true,
hot: true,
stats: "minimal",
contentBase: __dirname,
overlay: true
}
};
}
we need to add a tsconfig.json file with the following rules in the frontend directory:
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"declaration": false,
"esModuleInterop": true,
"experimentalDecorators": true,
"module": "es2015",
"moduleResolution": "node",
"noImplicitAny": false,
"noLib": false,
"sourceMap": true,
"strict": true,
"strictPropertyInitialization": false,
"suppressImplicitAnyIndexErrors": true,
"target": "es2015",
"baseUrl": "."
},
"exclude": [
"./node_modules"
],
"include": [
"./src/**/*.ts",
"./src/**/*.vue"
]
}
Add the launch command to package.json
:
{
. . .
"scripts": {
"serve": "webpack-dev-server"
}
}
Create our vue 3 app:
~/venv-django/mysite/frontend mkdir src/ && cd src/
# Entry file
~/venv-django/mysite/frontend/src touch main.ts
#ts definitions for *.vue files
~/venv-django/mysite/frontend/src touch shims-vue.d.ts
# Default vue 3 component
~/venv-django/mysite/frontend/src touch App.vue
main.ts
:
// frontend/src/main.ts
import {createApp} from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
shims-vue.d.ts
to avoid error with *.vue files:
// frontend/src/shims-vue.d.ts
declare module "*.vue" {
import { defineComponent } from "vue";
const Component: ReturnType<typeof defineComponent>;
export default Component;
}
And finally our component App.vue
:
<!-- frontend/src/App.vue -->
<template>
<h2>This is a Vue 3 component!</h2>
<button @click="increase">Clicked {{ count }} times.</button>
</template>
<script lang="ts">
import {defineComponent, ref} from "vue";
export default defineComponent({
setup() {
const count = ref(0)
const increase = () => {
count.value++
}
return {
count,
increase,
}
}
});
</script>
Test the project
yarn serve
yarn run v1.22.4
$ webpack-dev-server
ℹ 「wds」: Project is running at http://0.0.0.0:8080/
ℹ 「wds」: webpack output is served from http://0.0.0.0:8080/
ℹ 「wds」: Content not from webpack is served from /home/julien/venv-django/mysite/frontend
ℹ 「wdm」: 44 modules
ℹ 「wdm」: Compiled successfully.
Hit CONTROL-C and Congratulation now you have frontend and backend !!!
But sorry, they are not link yet, let's do it:
~/venv-django/mysite/frontend/src cd ../../
# Install webpack loader
pip install django-webpack-loader==0.6.0
Let's configure Django by setting the frontend dir in settings.py
:
# mysite/mysite/settings.py
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# ADD THESE TWO LINES
TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')
FRONTEND_DIR = os.path.join(BASE_DIR, 'frontend')
. . .
Add webpack_loader
to your installed modules in settings.py
:
# mysite/mysite/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 TEMPLATES_DIR
to your templates' config in settings.py
:
# mysite/mysite/settings.py
. . .
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',
],
},
},
]
. . .
Add webpack-loader config at the end of the settings.py
:
# mysite/mysite/settings.py
. . .
WEBPACK_LOADER = {
'DEFAULT': {
'CACHE': DEBUG,
'BUNDLE_DIR_NAME': '/bundles/', # must end with slash
'STATS_FILE': os.path.join(FRONTEND_DIR, 'webpack-stats.json'),
}
}
Create templates' directory:
~/venv-django/mysite mkdir templates
~/venv-django/mysite touch templates/application.html
Create main template inside:
<!-- mysite/templates/application.html -->
{% 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 id="inspire"></app>
</div>
{% render_bundle 'main' %}
<!-- built files will be auto injected -->
</body>
</html>
And finally add the route in urls.py
# mysite/mysite/urls.py
from django.conf import settings
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path("",
TemplateView.as_view(template_name="application.html"),
name="app",
),
]
Now you can start the apps in two different tabs:
~/venv-django/mysite/frontend yarn serve
yarn run v1.22.4
$ webpack-dev-server
ℹ 「wds」: Project is running at http://0.0.0.0:8080/
ℹ 「wds」: webpack output is served from http://0.0.0.0:8080/
ℹ 「wds」: Content not from webpack is served from /home/julien/venv-django/mysite/frontend
ℹ 「wdm」: 44 modules
ℹ 「wdm」: Compiled successfully.
~/venv-django/mysite python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
May 09, 2020 - 14:48:49
Django version 3.0.6, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
navigate to http://127.0.0.1:8000/
Congratulation and enjoy !!!
Tips:
- You can stop the postgres server wit
pg_ctl stop
- Code of this tutorial: django-vue3-example
Top comments (0)