javascriptjsonvisual-studio-codewebviewsecurity-policy

vscode webview - passing huge json data from webview to external js


I code vscode extension and I use webview for presenting text. The text is stored in json file - this is huge file, and there is a lot of text. Some words from that text need present popup window when mouse hover them on the webview. The words and popup information are stored in json. For example:

{
    wordA:{
        popupText: "text"
        //... and other properties
    },
    wordA:{
        popupText: "another text"
        //... and other properties
    }
    // .... and many many other data
}

I want to pass this json data from the webview to external js to be able to manage it. Due to security policy I cant just load json from javascript file - and I don't want to break the security policy.

HTML code for proper presenting the data is generated by other functions.

Files conneted to the problem:

I want pass data from webview.ts to myScript.js

///WebView.ts file
private _getHtmlForWebview(webview: vscode.Webview) {
    const scriptPathOnDisk = vscode.Uri.joinPath(this._extensionUri, 'myScript.js');
    const scriptUri = (scriptPathOnDisk).with({ 'scheme': 'vscode-resource' });
    const jsonPath = fs.readFileSync(path.join(__dirname, 'jsonFile.json'), 'utf8');
    const data = JSON.parse(jsonPath);
    return `<!DOCTYPE html>
        <html lang="en">
        <head>
            <some html stuff>...
            <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; img-src ${webview.cspSource} https:; script-src 'nonce-${nonce}';">
        </head>
        <body>
            <some html stuff which is generated automatically by other functions of the program>
            <for presenting text from json, put them into divs, spans and give them proper ids>
            <which will let the javascript manage those divs and spans>...
            <script nonce="${nonce}" src="${scriptUri}" type="text/javascript"></script>
        </body>
        </html>`;
} 

nonce is generated by function in the webview.ts

I tried by adding script tag before myScript is loaded into html

<script nonce="${nonce}" type="text/javascript">
    const jsonData = ${data};
</script>
<script nonce="${nonce}" src="${scriptUri}" type="text/javascript"></script>

but data is not reachable in myScript.

console.log(jsonData.wordA.popupText) show error, that jsonData doesn't exists in the scope

console.log(window.jsonData.wordA.popupText) shows undefined

I saw some solutions for React, Angular, Vue etc. but this is simple webview and I don't need any big framework here and from what i understand they will not work here.

I also saw something like acquireVsCodeApi() but I miss something and I don't have idea how set it in my case.


Solution

  • I resolved my specific situation. The point is about understand what i actually did by separating my files. ActivationFile has registered method for extension and passed reference to the function which is in the webview.ts file. In documentation there is no passing - all is done in one file - so in fact my name for 'webview.ts' is misleading because its still the extension, not the webview.

    in my webview.ts file I post message (in the same function where webview is created) currentPanel.webview.postMessage({command:"dajaJsonCommand", data:dataJson});

    In myScript.js I wrapped everything in DOMContentLoaded event and then follow documentation and set event listener for message from extension.:

    document.addEventListener('DOMContentLoaded', (function () {
    
    let dataVariable;
    window.addEventListener('message', event => {
        const message = event.data; // The JSON data our extension sent
        switch (message.command) {
            case 'dajaJsonCommand':
                dataVariable = message.data;
                break;
        }
    }); 
    

    And then json has been passed to the external script and could be reached by the program. End of the story. I hope its clear, if someone will need more details - let me know.