-
Notifications
You must be signed in to change notification settings - Fork 62
Description
The Problem
Hello, I have been using choc_WebView.h to embed a webview in a C++ audio plugin for a while. It's been working great, but we recently updated our choc submodule and now the constructor non deterministically fails to load the webview.
I've tracked down the issue to this commit: 442a8ed
Specifically, a newly introduced caching mechanism around line 1371:
if (auto userDataFolder = getUserDataFolder(); ! userDataFolder.empty()) { }
Behavior
When I load a fresh build of our plugin on windows, the webview always loads. After that, construction is a dice roll. Sometimes it works perfectly, and other times it never even hits our index.html
. Even when using theopts.webviewIsReady
it still does not help with the race condition. I confirmed that the race condition occurs in opts.webviewIsReady
. Whenever I add a debugger break point in the callback and I continue from the break point it, the webview always successfully loads.
So through some hunting I found the root of the above mentioned race condition comes from this newly introduced caching mechanism in 442a8ed. The cache is stored in the roaming folder of the host platform. For example, if I am loading our plugin in REAPER, the webview stores a cache at this path: C:\Users\yourusername\AppData\Roaming\reaper.exe\EBWebView\
.
If I delete the cache every time before reopening the UI, the webview successfully loads. THIS WAS THE AHA moment.
The Fix
-
The main problem seems to be the new
userDataFolder
option. Would it be possible to implement something in CHOC that exposes a flag to disallow the caching mechanism, aka make sureuserDataFolder
is alwaysNULL
? -
Or is there some cleaner mechanism to avoid a race condition when a cache exists? Is our own code logic wrong? Do we need a more defensive method for binding and navigating the webview?
Context
For context, here is how we construct the webview:
choc::ui::WebView::Options opts;
#if JUCE_DEBUG
opts.enableDebugMode = true;
#endif
#if !JUCE_DEBUG
opts.fetchResource = [=](const std::string& path) -> std::optional<choc::ui::WebView::Options::Resource>
{
...
};
#endif
opts.acceptsFirstMouseClick = true;
opts.enableDefaultClipboardKeyShortcutsInSafari = false;
opts.transparentBackground = true;
// THIS IS WHERE THE RACE CONDITION OCCURS
opts.webviewIsReady = [this](choc::ui::WebView& webView)
{
DBG("[WebViewEditor]: WebView ready, finish construction...");
#if JUCE_MAC
viewContainer.setView(webView.getViewHandle());
#elif JUCE_WINDOWS
viewContainer.setHWND(webView.getViewHandle());
#else
#error "Only support Mac and Windows here yet."
#endif
bind(); // code that calls choc::ui::WebView::bind
#if JUCE_DEBUG
webView.navigate("http://localhost:5173/");
#else
webView.navigate(PluginUtils::getIndexFilePath());
#endif
};
// Create the webview
webView = std::make_unique<choc::ui::WebView>(opts);
Conclusion
Thank you for your time! Let me know if you need information from me or if you can reproduce it.
-- Jack Kilgore (Lunacy Audio Dev)