1

I added Vue to my Django project, but since i didn't want to decouple frontend from backend, i decided to load webpack directly from Django. My setup seems to work with django webpack loader, but i'm having some doubts on how i structured the project.

Here is my folder:

my_site
   - django settings
my_app
   - views, urls, models, templates
vue_frontend 
   - webpack and vue stuff

My doubt is: should routing be handled by Django or should it be handled by Vue in a SPA?

Here is what i have now:

django_template2.html

{% extends 'header.html' %}
{% load render_bundle from webpack_loader %}
{% block content %}

<body>
    <div id="app">
        <firstVueComponent />
    </div>
</body>


{% render_bundle 'chunk-vendors' %}
{% render_bundle 'main' %}
{% endblock %}

django_template2.html

{% extends 'header.html' %}
{% load render_bundle from webpack_loader %}
{% block content %}

<body>
    <div id="app">
        <secondVueComponent />
    </div>
</body>


{% render_bundle 'chunk-vendors' %}
{% render_bundle 'main' %}
{% endblock %}

So Django handles the urls here:

from django.urls import path, include
from . import views

urlpatterns = [
    path('first_page/', views.first_page, name='first'),
    path('second_page/', views.second_page, name='second'),
]

So here i'm not using Vue to handle routes, but i load individual Vue components of the same app in those Django templates where i need them. My doubt: is it a bad practice? Are there reasons for which i should avoid doing so?

JayK23
  • 287
  • 1
  • 15
  • 49
  • Might be an XY problem. Why don't you want to decouple your front and back end? It's an industry standard to have those separated with a web API as an abstraction layer – Igonato Mar 11 '21 at 22:59
  • There are various reasons, such as that i don't want to use the benefits of rendering it from Django and all the security benefits of Django in general, also i'm more skilled with Django than i am with Vue, so i would not feel safe handling authentication from a separated frontend – JayK23 Mar 11 '21 at 23:02
  • I see. It's pretty hard to compromise the security from the front end alone though. All Vue, React and Angular protect you from XSS by default, you need to try really hard to shoot yourself in the foot to do so. And the authentication is handled by backend regardless of FE being tightly coupled. – Igonato Mar 11 '21 at 23:23
  • Yes, the main problem is that having the apps hosted on two different domains might make me lose a lot of django benefits in terms of security. I have some doubts on storing a jwt token on local storage, i don't think its the safest solution; there is session based auth but i don't know how would it work on two different domains. Another thing is the lack of examples on this, and finally the biggest problem is that i already setup the app on this environment, so moving to decoupled would be quite a pivot – JayK23 Mar 11 '21 at 23:46
  • Yea, separate domains suck, but you can use one domain with nginx proxy_pass or by the means of a CDN (CloudFront, Cloudflare, Fastly all can do it). For local development use dev-proxy. Funny thing I had the exact same discussion not so long ago, maybe I'll squeeze out a blog post on the weekend on how to set up Django + SPA on one domain it isn't that difficult really. Anyway, if your setup works for you, keep it up. To answer your original question routing should happen in the SPA, otherwise your SPA will not be an SPA. You will still need to return the index.html from the Django end though – Igonato Mar 12 '21 at 00:05
  • I would love to read a post about it, it's much needed, so please link it here if you do it! There is huge confusion on this matter, in particular on how to handle auth, that's why I wanted to keep the Django session auth. But I think can use the Django session auth from Django Rest Framework as long as the domain is the same, so I might give it a try. At first I wanted to add Vue only wherever I needed it, that's why I came up with the system I described in the question, but I keep having a lot of doubts on whether I should decouple or not – JayK23 Mar 12 '21 at 00:52

1 Answers1

1

My doubt is: should routing be handled by Django or should it be handled by Vue in a SPA?

Your FE needs to know the routes if you're going to do SPA, e.g. your FE needs to know how to update the URL if user clicks on a link/item. Otherwise there would be page refreshes or wrong URLs.

So here i'm not using Vue to handle routes, but i load individual Vue components of the same app in those Django templates where i need them. My doubt: is it a bad practice? Are there reasons for which i should avoid doing so?

I think you need to decide it you're going to build a SPA or not. My rule-of-thumb is SPA is better if have a lot of interactions on your page or you have a team of speciallized people for FE. Having a total separation between BE/FE is definitely industry de-facto standard but rendering most stuff on BE and having a lightweight FE is not a crime either, Stack overflow itself uses such approach.

If you're going with SPA, putting FE URLs in BE also makes not much sense (unless you're doing something like server side rendering). BE will provide a set of API URLs (invisible to end user) and FE will consume them and provide a set of FE URLs that users would see.

Yes, the main problem is that having the apps hosted on two different domains might make me lose a lot of django benefits in terms of security. I have some doubts on storing a jwt token on local storage, i don't think its the safest solution; there is session based auth but i don't know how would it work on two different domains. Another thing is the lack of examples on this, and finally the biggest problem is that i already setup the app on this environment, so moving to decoupled would be quite a pivot

There are multiple answers for your concern.

1- There's no need to have separated domain. You can prefix all your BE URLs with /api/ then on production you can use a reverse-proxy like NGINX or Traefik or your load balancer, ... to separate the two. Having separate domains is easier to maintain in long run but you'll need to handle cookie/CORS issues now and then.

2- If you have separated domains you can set cookies on the main domain from subdomain with this settings

3- There's no need to go with JWT token in localstorage. IMO it's inferior to having httponly cookies. Django session auth has httponly turned on by default. This way random npm libraries you installed or 3rd party scripts on your page has no way to access and steal the token.

4- On a separate note, Django CSRF protection is kinda obsolete now we have samesite cookie on browsers. Check browser support here. Newer versions of Django defaults to Lax that protects you from CSRF on supported browsers. So you can turn that protection off to have one less headache.

I personally think you can stick to Django session based auth, no need to add anything to your FE. FE will just call /api/auth/login and proper cookies will be set automatically.

To be more robust you can add an API like /api/auth/me that returns current logged in user data to FE. FE will call that when user visits your website for first time to understand if user is logged in or not.

Arman Ordookhani
  • 6,031
  • 28
  • 41
  • Thank you a lot. This was incredibly helpful. The big issue here that got me completely frozen is if I should use the BE to render the pages or go full SPA. My experience is using Django for everything, so rendering Vue components wherever I need them inside of my Django templates and using my urls.py was convenient, but I had some people telling me it's not a very good approach. The app I'm creating has high interactivity but i don't have two teams working on it. – JayK23 Mar 15 '21 at 17:51
  • I would like to go full SPA but the big problem is that Django/Python for everything is my field, I have way less experience with Vue/JS so building the authentication myself doesn't make me feel totally safe, and another problem is the lack of examples or sources about this approach, even though it looks like SPA is the approach everyone takes – JayK23 Mar 15 '21 at 17:53
  • You can still serve your JS files from BE for now. I prefer not to couple BE with routing and Vue components. i.e. every URL that doesn't start with /api/ will return an index.html that has the JS file inside. – Arman Ordookhani Mar 15 '21 at 18:36
  • Ok, but what if instead of using Django to handle urls i let Vue handles routes but the Vue app is still rendered by Django with webpack-loader? How would it be different from rendering the Vue app from Nginx as you mentioned? – JayK23 Mar 15 '21 at 18:38
  • I don't know the characteristics of that library. Usual practice is to render HTML files from Django and serve static/media files with another tool like NGINX. But all can be served from Django as well, some of your workers will be blocked serving files (that inefficient because they use a lot of ram compared to NGINX). – Arman Ordookhani Mar 16 '21 at 09:01
  • Yes, nginx should render it with webpack loader, since it's Django rendering webpack as static files. My doubt is if i should use Django urls or Vue routes, or if there is a way to use both together, like for authentication i use Django urls and for the rest i use vue routes – JayK23 Mar 16 '21 at 12:02
  • My suggestion is to use Vue routes. Django urls are for API URLs. e.g. You go to /login on your browser that's a Vue route, Vue calls /api/auth/login that's a Django URL. – Arman Ordookhani Mar 16 '21 at 15:55
  • This makes sense. The problem with that is building authentication, I have no idea how to do it since I have always used Django templates for it – JayK23 Mar 16 '21 at 16:38
  • Nothing special about that, you create an endpoint in BE for authenticate, in that you call Django authenticate function, passing request + username + password to it. Cookie will be a set automatically. FE just calls that endpoint in login page. – Arman Ordookhani Mar 16 '21 at 17:22
  • Thank you a lot! Please allow me just one last question. I was thinking of doing this: the login/register pages are rendered using Django templates, but the rest of the app is a SPA. So mysite.com/login would be a Django URL, but then after logging in everything is a SPA. So basically I'm mixing django URLs and Vue routes. Would it be possible to do this? That's because I already created the authentication part, so I would like to avoid re-making it. But if that's impossible, I'll redo everything from Vue – JayK23 Mar 16 '21 at 17:32
  • Sure it's possible to mix, cookies are shared. But people don't do it because it's confusing. – Arman Ordookhani Mar 17 '21 at 10:16
  • Thank you a lot. This was very helpful. Now i'm trying to find a way to use django-allauth from Vue, since i think i will decouple and have a frontend app and a backend app on the same domain and same folder but separated, so Vue will talk with Django using API endpoints – JayK23 Mar 17 '21 at 10:29