Reputation: 1247
In my Application I create a window with PyQt5 and load an HTML source. I want to use ThreeJS in my project which requires the use of JavaScript modules. However I do not seem to get modules working in my setup:
this works fine: <script src="js/main.js"></script>
this does not: <script type="module" src="js/main.js"></script>
What's the problem here? Do I need to do something additional in PyQt5 to enable JavaScript modules.
Without JavaScript modules it will be very hard to use ThreeJS, so how can I solve this issue?
EDIT: Here is the PyQt5 code that I'm using:
import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.browser = QWebEngineView()
config_name = 'data_files/init.html'
if getattr(sys, 'frozen', False):
application_path = os.path.dirname(sys.executable)
elif __file__:
application_path = os.path.dirname(__file__)
config_path = os.path.join(application_path, config_name)
self.browser.load(QUrl().fromLocalFile(config_path))
self.setCentralWidget(self.browser)
self.showMaximized()
app = QApplication(sys.argv)
QApplication.setApplicationName('v0.1')
window = MainWindow()
app.exec_()
This is the html:
<body>
<script src="js/main.js"></script>
<div id="myText" style="opacity:0">Hello World</div>
</body>¨
This is the javaScript:
window.addEventListener("load", () => {
document.getElementById("myText").style.opacity = "1"
})
The JavaScript only works when the script is not a Module, when using type="module"
nothing happens, the opacity of my element doesn't change.
Upvotes: 1
Views: 1862
Reputation: 243973
As the docs points out:
You need to pay attention to local testing — if you try to load the HTML file locally (i.e. with a file:// URL), you'll run into CORS errors due to JavaScript module security requirements. You need to do your testing through a server.
The modules are not accessible if you use local files, therefore you get the error message:
js: Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
In this case there are 2 options:
Implement a server, for example using aiohttp + qasync:
import asyncio
import functools
import os
from pathlib import Path
import sys
from aiohttp import web
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView
import qasync
from qasync import QApplication
application_path = (
Path(sys.executable).resolve().parent
if getattr(sys, "frozen", False)
else Path(__file__).resolve().parent
)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.browser = QWebEngineView()
config_name = "/data_files/init.html"
url = QUrl("http://localhost:4000")
url.setPath(config_name)
self.browser.load(url)
self.setCentralWidget(self.browser)
self.showMaximized()
async def main():
def close_future(future, loop):
loop.call_later(10, future.cancel)
future.cancel()
loop = asyncio.get_event_loop()
future = asyncio.Future()
qt_app = QApplication.instance()
if hasattr(qt_app, "aboutToQuit"):
getattr(qt_app, "aboutToQuit").connect(
functools.partial(close_future, future, loop)
)
app = web.Application()
app.router.add_static("/", application_path, show_index=True)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, "localhost", 4000)
await site.start()
view = MainWindow()
view.show()
await future
await runner.cleanup()
return True
if __name__ == "__main__":
try:
qasync.run(main())
except asyncio.exceptions.CancelledError:
sys.exit(0)
import sys
import os
from PyQt5.QtCore import QCoreApplication, QUrl, QFile, QFileInfo, QMimeDatabase
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineCore import (
QWebEngineUrlScheme,
QWebEngineUrlSchemeHandler,
QWebEngineUrlRequestJob,
)
from PyQt5.QtWebEngineWidgets import QWebEngineView
application_path = (
os.path.dirname(sys.executable)
if getattr(sys, "frozen", False)
else os.path.dirname(__file__)
)
class QtSchemeHandler(QWebEngineUrlSchemeHandler):
def requestStarted(self, job):
request_method = job.requestMethod()
if request_method != b"GET":
job.fail(QWebEngineUrlRequestJob.RequestDenied)
return
request_url = job.requestUrl()
request_path = request_url.path()
file = QFile(application_path + request_path)
file.setParent(job)
job.destroyed.connect(file.deleteLater)
if not file.exists() or file.size() == 0:
print(f"resource '{request_path}' not found or is empty")
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
return
file_info = QFileInfo(file)
mime_database = QMimeDatabase()
mime_type = mime_database.mimeTypeForFile(file_info)
job.reply(mime_type.name().encode(), file)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.browser = QWebEngineView()
self.scheme_handler = QtSchemeHandler()
self.browser.page().profile().installUrlSchemeHandler(
b"qt", self.scheme_handler
)
filename = "/data_files/init.html"
url = QUrl("qt://main")
url.setPath(filename)
self.browser.load(url)
self.setCentralWidget(self.browser)
if __name__ == "__main__":
scheme = QWebEngineUrlScheme(b"qt")
scheme.setFlags(QWebEngineUrlScheme.CorsEnabled)
QWebEngineUrlScheme.registerScheme(scheme)
app = QApplication(sys.argv)
QApplication.setApplicationName("v0.1")
window = MainWindow()
window.show()
app.exec_()
File structure:
├── data_files
│ ├── init.html
│ └── js
│ └── main.js
└── main.py
Upvotes: 3
Reputation: 215
If you add Dev Tools to your project, you can see JavaScript errors..
Also you can check this link for your problem.
Upvotes: 1