ilikerobots / cookiecutter-vue-django

Vue 3 + Vite + Django with no compromises. Use Vue SFCs directly in Django Templates, DRF not required.
BSD 3-Clause "New" or "Revised" License
208 stars 24 forks source link

How are you loading non CSS assets? #89

Closed dylanjcastillo closed 11 months ago

dylanjcastillo commented 11 months ago

I noticed that non-CSS assets in the frontend assets/ folder didn't load correctly.

To make it work I included those assets in the static folder in the backend application and used the inject approach as follows (for logo.svg):

Django template: home.html

{% extends "_base.html" %}
{% load vue_utils %}
{% load static %}
{% block title %}
    Home
{% endblock title %}
{% block content %}
    <div id="app"></div>
{% endblock content %}
{% block scripts %}
    <script type="module" crossorigin src="{% vue_bundle_url 'main' %}"></script>
    {% static 'logo.svg' as logoSvg %}
    {% vue_provide 'logoSvg' logoSvg %}
{% endblock scripts %}

Vue: app.vue

<script setup>
import { inject } from "vue";
import HelloWorld from "./components/HelloWorld.vue";
import TheWelcome from "./components/TheWelcome.vue";

const logoSvg = inject('logoSvg');
</script>

<template>
  <header>
    <img alt="Vue logo" class="logo" :src="logoSvg" width="125" height="125" />
    <div >
      <HelloWorld msg="HAHAHA" />
    </div>
  </header>

  <main>
    <TheWelcome />
  </main>
</template>

<style scoped>
</style>

But I was wondering if there's a better way to handle this. Are you following a similar approach or doing something else?

Again, thank you. I got burned using HTMX I was looking for a solution that provided a way to easily encapsulate the frontend in components and not have to use a REST backend service.

ilikerobots commented 11 months ago

That's one of the two best ways to do it, as far as I have discovered thus far. The other way is to use the "psuedoSlot" approach, where you would add a tag inside your template root element and then re-render it in your component. This depends on some code to attach these "pseudo-slots", which you can roll yourself or I've made it available as part of vue-plugin-django-utils

This would allow you to do something like:

{% extends "_base.html" %}
{% load vue_utils %}
{% load static %}
{% block title %}
    Home
{% endblock title %}
{% block content %}
    <div id="app"> 
        <img src="{% static 'logo.svg' %}"  
                 alt="Vue logo" class="logo" width="125" height="125" 
                 data-django-slot="logoSvg">
    </div>
{% endblock content %}
{% block scripts %}
    <script type="module" crossorigin src="{% vue_bundle_url 'main' %}"></script>
{% endblock scripts %}
<script setup>
import HelloWorld from "./components/HelloWorld.vue";
import TheWelcome from "./components/TheWelcome.vue";
</script>

<template>
  <header>
    <span v-html="$djangoSlots.logoSvg"></span>
    <div >
      <HelloWorld msg="HAHAHA" />
    </div>
  </header>

  <main>
    <TheWelcome />
  </main>
</template>

Thanks for the kind words!