Code Monkey home page Code Monkey logo

django-vue-cli-webpack-demo's Introduction

Django + Vue CLI + Webpack demo

The purpose of this repository is to demonstrate a slightly more canonical (but lesser known) approach of including Webpack bundles from a Vue CLI project into Django templates without any additional plugins. Instead, it makes use of:

  • index.html generated by html-webpack-plugin (which is bundled with Vue CLI);
  • {% extends %} tag in Django templates.

All of the Vue.js / Vue CLI / Webpack goodies — such as the dev server, client-side routing, hot module replacement, code-splitting, filename hashes, prefetch tags — should work fine in this demo. In the dev mode, the bundles are served from memory, not the disk.

The approach has been popularized by @Ejez. You can read up on it here, here and here. The official Vue CLI documentation also gives a hint about it:

you should consider using the indexPath option to use the generated HTML as a view template in your server-side framework

Why not just use django-webpack-loader?

Another and more common approach (described here and here) makes use of django-webpack-loader, a Django extension which consumes output of webpack-bundle-tracker (Webpack plugin from the same author, @owais) and provides {% render_bundle %} template tag.

And it’s a fine approach! If it works well for you, there is no reason to switch. But it’s good to have options to choose from, right?

What’s inside the repository?

  • server/ — basic Django (3.0) project.
  • client/ — basic Vue CLI app generated by Vue CLI (4.3).

It’s a minimal working demo that you can easily run and play around with, NOT a starter project or boilerplate.

Additionally, there are VS Code tasks for running dev servers under .vscode/. If you don’t use VS Code, you don’t need this directory.

Running

  1. Clone the repo and cd into the directory.
  2. Install Django: pip install django
  3. Install Vue.js project dependencies: cd client && npm install
  4. Now you can:
    • run the Vue.js dev server: npm run serve
    • build for production: npm run build
  5. cd to the server/ directory and run Django dev server from it: python manage.py runserver
  6. Open http://127.0.0.1:8000/ in your browser.

How does this work, exactly?

A recommended way to get a quick grasp of how it all works:

  1. See the changes introduced in commit 7a3df2a. The changes are minimal.
  2. Read @Ejez's short explanation.
  3. Run the project (see instructions above).

But if you prefer reading a long text instead, have fun.

Let’s start from the official documentation for Vue CLI:

The file public/index.html is a template that will be processed with html-webpack-plugin. During build, asset links will be injected automatically. In addition, Vue CLI also automatically injects resource hints (preload/prefetch), manifest/icon links (when PWA plugin is used), and the asset links for the JavaScript and CSS files produced during the build.

In this demo, we modified the client/public/index.html template so that it is also a valid Django template that extends another Django template (server/templates/base.html). That’s right: client/public/index.html is a valid template for both Vue.js and Django, but Vue.js treats it like regular HTML, ignoring Django-specific tags, like {% extends %}.

During build, Webpack of the Vue CLI app injects all necessary asset links into the template and saves the resulting file as base-vue.html into the Django templates directory (server/templates/) — as prescribed by indexPath option in client/vue.config.js:

// outputDir resolves to server/static/dist
outputDir: '../server/static/dist',
// indexPath is relative to outputDir and resolves to server/templates/base-vue.html
indexPath: '../../templates/base-vue.html',

In Django’s server/urls.py we defined a TemplateView to serve server/templates/index.html — which is a template that extends base-vue.html. (Therefore, if you run the Django dev server before building the Vue CLI project, you will get a TemplateDoesNotExist error).

So the hierarchy of our Django templates can be depicted as:

base.html
└── base-vue.html <- generated by Webpack from client/public/index.html
    └── index.html <- served by Django at /

In base-vue.html we use the {{ block.super }} technique to preserve the contents of <head> and <body> tags from base.html. In a similar fashion you can customize the contents of these tags in children templates.

Worth noting that by default the Vue.js dev server does not write any files to the disk, instead it serves everything from memory. However, we need base-vue.html on the disk, because we configured Django to use it as a template. This can be easily achieved using the Webpack’s devServer.writeToDisk option. In client/vue.config.js we defined an arrow function for devServer.writeToDisk that tells Webpack to write only index.html and keep everything else in memory:

chainWebpack: (config) => {
  config.devServer.writeToDisk((filePath) => filePath.endsWith("index.html"));
};

Suggestions, questions?

Just open an issue. Please note that issues unrelated to the purpose of this repository will be marked as closed.

django-vue-cli-webpack-demo's People

Contributors

dependabot[bot] avatar eugenedae avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

django-vue-cli-webpack-demo's Issues

Not working as I expected..

I just setup this repo to give a try. But I'm not getting output as shown in screen shot. Im only getting text called powered by django. Do I'm missing something? And do I need to run both server, I mean vue dev server and django devserver?

Different locations for node_modules folder and vue.config.js.

This is working fine and also this is awesome. But I've a question, Actually I'm new to javascript and vuejs. But I'm enough familiar with django. Actually I only want to put public folder and src folder inside client. Except this i want to all types of files and folder outside from client. I didn't know how to achieve this one?

X-Content-Type-Options: nosniff

On local works fine:

Django version 3.2.4, using settings 'demo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[08/Oct/2021 10:02:32] "GET / HTTP/1.1" 200 1058
[08/Oct/2021 10:02:32] "GET /static/dist/css/app.f39fb7df.css HTTP/1.1" 200 428
[08/Oct/2021 10:02:32] "GET /static/dist/js/app.4e3ad5f1.js HTTP/1.1" 200 5880
[08/Oct/2021 10:02:32] "GET /static/dist/js/chunk-vendors.ee84eca6.js HTTP/1.1" 200 96992
[08/Oct/2021 10:02:32] "GET /static/dist/img/logo.82b9c7a5.png HTTP/1.1" 200 6849
[08/Oct/2021 10:02:32] "GET /static/dist/js/about.23893448.js HTTP/1.1" 200 455
[08/Oct/2021 10:02:34] "GET /static/dist/js/about.23893448.js HTTP/1.1" 200 455

On my hosting:

The resource from “https://vue.mihaicorciu.ro/static/dist/css/app.f39fb7df.css” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
The resource from “https://vue.mihaicorciu.ro/static/dist/js/chunk-vendors.ee84eca6.js” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
Loading failed for the <script> with source “https://vue.mihaicorciu.ro/static/dist/js/chunk-vendors.ee84eca6.js”.
The resource from “https://vue.mihaicorciu.ro/static/dist/js/app.4e3ad5f1.js” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
Loading failed for the <script> with source “https://vue.mihaicorciu.ro/static/dist/js/app.4e3ad5f1.js”.

Any suggestions to solve?
Thank you.

`Howto` for multilanguage sites?

Hi, thanks for awesome workflow example!
Buy I have one big problem.
My site is multilanguage.
In django templates I use {% trans 'some text' %} or {% blocktrans %}some text{% endblocktrans %}
This strings is collected somehow with django (I don't know how, because I only newbie at this project and I only frontender)
So, need to allow django to search through all vue files.
But my knowledge in Django is not enough.
What I was looking for and what might be useful:
Point:
https://stackoverflow.com/a/56843493
Examples:
https://tuleap.net/plugins/git/tuleap/tuleap/stable?a=commit&h=7cd307f038fdf1439418aa61793850e3655939c5
https://tuleap.net/plugins/git/tuleap/tuleap/stable?a=tree&hb=d9ec3ef12707285072386a68789069ed48a0e845&f=tools%2Futils%2Fscripts

https://tuleap.net/plugins/git/tuleap/tuleap/stable?a=blob&hb=d9ec3ef12707285072386a68789069ed48a0e845&h=12000a5f33fec8ff29944eb665e357d2c281f627&f=tools%2Futils%2Fgenerate-po.php

I would appreciate your help.
Thanks.

Use in Django Admin templates

templates/base.html

{% extends "admin/base_site.html" %}
...
<div id="content-main">
{% block content %}{% endblock %}
</div>
...

templates/index.html

{% extends "base-vue.html" %}

{% block content %}
    <div id="app"></div>
    {{ block.super }}
{% endblock content %}

public/index.html

{% extends "base.html" %}

{% block extrahead %}
  {{ block.super }}
  <%= htmlWebpackPlugin.files.css.map(src => `<link rel="stylesheet" type="text/css" href="${src}">`).join("\r\n ") %>
{% endblock %}

{% block content %}
  {{ block.super }}
  <%= htmlWebpackPlugin.files.js.map(src => `<script type="text/javascript" src="${src}"></script>`).join("\r\n ") %>
{% endblock %}

vue.config.js

chainWebpack: (config) => {
    ...
    config.plugin("html").tap((args) => {
      args[0].inject = false;
      return args;
    });
    ...
}

https://github.com/jantimon/html-webpack-plugin/tree/main/examples/custom-insertion-position
jantimon/html-webpack-plugin#1284

Are there any version dependencies?

Hi Eugene - great work, I really like the approach!

Is there any dependency on anything new? Or do you expect it to work on older versions of django and (especially) vue. There are other dependencies preventing me from using latest.

Easiest way to change config to make an MPA?

I'm trying to make an MPA as I only need to sprinkle Vue in a few places around my existing Django project.
A few interactive forms etc.

I have thought about using Vue within the browser but I'd really like to use .vue components.

Setting up vue to output multiple pages is very straight forward via the pages attribute in vue.config.js.

Any help with configuring this project into a Vue MPA?

Use with vite

Is it possible to use this with vite rather than webpack?

Django apps

This is a really great and simple approach.
Have you thought of how Django apps (and their templates) could be included in this way?
Would it be possible to have "plugin" apps which "inject" their own frontend parts vie templates into the main template?

Example with Docker?

This seems like such a neat solution to incorporating Vue.js into a django app. I'm wondering if you could show an example of how you'd incorporate this into a Docker based setup. I've got it working just fine for my dev image, but I'm having trouble understanding how to make it build the files for production so that they're actually served from the static directory instead of from the webpack dev-server.

My super basic Dockerfile for django is below:

# pull official base image
FROM python:3.8.3-alpine

# set work directory
WORKDIR /usr/src/app

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN apk update \
    && apk add postgresql-dev gcc python3-dev musl-dev

# install dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt

COPY ./entrypoint.sh .

# copy project
COPY . .

ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

Do I just add?

ENV NODE_ENV = 'production'
RUN cd frontend
RUN yarn build
RUN cd ..

NB: My frontend directory lives inside of the app/ directory so it gets copied over in the "copy project" step.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.