Search code examples
pythonpyqtpyqt5pyinstallerqwebengineview

How to add static(html, css, js, etc) files in pyinstaller to create standalone exe file?


I'm using QtWebEngineWidgets, QtWebChannel to create PyQt5 application, which uses HTML, CSS, JavaScript.

It's working fine, when we run in general way i.e., python main.py

Importing HTML as below,

current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "index.html")
url = QtCore.QUrl.fromLocalFile(filename)

Importing CSS, JavaScript files as below,

# in index.html
<link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="my_custom.js"></script>

Now, I'm trying to create a standalone .exe file using pyinstaller.

I have tried from here with no success.

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

Pyinstaller command:

pyinstaller --onefile --windowed main.py

I need to manually add static files at generated .exe file to work as expected. Which I want to include it in .exe file itself. How to get this?


Solution

  • From your question you can presume that the structure of your project is as follows:

    ├── index.html
    ├── jquery.js
    ├── main.py
    ├── my_custom.js
    └── styles.css
    

    For your case there are 2 options:

    1. using --add-data

      import os
      import sys
      
      from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
      
      
      def resource_path(relative_path):
          """ Get absolute path to resource, works for dev and for PyInstaller """
          try:
              # PyInstaller creates a temp folder and stores path in _MEIPASS
              base_path = sys._MEIPASS
          except Exception:
              base_path = os.path.abspath(".")
      
          return os.path.join(base_path, relative_path)
      
      
      if __name__ == "__main__":
          import sys
      
          app = QtWidgets.QApplication(sys.argv)
          view = QtWebEngineWidgets.QWebEngineView()
      
          filename = resource_path("index.html")
          url = QtCore.QUrl.fromLocalFile(filename)
      
          view.load(url)
          view.show()
          sys.exit(app.exec_())
      

      If you want to add external resources to the executable then you must use the "--add-data" option:

      pyinstaller --onefile --windowed --add-data="index.html:." --add-data="jquery.js:." --add-data="my_custom.js:." --add-data="styles.css:." main.py
      

      For windows change ":" with ";".

    2. using .qrc

      With this method you will convert the files (.html, .css, .js, etc) into .py code using pyrcc5 for this you must follow the following steps:

      2.1. Create a file called resource.qrc with the following content in the project folder:

      <RCC>
          <qresource prefix="/">
              <file>index.html</file>
              <file>jquery.js</file>
              <file>my_custom.js</file>
              <file>styles.css</file>
          </qresource>
      </RCC>
      

      2.2 Convert it to .py using pyrcc5:

      pyrcc5 resource.qrc -o resource_rc.py
      

      2.3 Import the resource_rc.py file and use the url with schema "qrc" in the main.py file:

      import os
      import sys
      
      from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
      
      import resource_rc
      
      
      if __name__ == "__main__":
          import sys
      
          app = QtWidgets.QApplication(sys.argv)
          view = QtWebEngineWidgets.QWebEngineView()
      
          url = QtCore.QUrl("qrc:/index.html")
      
          view.load(url)
          view.show()
          sys.exit(app.exec_())
      

      2.4 Compile the project using your initial command

      pyinstaller --onefile --windowed main.py