Skip to content

Instantly share code, notes, and snippets.

@lucianoratamero
Last active July 20, 2024 13:27
Show Gist options
  • Save lucianoratamero/7fc9737d24229ea9219f0987272896a2 to your computer and use it in GitHub Desktop.
Save lucianoratamero/7fc9737d24229ea9219f0987272896a2 to your computer and use it in GitHub Desktop.
Using Vite with Django, the simple way

Using Vite with Django, the simple way

Warning

I'm surely not maintaining this as well as I could. There are also other possible, better integrated solutions, like django-vite, so keep in mind this was supposed to be more of a note to myself than anything :]

This gist has most of the things I've used to develop the frontend using vite inside a monolithic django app.

Here's a boilerplate that uses this approach: https://github.com/labcodes/django-react-boilerplate

A couple of things to note:

  • it runs in SPA mode by default. If you want SSR, you may want to look into django_vite;
  • static files unrelated to your app, like images or fonts, should be served by django, instead of imported directly inside your frontend app;
  • you'll need to enable manifest in your vite configs for production;
  • I've only tested this with a React app, but I'll share my notes when testing with a Svelte app later.
    • I've already tested with svelte, and the changes are really small! For the most part, you'll only need to remove react-specific stuff (like react-refresh), use a svelte + vite app as base, and change base.html to import main.js instead of jsx. And I've created a sample template for it too!

Besides that, just read the comments carefully and everything should work out. Whenever I'm free, I'll make a video about this and add the URL here :]

I've published a video on how to do it, step-by-step: https://www.youtube.com/watch?v=FCyYIVfDkhY

{% load render_vite_bundle %}
<!DOCTYPE html>
<html lang="en">
<!--
For this base.html to work in dev and in production,
you'll need to set a couple of keys inside your settings.py.
Another file in this gist shows which ones you'll really need.
-->
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
{% if debug %}
<script type="module" src="http://localhost:3000/@vite/client"></script>
<!-- If you're using vite with React, this next script will be needed for HMR -->
<script type="module">
import RefreshRuntime from 'http://localhost:3000/@react-refresh'
if (RefreshRuntime) {
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => { }
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
}
</script>
{% endif %}
</head>
<body>
<div id="root"></div>
{% if debug %}
<!-- This url will be different for each type of app. Point it to your main js file. -->
<script type="module" src="http://localhost:3000/main.jsx"></script>
{% else %}
{% render_vite_bundle %}
{% endif %}
</body>
</html>
# This template tag is needed for production
# Add it to one of your django apps (/appdir/templatetags/render_vite_bundle.py, for example)
import os
import json
from django import template
from django.conf import settings
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def render_vite_bundle():
"""
Template tag to render a vite bundle.
Supposed to only be used in production.
For development, see other files.
"""
try:
fd = open(f"{settings.VITE_APP_DIR}/dist/manifest.json", "r")
manifest = json.load(fd)
except:
raise Exception(
f"Vite manifest file not found or invalid. Maybe your {settings.VITE_APP_DIR}/dist/manifest.json file is empty?"
)
imports_files = "".join(
[
f'<script type="module" src="/static/{manifest[file]["file"]}"></script>'
for file in manifest["index.html"]["imports"]
]
)
return mark_safe(
f"""<script type="module" src="/static/{manifest['index.html']['file']}"></script>
<link rel="stylesheet" type="text/css" href="/static/{manifest['index.html']['css'][0]}" />
{imports_files}"""
)
# These are the settings you should have for everything to work properly.
# Add these to your main settings.py file, or modify it accordingly.
# Needed for production. Avoid using '*'.
ALLOWED_HOSTS = ['your-production-domain.com']
# Needed for 'debug' to be available inside templates.
# https://docs.djangoproject.com/en/3.2/ref/templates/api/#django-template-context-processors-debug
INTERNAL_IPS = ['127.0.0.1']
# Vite App Dir: point it to the folder your vite app is in.
VITE_APP_DIR = BASE_DIR / "src"
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
# You may change these, but it's important that the dist folder is includedself.
# If it's not, collectstatic won't copy your bundle to production.
STATIC_URL = "/static/"
STATICFILES_DIRS = [
VITE_APP_DIR / "dist",
]
STATIC_ROOT = BASE_DIR / "staticfiles"
import { defineConfig } from "vite";
import reactRefresh from "@vitejs/plugin-react-refresh";
// https://vitejs.dev/config/
export default defineConfig({
build: { manifest: true },
base: process.env.mode === "production" ? "/static/" : "/",
root: "./src",
plugins: [reactRefresh()],
});
@pedrovgp
Copy link

Yeap, django-vite seems to do better what I did above :P. Thanks!

@mahfy3w
Copy link

mahfy3w commented Jul 29, 2023

Thanks for the great work! Sadly I had to encounter this error in the python server:

[HMR][Svelte] Unrecoverable HMR error in <App>: next update will trigger a full reload [proxy.js:15:11](http://localhost:5173/@fs/home/Mahfy3w/Documents/projects/DjangoSvelte/DjangoSvelte/node_modules/svelte-hmr/runtime/proxy.js?v=45928d43)
    logError http://localhost:5173/@fs/home/Mahfy3w/Documents/projects/DjangoSvelte/DjangoSvelte/node_modules/svelte-hmr/runtime/proxy.js?v=45928d43:15
    Proxy<App> http://localhost:5173/@fs/home/Mahfy3w/Documents/projects/DjangoSvelte/DjangoSvelte/node_modules/svelte-hmr/runtime/proxy.js?v=45928d43:380
    <anonymous> http://localhost:5173/main.js:4
Uncaught Error: 'target' is a required option
    SvelteComponentDev dev.js:329
    App App.svelte:186
    createProxiedComponent svelte-hooks.js:341
    ProxyComponent proxy.js:242
    Proxy<App> proxy.js:349
    <anonymous> main.js:4
[dev.js:329:9](http://localhost:5173/@fs/home/Mahfy3w/Documents/projects/DjangoSvelte/DjangoSvelte/node_modules/svelte/src/runtime/internal/dev.js)
    SvelteComponentDev dev.js:329
    App App.svelte:186
    createProxiedComponent svelte-hooks.js:341
    ProxyComponent proxy.js:242
    Proxy<App> proxy.js:349
    <anonymous> main.js:4

I was doing this with svelte, and I did all the instructions including removing the react specific code.
it doesn't show anything on the page. Can someone tell me what I did wrong?

@matheuszwilk
Copy link

Olá senhor Luciano, eu vi seu video hoje depois de 2 anos de gravação, gostaria de saber se sua solução para o usar o Vite + Django ainda esta funcional ou se tem uma forma mais atualizada, aguardo sua resposta e obrigado pelo tutorial..

@lucianoratamero
Copy link
Author

oi @matheuszwilk ! eu pessoalmente tenho usado mais o django-vite ultimamente, mas já vi projeto novo (inclusive projeto em que eu não estive involvido) usando uma variação desse código que tá aqui e no vídeo.

ou seja, essa abordagem tá bem desatualizada, mas parece ainda funcionar para grande parte dos casos, com algumas alterações a depender do projeto. te sugiro, no entanto, dar uma olhada no django-vite, por ele dar melhor flexibilidade, ou simplesmente usar um framework full stack que dê suporte nativo a ferramentas de front, como o svelte kit, nextjs ou até mesmo o laravel.

@Newton52owusu
Copy link

how will i work with already built templates. How should i connect it to be viewed by the backend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment