OK I did come up with a solution for now, but don't know if it's the best one:
I just added a QMLUtil C++ class (derived from QObject) with a method Q_INVOKABLE QString readFile(const QString& path);. This just uses QFile::readAll() to read the file and return the contents as a QString.
I then passed an instance of this to QML engine in main() with:
QMLUtil qmlUtil;
QQmlApplicationEngine.rootContext()->setContextProperty("QMLUtil", &qmlUtil);
and can use it in my TextArea:
text: visible ? QMLUtil.readFile(":myapp/file.html") : ""
(Note need to use QFile's file path syntax with : prefix instead of qrc:/.)
Pretty simple (doesn't do much with errors, just throws an exception or returns empty string), and would probably have some issues if the file were very large, but seems to work for now. If there was a pure Javascript solution, that would be better for some of my other QML/JS-only projects however.
Let me know if you have other ideas on how to do this!
Thanks