Photo by Lachlan Donald on Unsplash

With each new upgrade of Apple's operating system, I like to use native apps as long as possible and now that I'm on Mojave, I am resisting a switch to Firefox or Chrome just to be able to use vue-devtools.

To answer the demand for these tools with Safari users, the Vue team built an Electron app that is browser independent.

To get it running is a bit clunky and involves making edits to your main HTML file that you probably shouldn't commit or at least remember to remove before going to production. Well, I'm lazy and I didn't want to have to toggle one line of code back and forth depending on what mode I was in.

I can leverage the fact that Django templates are rendered at the server after the request comes in and before the response is sent. In fact, the response is the HTML that results from the rendered template. With this knowledge I can build something that dynamically makes the decision during each request / response cycle, to render the script tag that DevTools needs.

Furthermore, I can make sure this evaluation is only done when developing locally by using the DEBUG variable in settings.py.

My solution? A context processor that is only installed if DEBUG is True:

# settings.py
if DEBUG:
    TEMPLATES[0]["OPTIONS"]["context_processors"].append("app.context_processors.vue_debug")

Then in the context processors, I'm looking to return a boolean value only if a socket connection can be made to the Electron app. I don't want to add the script tag and cause console errors due to loading failure, if the app isn't servicing that endpoint. So, let's do a little socket programming to detect an open port at the default port used by DevTools:

# context_processors.py
import socket

def vue_debug(request):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect(("0.0.0.0", 8098))
        debug = True
    except ConnectionRefusedError:
        debug = False
    sock.close()
    return {
        "VUE_DEBUG": debug
    }

Then we'll have a conditional include of the necessary script tag. Just put this somewhere in your <head> tag:

{% if VUE_DEBUG %}<script src="http://localhost:8098"></script>{% endif %}

Make sure you have vue-devtools installed as part of your devDependencies and add a quick script to save some typing:

// package.json -- whittled down for brevity

"scripts": {
  "start": "HOT_RELOAD=1 webpack-dev-server --mode development",
  "debug": "vue-devtools",
},
"devDependencies": {
  "@vue/devtools": "^4.1.5"
}

Now, you are ready to go. Open up three terminal tabs and run the following in each one:

  1. ./manage.py runserver
  2. npm start
  3. npm run debug

The first terminal will run the familiar Django dev server. The second will fire up webpack's dev server to build and serve your frontend code. The last will launch the vue-devtools Electron app and connect to your web application.

Check out my previous post to see how we get Django and Webpack playing well each other.