I spent a couple of hours setting up WebView2 debugging with VS Code on Windows, and I want to share my experience with you.
Documentation
The WebView2 VS Code debugging page have some outdated and missing information. I corrected it and sent a Pull Request to them. See the description of the PR about the changes.
WebView2 and source maps
WebView2 does not load separate JS, CSS or other source maps which are referenced by content files served through the WebResourceRequested
API. This WebResourceRequested
API is used by JUCE’s ResourceProvider
too. This is a known limitation,
which WebView2 maintainers seems to be not willing to fix. Edge (Chromium) uses a different internal mechanism to download source maps than to other resources. That is why, the ResourceProvider
is not called to serve any source map files. Instead, you can see the following message in the Debug Console:
Could not read source map for https://juce.backend/main.js: Unexpected 503 response from https://juce.backend/main.js.map: getaddrinfo ENOTFOUND juce.backend
VS Code provides several properties in launch.json
to configure locations of source maps (resolveSourceMapLocations
, sourceMapPathOverrides
, outFiles
), but in practice none of them worked for me. (any idea anyone???)
I created a PR to WebView2 documentation about this issue too.
Workarounds
- Use external web server: it is rather easy. Native integration (functions and events between JS and C++) works without ResourceProvider. So in debug mode, omit the
WebBrowserComponent::Options::withResourceProvider(…)
call and make the browser component load the URL of your local web server. This results in a very convenient development / debugging experience (e.g. hot-reload), but you will not debug the “real thing” served by your ResourceProvider
.
- Inline source maps: source maps can be embedded to JS, CSS etc. files. TypeScript offers the
”inlineSourceMap”: true
property in tsconfig.json
. Many build/packaging systems and web frameworks offer that functionility, but not all. Refer to the documentation of the packaging system or framework of your choice!
- Merge source maps on the fly: as a last resort, you can merge your separate source maps to the JS files in the
ResourceProvider
. Here you can find how to do that.
This may be necessary, if you use a web framework like Angular which does not support inline source map generation.
One-click C++ and JS debug
If you - like me - want to automate as many things as possible in your developer workflow, you might like this 
I put together a compound configuration in launch.json
, which starts the development web server, builds and launches the JUCE app, and then automatically attaches the msedge
debugger to the app process. This way both C++ and JS can be debugged with a single click.
The only trick here, is that the msedge
attach config shall wait until the app is built and started. That can be solved with a preLaunchTask
which runs a Powershell script. The script periodically checks if your app process started and exists once it find it.
launch.json
:
{
"version": "0.2.0",
"configurations": [
{
"name": "[Windows] Web Attach after Standalone startup",
"type": "msedge",
"port": 9222,
"request": "attach",
"webRoot": "${workspaceFolder}/your/web/folder",
"preLaunchTask": "[Windows] Wait for Standalone "
},
{
"name": "[Windows] Standalone with Web Serve",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceRoot}/path/to/your/built/standalone_executable.exe",
"preLaunchTask": "[Windows] CMake Build Debug + NPM Serve",
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"console": "integratedTerminal",
"environment": [
{
// Check this env var in your C++ code and use this URL instead of ResourceProvider
"name": "USE_WEBSERVER",
"value": "http://localhost:4200"
},
{
"name": "WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS",
"value": "--remote-debugging-port=9222"
}
]
}
],
"compounds": [
{
"name": "[Windows] Standalone with Web Serve + Web Attach",
"stopAll": true,
"configurations": [
"[Windows] Standalone with Web Serve",
"[Windows] Web Attach after Standalone startup"
]
}
]
}
tasks.json
:
{
"version": "2.0.0",
"tasks": [
{
"label": "[Windows] Wait for Standalone ",
"type": "shell",
"command": "${workspaceFolder}/scripts/ahp-wait-process.ps1",
"args": [
"standalone_executable*"
],
"group": "none",
},
{
"label": "[Windows] CMake Build Debug + NPM Serve",
"dependsOrder": "sequence",
"dependsOn": [
"[Windows] CMake Build Debug",
"NPM Serve",
]
},
{
"label": "NPM Serve",
// Start here your development web server
...
},
{
"label": "[Windows] CMake Build Debug",
// Build your JUCE app here
...
},
ahp-wait-process.ps1
:
param
(
[String]
[Parameter(Mandatory = $true)]
$Name
)
$existingCount = (Get-Process -Name $Name -ErrorAction SilentlyContinue).Count
Write-Host "Waiting for $Name" -NoNewline
while ($true)
{
$count = (Get-Process -Name $Name -ErrorAction SilentlyContinue).Count
if($count -gt $existingCount)
{
break
}
Write-Host '.' -NoNewline
Start-Sleep -Milliseconds 400
}
Write-Host "`n$Name" is running