Driving Monaco from twinBASIC

A case study combining everything from the previous tutorials: a form with two WebView2 controls — the Microsoft Monaco editor on the left, a live HTML preview on the right. As the user types, Monaco posts the edited source to twinBASIC, which mirrors it into the preview pane.

The complete project ships as Sample 0 — WebView2 Examples in the New-Project dialog (form Example 3).

Architecture

The editor runs as a local web app under a virtual hostname; the preview pane is fed raw HTML through NavigateToString.

Setting up the editor’s assets

The Monaco editor ships as a ~2 MB collection of JavaScript, CSS, and font files. Drop them into a Resources sub-folder of your project — call it MONACO_DEMO — alongside an index.html and a small bootstrap script.js. The Hosting local web assets tutorial describes the layout.

The page itself is a single <div id='container'> plus the bootstrap script that listens for an initial-content message from the host:

<!DOCTYPE html>
<html>
    <head>
        <script src="/vs/loader.js"></script>
        <script src="/script.js"></script>
        <link rel="stylesheet" href="/styles.css">
    </head>
    <body>
        <div id="container"></div>
    </body>
</html>
window.chrome.webview.addEventListener('message', (event) => {
    let initialHTML = event.data;

    require.config({ paths: { 'vs': 'https://monaco.example/vs' } });
    require(["vs/editor/editor.main"], () => {
        let editor = monaco.editor.create(document.getElementById('container'), {
            value: initialHTML,
            language: 'html',
            theme: 'vs-dark',
            minimap: { enabled: false }
        });

        editor.onDidChangeModelContent(() => {
            // Inform the host of every edit.
            window.chrome.webview.postMessage(editor.getValue());
        });
    });
});

The BASIC side

Drop two WebView2 controls on a form — WebView (the editor) and WebViewPreview (the renderer). The Ready handler deploys the assets, registers the virtual host, and navigates:

Private localPath As String

Private Sub WebView_Ready() Handles WebView.Ready
    localPath = Environ$("USERPROFILE") & "\Documents\tbMonacoDemo"
    CopyResourcesFolderContentsToLocalPath "MONACO_DEMO", localPath

    WebView.SetVirtualHostNameToFolderMapping _
        "monaco.example", localPath & "\", wv2ResourceAllow
    WebView.Navigate "https://monaco.example/index.html"
End Sub

(CopyResourcesFolderContentsToLocalPath is the helper from Hosting local web assets.)

Pushing the initial content

Once Monaco has finished loading, the bootstrap script listens for a message event carrying the HTML to seed the editor with. Fire that message after the editor’s NavigationComplete:

Private Sub WebView_NavigationComplete( _
        ByVal IsSuccess As Boolean, ByVal WebErrorStatus As Long) _
        Handles WebView.NavigationComplete

    Dim initialHTML As String = _
        StrConv(LoadResData("initial-editor-html.html", "MONACO_DEMO"), vbFromUTF8)

    WebView.PostWebMessage(initialHTML)
    WebViewPreview.NavigateToString(initialHTML)
End Sub

LoadResData returns the resource bytes; StrConv(..., vbFromUTF8) decodes them. PostWebMessage hands the string to Monaco’s message listener; NavigateToString seeds the preview pane with the same text rendered as HTML.

Live preview

Every keystroke in Monaco fires its onDidChangeModelContent callback, which postMessages the new content back to BASIC. That arrives as the JsMessage event — feed it straight into the preview:

Private Sub WebView_JsMessage(ByVal Message As Variant) Handles WebView.JsMessage
    WebViewPreview.NavigateToString(Message)
End Sub

That’s it — the preview pane re-renders on every edit.

Detecting a missing Edge runtime

A reasonable fraction of users will run the application on a machine where the WebView2 Evergreen runtime isn’t installed. The Error event surfaces this case as Win32 error code &H80070002 (ERROR_FILE_NOT_FOUND):

Private Sub WebView_Error(ByVal code As Long, ByVal msg As String) _
        Handles WebView.Error
    Const ERROR_FILE_NOT_FOUND As Long = &H80070002
    If code = ERROR_FILE_NOT_FOUND Then
        MsgBox "Failed to initialize the WebView2 control." & vbCrLf & _
               "Please install the WebView2 (Evergreen) runtime.", _
               vbExclamation, "WebView2"
    Else
        MsgBox "WebView2 error " & Hex$(code) & ": " & msg, _
               vbExclamation, "WebView2"
    End If
End Sub

It is worth handling this even in single-WebView applications — the message you show here is the difference between “nothing happens” and “oh, I need to install something”.

Where next