This article is for individuals who have had intermediate practice with the Vue.js and Django separately, but need direction on how to make these two frameworks work together. I will outline an example of how to set up some boilerplate code with a straightforward project structure using Django and Vue.js. Please note I am developing on macOS Catalina, so the shell commands will vary for your operating system. The finished product can be found on my github: https://github.com/jordanengstrom/blank_django_vue_project
At a high level we will be aiming for a project structure that looks something like this:
my_project/
|
|____ core/
| |____ __init__.py
| |____ views.py # class based TemplateView for index.html
|
|
|____ frontend/ # root frontend
| |____ src/ # vue components, router, store, etc.
| |____ node_modules/
| |____ vue.config.js # important file number 1
| |____ webpack-stats.json # important file number 2
|
|
|____ my_project/ # root backend
| |____ __init__.py
| |____ settings.py
| |____ urls.py
| |____ views.py
|
|
|____ templates/
| |____ index.html # django template that houses vue
|
|____ .gitignore
|____ venv/
|____ requirements.txt
|____ manage.py
|____ db.sqlite3
Enter fullscreen mode Exit fullscreen mode
We’ll start with the backend. Create an empty directory for your project, and then run:
$ django-admin startproject my_project && cd my_project
$ mkdir venv && python3 -m venv venv && source venv/bin/activate
$ (venv) pip install django djangorestframework
$ (venv) mkdir templates && cd templates && touch index.html
$ (venv) cd ..
$ (venv) mkdir core && touch __init__.py && touch views.py
Enter fullscreen mode Exit fullscreen mode
This is all we need to do with Django for now. We’ll come back to the templates/index.html and core/views.py files later. This next command assumes you’ve already installed vue globally. If you haven’t, simply run: npm install -g vue-cli
$ vue create frontend
Enter fullscreen mode Exit fullscreen mode
Then walk through the setup wizard so your presets look something like this (or customize your presets as you prefer):
$ Vue CLI v4.3.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Where do you prefer placing config for Babel, ESLint, etc.? In package.json
? Save this as a preset for future projects? (y/N) N
### installation magic happens...
Successfully created project frontend.
Get started with the following commands:
$ cd frontend
$ npm run serve
Enter fullscreen mode Exit fullscreen mode
Now we have separate frontend and backend environments! The frontend server will be at http://localhost:8080/ which will display the Vue landing page, and the backend will be at http://127.0.0.1:8000/ which will display the Django landing page. You can kick off the frontend per above commands and kick off the backend in the root directory with:
python manage.py runserver
Enter fullscreen mode Exit fullscreen mode
Now, these environments just need to be able to talk to each other. The two tools we will use to accomplish this are webpack-bundle-tracker on the Vue side and Django webpack loader on the backend.
$ cd frontend
$ npm install webpack-bundle-tracker@0.4.3
Enter fullscreen mode Exit fullscreen mode
We need version 0.4.3 of webpack-bundle-tracker because the files Django is expecting will not be automatically generated in the same way if we use the latest alpha version. Please note, 0.4.3 is the latest stable release as of April 2020. If we don’t specify this version, npm will pull down the latest alpha version which will not work the same. Next we need to create the vue.config.js file in the frontend directory:
$ touch vue.config.js
Enter fullscreen mode Exit fullscreen mode
and fill it with these contents:
const BundleTracker = require("webpack-bundle-tracker");
module.exports = {
// on Windows you might want to set publicPath: "http://127.0.0.1:8080/"
publicPath: "http://0.0.0.0:8080/",
outputDir: "./dist/",
chainWebpack: (config) => {
config
.plugin("BundleTracker")
.use(BundleTracker, [{ filename: "./webpack-stats.json" }]);
config.output.filename("bundle.js");
config.optimization.splitChunks(false);
config.resolve.alias.set("__STATIC__", "static");
config.devServer
// the first 3 lines of the following code have been added to the configuration
.public("http://127.0.0.1:8080")
.host("127.0.0.1")
.port(8080)
.hotOnly(true)
.watchOptions({ poll: 1000 })
.https(false)
.disableHostCheck(true)
.headers({ "Access-Control-Allow-Origin": ["*"] });
}
// uncomment before executing 'npm run build'
// css: {
// extract: {
// filename: 'bundle.css',
// chunkFilename: 'bundle.css',
// },
// }
};
Enter fullscreen mode Exit fullscreen mode
Comment out the base url settings that comes with Vue’s router. If you skip this, you’ll just end up having a path like this: http://127.0.0.1:8000/http:/0.0.0.0:8080/blah-blah-blah
to which I say – ew wtf?
Fix it by removing the base url config:
const router = new VueRouter({
mode: "history",
// base: process.env.BASE_URL,
routes
});
Enter fullscreen mode Exit fullscreen mode
Once you create this file, spin up the frontend development server, and a webpack-stats.json file will be generated
npm run serve
Enter fullscreen mode Exit fullscreen mode
Now navigate to the root directory and ensure your virtual environment is activated so we can install django-webpack-loader. Also, feel free to generate your requirements file:
$ (venv) pip install django-webpack-loader
$ pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode
Then, add webpack_loader to Django’s installed apps in settings.py, and add the following changes to the settings.py file:
INSTALLED_APPS = [
...
'rest_framework',
'webpack_loader',
]
.
.
.
TEMPLATES = [
{ ...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
},
]
.
.
.
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "assets"),
os.path.join(BASE_DIR, "frontend/dist"),
]
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'dist/',
'STATS_FILE': os.path.join(BASE_DIR, 'frontend', 'webpack-stats.json')
}
}
Enter fullscreen mode Exit fullscreen mode
Paste this into your templates/index.html file:
{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- This part is in the screenshot at the bottom! -->
<h1>Vue JS</h1>
<div id="app"></div>
{% render_bundle 'app' %}
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
Paste this into your core/views.py file:
from django.conf import settings
from django.views.generic.base import TemplateView
class IndexTemplateView(TemplateView):
def get_template_names(self):
template_name = "index.html"
return template_name
Enter fullscreen mode Exit fullscreen mode
Make sure these are reflected in your my_project/urls.py file:
from django.urls import re_path
from core.views import IndexTemplateView
urlpatterns = [
...
re_path(r"^.*$", IndexTemplateView.as_view(), name="entry-point"),
]
Enter fullscreen mode Exit fullscreen mode
Once these changes are made, spin up your npm server in one terminal tab, and then spin up your Django dev server in another terminal tab and you should be good to go! Happy coding
$ npm run serve
Enter fullscreen mode Exit fullscreen mode
$ (venv) python manage.py runserver
Enter fullscreen mode Exit fullscreen mode
暂无评论内容