I'm trying to load an HTML page referencing local JS and CSS files into a Webview. Details below on the code I'm using to construct the URIs (the results don't look correct, but the code I believe matches other examples online). The Webview Developer Tools show 401 errors for the assets. How can I get these loaded?
I'm producing HTML with this in the <head>
. (I have both logged this HTML as well as viewed the source elements through the Webview Developer tools to verify.)
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; style-src 'self' https://*.vscode-cdn.net; script-src 'nonce-1CAM0Lr33whIXdLU4Rz5KKxJaq0hduY3'">
<link href="https://file%2B.vscode-resource.vscode-cdn.net/Users/phrogz/Code/visual-scxml-editor/resources/baseeditorstyles.css"
rel="stylesheet">
<script nonce="1CAM0Lr33whIXdLU4Rz5KKxJaq0hduY3" type='module'
src="https://file%2B.vscode-resource.vscode-cdn.net/Users/phrogz/Code/visual-scxml-editor/resources/editorglue.js"></script>
The URIs are being produced by this code:
private resourceURI(file: string) {
return vscode.Uri.joinPath(this.extensionURI, 'resources', file);
}
private webviewURI(file: string) {
return this.panel.webview.asWebviewUri(this.resourceURI(file)).toString();
}
// …
const editorCSSURI = this.webviewURI('baseeditorstyles.css');
… where extensionURI
is from context.extensionUri
with contents: {scheme: 'file', authority: '', path: '/Users/phrogz/Code/visual-scxml-editor', query: '', fragment: '', …}
. That path
is correct.
As best I can tell, that's the same effective code path as shown in this VS Code example for generating the webview URI.
The result, however, is that every CSS and JS asset shows net::ERR_ABORTED 401
in the Webview Developer Tools.
GET https://file+.vscode-resource.vscode-cdn.net/Users/phrogz/Code/visual-scxml-editor/resources/baseeditorstyles.css net::ERR_ABORTED 401
(anonymous) @ index.html?id=084ede1f-0484-44cf-8cd7-1b60312bd463&origin=cf31cd3f-41e9-41ea-861e-c867d65713ed&swVersion=4&extensionId=undefined_publisher.visual-scxml-editor&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app:973
setTimeout (async)
onFrameLoaded @ index.html?id=084ede1f-0484-44cf-8cd7-1b60312bd463&origin=cf31cd3f-41e9-41ea-861e-c867d65713ed&swVersion=4&extensionId=undefined_publisher.visual-scxml-editor&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app:971
(anonymous) @ index.html?id=084ede1f-0484-44cf-8cd7-1b60312bd463&origin=cf31cd3f-41e9-41ea-861e-c867d65713ed&swVersion=4&extensionId=undefined_publisher.visual-scxml-editor&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app:1002
Any thoughts as to what I'm doing wrong?
@Andrew below suggests that asWebviewUri()
should be returning a URI with a scheme of vscode-resource
. Modifying my webviewURI()
function to output debug information:
console.log({
file,
fileURI:this.resourceURI(file),
webURI:this.panel.webview.asWebviewUri(this.resourceURI(file))
})
…shows that it is in fact generating URIs with an https
schema and an authority of file+.vscode-resource.vscode-cdn.net
:
{file: 'neatxml.js', fileURI: f, webURI: f}
file: 'neatxml.js'
fileURI: f {scheme: 'file', authority: '', path: '/Users/phrogz/Code/visual-scxml-editor/resources/neatxml.js', query: '', fragment: '', …}
_formatted: null
_fsPath: null
authority: ''
fragment: ''
fsPath: ƒ fsPath(){return this._fsPath||(this._fsPath=b(this,!1)),this._fsPath}
path: '/Users/phrogz/Code/visual-scxml-editor/resources/neatxml.js'
query: ''
scheme: 'file'
webURI: f {scheme: 'https', authority: 'file+.vscode-resource.vscode-cdn.net', path: '/Users/phrogz/Code/visual-scxml-editor/resources/neatxml.js', query: '', fragment: '', …}
_formatted: null
_fsPath: null
authority: 'file+.vscode-resource.vscode-cdn.net'
fragment: ''
fsPath: ƒ fsPath(){return this._fsPath||(this._fsPath=b(this,!1)),this._fsPath}
path: '/Users/phrogz/Code/visual-scxml-editor/resources/neatxml.js'
query: ''
scheme: 'https'
While in the past it may have been that asWebviewUri()
generated URIs with a vscode-resource:
scheme, that is no longer true. The CORS policy generated by this.panel.webview.cspSource
is properly aligned with the URIs it generates to work.
What is missing is that when vscode.window.createWebviewPanel()
is called one must pass along localResourceRoots
listing the location(s) where files may be loaded from. For example:
const resourcesDir = vscode.Uri.joinPath(context.extensionUri, 'resources')const panel = vscode.window.createWebviewPanel(
'scxml', `SCXML ${path.basename(doc.fileName)}`,
vscode.ViewColumn.Beside,
{
enableScripts: true,
localResourceRoots: [resourcesDir]
}
);
I actually had both enableScripts
and localResourceRoots
set, but due to a copy/paste error I was setting the directory to 'media'
instead of my actual 'resources'
directory.