The static in a URL is being duplicated when serving with Vite to Django backend
I'm trying to integrate vite with django using django-vite package. (no SPA, just htmx, alpine and bulma). Everything works fine in both dev mode and production mode (debug on, vite serves static files, debug off, vite builds them, django serves them). The only problem is that in dev mode, the static part of the url for static assets is duplicated like this:
<script type="module" src="http://localhost:5173/static/static/js/main.js"></script>
It's not causing any actual problems, but still i am concerned.
Here's vite.config.js:
import { defineConfig } from 'vite';
import { resolve } from 'path';
export default defineConfig({
base: "/static/",
build: {
emptyOutDir: false,
manifest: "manifest.json",
outDir: resolve(import.meta.dirname, "assets"), // -> MUST be included in STATICFILES_DIRS
// assetsDir: "static", // the folder name inside outDir
rolldownOptions: {
input: {
main: resolve(import.meta.dirname, "static/js/main.js"),
style: resolve(import.meta.dirname, "static/css/style.css"),
},
output: {
entryFileNames: `js/[name]-bundle.js`,
assetFileNames: `css/[name]-bundle.css`,
}
},
},
});
Django related settings:
STATIC_URL = 'static/'
# must equal to vite's build.outDir
STATICFILES_DIRS = [
BASE_DIR / "static"
]
DJANGO_VITE = {
"default": {
"dev_mode": True,
"manifest_path": BASE_DIR / "assets" / "manifest.json",
}
}
The first static comes from STATIC_URL/base; the second is part of the asset path. In dev mode, django-bite builds the URL as STATIC_URL + the path you pass to {% vite_asset %}, and that path is relative to Vite's root. You didn't set root, so it defaults to the project folder, and the path becomes static/js/main.js. Vite also serves that file at base + static/js/main.js, which is why nothing breaks.
To get /static/js/main.js, make the static folder Vite's root
export default defineConfig({
root: resolve(import.meta.dirname, "static"),
base: "/static/",
// rest unchanged
Then drop static/ from the paths in your templates
{% vite_asset 'js/main.js' %}
You input and outDir are absolute paths, so they don't change. The manifest keys becomes js/main.js and css/style.css, so the same paths work in production.