DEV Community

foxgem
foxgem

Posted on

Simplifying VS Code Webview Development with vscode-page

With Webview, you can build a complex UI for users of your extension. And its development is not a hard work:

  1. Design html page
  2. Create a WebviewPanel
  3. Handle messaging between html and WebviewPanel

In Webview API Document, you can find all you want to kick off this job.

However, as doing that 3-step development cycle again and again, you may find there are some repetive tasks:

  • local resource root setting
    • Need to transform relative paths to "vscode-resource" scheme.
  • createOrShow logic
  • retainContextWhenHidden setting
  • the boilerplate code for messaging handling
    • In html page, adding an event listener to change partial content in the same page based on response from WebviewPanel.
    • In WebviewPanel, creating a message processor for all messages from html page.

Based on DRY, if we could abstract away all these tasks, we could spend more time writing business logic. That's why vscode-page comes.

What is vscode-page

vscode-page is a light-weight page micro framework for vscode webview, it could accelerate Vs Code Extension Webview development.

Its features:

  • abstract away communication between html page and WebviewPanel.
  • built-in template engine, with handlebars.js.
  • message mapping, a simple way to organize message handler and view.
  • baseUrl support, relative paths can be used in html page.

And here is its archtecture:

vscode-page architecture

Now, it is time to see how to use it to simplify our vscode Webview development.

How to use vscode-page

Let's create a "hello world" extension project to show its usage: this extension will load a html page by a command, at the same time a "hello world" will be passed from WebviewPannel to that html page which will show it.

First, create an extension project and install its dependencies:

yo code hello-page

...

cd hello-page
npm install --save vscode-page
npm install --save handlebars.js
Enter fullscreen mode Exit fullscreen mode

Then, replace all lines in extension.ts with the followings:

import * as vscode from "vscode";
import { createOrShowPage } from "vscode-page";

export function activate(context: vscode.ExtensionContext) {
  console.log('Congratulations, your extension "hello-page" is now active!');

  let disposable = vscode.commands.registerCommand(
    "extension.helloWorld",
    () => {
      createOrShowPage(
        "name", // name
        "ext.home", // viewType
        "Hello Page", // title
        "pages", // localResourceRoot
        "hello.html", // html
        context, // vscode.ExtensionContext
        [
          // Message Mappings
          {
            command: "ready", // command from js function in html
            // message handler
            handler: async () => {
              return {
                body: "hello world"
              };
            },
            // views changed by handler returning
            // [{element-id, handlebars-template}]
            templates: [{ id: "content", content: "{{body}}" }]
          }
        ]
      );
    }
  );

  context.subscriptions.push(disposable);
}

export function deactivate() {}
Enter fullscreen mode Exit fullscreen mode

Finally, create hello.html in pages directory which is at the same level as src directory. And its content:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <!-- MUST be added -->
    <base href="{{base}}" />
    <!-- MUST be added -->
    <script type="text/javascript">"{{init}}"</script>
    <title>Hello Page</title>
  </head>
  <body>
    <h1>vsode-page Hello World</h1>
    <!-- element id must be the same template id in MessageMapping -->
    <div id="content"></div>
    <script type="text/javascript">
      initEventListener(); // initialize
      const vscode = acquireVsCodeApi();
      vscode.postMessage({
        command: "ready" // command sent to MessageMappings
      });
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

That's it! Now, you can build and start this extension to check result.

Conclusion

With vscode-page, you don't bother repeating yourself, only focus on core business logics:

  • Message format between html page and WebviewPanel
  • Fine-graded handlers for each message
  • HTML page layout, js function and view templates

Although is a toy project shown in this post, you can find a more complex example in its repository. Also, you can find more details in README.

Top comments (0)