1. Create VueJS project

Install the Vue CLI if you don’t have it.

npm install -g @vue/cli

Create a Vue project inside the project directory.

vue create vue

Here, I chose VueJS 2 and named it “vue”.

Start the dev server.

cd vue
npm run serve

2. Create basic PyQt app

import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWebChannel import *


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

This will just show a blank window.

3. Load the VueJS app with QWebEngineView

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        view = self.view = QWebEngineView()
        self.view.setUrl(QUrl('http://localhost:8080'))
        self.setCentralWidget(self.view)

This assumes that the VueJS dev server is running locally on port 8080.

4. Show dev tools in separate dialog for debugging

dev_view = QWebEngineView()
self.view.page().setDevToolsPage(dev_view.page())
d = QDialog(self)
l = QVBoxLayout()
d.setLayout(l)
l.addWidget(dev_view)
d.show()

Alternatively, you can run the program with --enable-logging, then the messages from the VueJS app will show up in the console where you started the Python program from.

5. Communicate

Use QWebChannel to communicate between Python and JavaScript.

6. Build the VueJS app for distribution

Add a file named vue.config.js with the following content into the vue directory.

module.exports = {
  publicPath: './'
}

This ensures that the paths in the build output are relative.

Then build the app.

npm run build

Change the Python app to use the built version.

self.view.setUrl(QUrl.fromLocalFile(
    os.path.join(os.path.dirname(os.path.realpath(__file__)),
                 'vue/dist/index.html')))

Done.