How to inject css from vue into a django template?
I have django as backend, vue as frontend - using boilerplate from https://github.com/ilikerobots/cookiecutter-vue-django
I want to integrate quasar for my frontend. This is my setup in main.js
:
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { Quasar } from 'quasar'
import App from './App.vue'
import 'quasar/dist/quasar.css'
import '@quasar/extras/material-icons/material-icons.css'
import '@quasar/extras/material-icons-outlined/material-icons-outlined.css'
import '@quasar/extras/material-icons-round/material-icons-round.css'
import '@quasar/extras/material-icons-sharp/material-icons-sharp.css'
import '@quasar/extras/material-symbols-outlined/material-symbols-outlined.css'
import '@quasar/extras/bootstrap-icons/bootstrap-icons.css'
const app = createApp(App)
app.use(createPinia()).use(Quasar, {
plugins: {}
})
app.mount('#app')
I am injecting this in my django template header.html
:
{% extends "base.html" %}
{% load vue_utils %}
{% block content %}
<div id="app"></div>
{% endblock %}
{% block inline_javascript %}
<script type="module" crossorigin src="{% vue_bundle_url 'main' %}"></script>
{% endblock inline_javascript %}
This is my vue component - App.vue
:
<template>
<q-layout view="hHh lpR fFf">
<q-header elevated class="bg-primary text-white" height-hint="98">
<q-toolbar>
<q-btn dense flat round icon="menu" @click="toggleLeftDrawer" />
<q-toolbar-title>
<q-avatar>
<img src="https://cdn.quasar.dev/logo-v2/svg/logo-mono-white.svg">
</q-avatar>
Title
</q-toolbar-title>
</q-toolbar>
<q-tabs align="left">
<q-route-tab to="/page1" label="Page One" />
<q-route-tab to="/page2" label="Page Two" />
<q-route-tab to="/page3" label="Page Three" />
</q-tabs>
</q-header>
<q-drawer show-if-above v-model="leftDrawerOpen" side="left" behavior="desktop" elevated>
<!-- drawer content -->
</q-drawer>
<q-page-container>
<router-view />
</q-page-container>
</q-layout>
</template>
<script>
import { ref } from 'vue'
console.log("HERE")
export default {
setup () {
const leftDrawerOpen = ref(false)
return {
leftDrawerOpen,
toggleLeftDrawer () {
leftDrawerOpen.value = !leftDrawerOpen.value
}
}
}
}
</script>
Looks when passed and rendered by django template:
Problem Summary: In development mode, the WOFF font files are not loading correctly. In production mode, the WOFF files load correctly when served from /static/vue/, but in development, the relative URLs in material-icons.css point to incorrect paths. You're using the base config in Vite to set /static/vue/ in production, but the same approach doesn’t work in development. Key Steps to Resolve the Issue Check Relative Paths in material-icons.css: The @font-face rule in material-icons.css uses relative paths to locate the font files:
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
font-display: block;
src: url('./web-font/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2') format('woff2'),
url('./web-font/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff') format('woff');
}
The ./web-font/ path is relative to the location of the material-icons.css file. This works in production because the fonts are served from a known location in /static/vue/, but it doesn't work in development when the assets are served by Vite from a different location.
Make Font Path Absolute in CSS: To solve this, you can change the relative paths to absolute paths. Instead of using ./web-font/, you should use a full path that is consistent in both development and production environments. For example, in your main.css or a specific CSS file that imports material-icons.css, you can use an absolute URL that works in both environments:
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
font-display: block;
src: url('/static/vue/web-font/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2') format('woff2'),
url('/static/vue/web-font/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff') format('woff');
}
This ensures that both in development (where Vite serves assets via http://127.0.0.1:5173) and production (where they are served via Django's /static/vue/ path), the URLs will be correct.
Vite Configuration for Asset Loading: In development mode, Vite might not resolve the font paths properly unless you specify the base URL explicitly for static assets like fonts. You can modify the vite.config.js to configure the base and handle static assets properly:
// vite.config.js
export default {
base: '/static/vue/', // This makes sure assets are served correctly in production
build: {
rollupOptions: {
input: {
main: resolve('./src/main.js'),
main_header: resolve('./src/main_header.js'),
reward: resolve('./src/reward.js'),
},
output: {
dir: '../my_project/static/vue/',
entryFileNames: '[name].js',
},
},
},
assetsInclude: ['**/*.woff', '**/*.woff2'], // Include font files for Vite
};
This ensures that Vite handles font files correctly and that the correct paths are generated.
Ensure Static Files are Copied to the Correct Location: Vite and Django need to share the same static folder structure. After building your Vue app, ensure the output from Vite is placed in the Django static directory, and that the fonts are in the right place under /static/vue/.
If needed, use a build script or a copy process to ensure that fonts are available in the Django static folder after running npm run build.
Test and Debug: Once you've made these changes, clear your browser cache to make sure the browser isn't loading old CSS or JS files. Also, check the browser's network tab to verify that the WOFF files are being requested from the correct URL in both development and production.
Conclusion: Update the font paths in material-icons.css to be absolute (/static/vue/web-font/), which will work across both development and production. Configure Vite to handle asset URLs by setting the base option and including font files in the build. Ensure fonts are copied to the correct location in your static folder during the build process. This should resolve the issues you're encountering with loading the WOFF files in both environments.