DEV Community

Cover image for Building a VSCode Extension: Part Four
Corey O'Donnell
Corey O'Donnell

Posted on • Edited on • Originally published at codebycorey.com

Building a VSCode Extension: Part Four

One of the of most important things to make this extension function is to figure out the best way to have the React.js app communicate with the extension framework. After reading the docs and playing around, it was fairly simple using VS Codes message API.

Passing Messages with VS Code's API

VS Code offers a special API Object inside their webview by calling acquireVsCodeApi inside your JavaScript. The API object has a postMessage() function that can be used to send messages back to the extension's backend. You can subscribe to messages in the backend using the panel.webview.onDidReceiveMessage() function.

Example of sending a message when script is loaded in Webview App.tsx

// Add typedef for acquireVsCodeApi
declare const acquireVsCodeApi: Function;
// Fetch the api object
export const vscodeApi = acquireVsCodeApi();
vscodeApi.postMessage('React App Loaded')
Enter fullscreen mode Exit fullscreen mode

You can then verify your extension caught the message using:

panel.webview.onDidReceiveMessage((message) => console.log('MESSAGE', message))
Enter fullscreen mode Exit fullscreen mode

Now that we can send messages to the VS Code backend, we need to figure out how to send messages back to the webview and catch it. You can easily send a message using panel.webview.postMessage() function which is similar to how we sent the message from the webview. Instead of using the VSCodeAPI to catch the message in the webview, you actually add an event listener on the window object for message.

Sending the message from the VS Code backend after react app loads:

panel.webview.onDidReceiveMessage((message) => {
    if (message === 'React App Loaded') {
        panel.webview.postMessage('Extension Knows React is ready');
    }
})
Enter fullscreen mode Exit fullscreen mode

Webview listening for a message from the VS Code backend in App.tsx:

window.addEventListener('message', (message) => console.log('CAUGHT THE MESSAGE', message));
Enter fullscreen mode Exit fullscreen mode

You should now see a console.log() with the caught message.

Cleaning up the React Code

I decided to create a lib service that wraps the VS Code API. I can add more type checking to the API and simplify cleanup of eventListeners.

declare const acquireVsCodeApi: Function;

interface VSCodeApi {
    getState: () => any;
    setState: (newState: any) => any;
    postMessage: (message: any) => void;
}

class VSCodeWrapper {
    private readonly vscodeApi: VSCodeApi = acquireVsCodeApi();

    /**
     * Send message to the extension framework.
     * @param message
     */
    public postMessage(message: any): void {
        this.vscodeApi.postMessage(message);
    }

    /**
     * Add listener for messages from extension framework.
     * @param callback called when the extension sends a message
     * @returns function to clean up the message eventListener.
     */
    public onMessage(callback: (message: any) => void): () => void {
        window.addEventListener('message', callback);
        return () => window.removeEventListener('message', callback);
    }
}

// Singleton to prevent multiple fetches of VsCodeAPI.
export const VSCodeAPI: VSCodeWrapper = new VSCodeWrapper();
Enter fullscreen mode Exit fullscreen mode

I can now subscribe to messages using useEffect inside of my App.tsx:

import React, { useEffect } from 'react';
import './App.css';

import { VSCodeAPI } from './lib/VSCodeAPI';

export default function App() {
    useEffect(() => {
        return VSCodeAPI.onMessage((message) => console.log('app', message));
    });
    return (
        <h1>Hello World</h1>
    );
}
Enter fullscreen mode Exit fullscreen mode

Next Steps

Now that we can pass data between the view and the backend, we can start working on actual functionality. I need to look through the VS Code documentation on how to create a custom editor to generate and modify the todo.md file. I want to add Tailwind CSS to the front end for styles and create views for displaying and submitting todos.

Top comments (1)

Collapse
 
philip_zhang_854092d88473 profile image
Philip

I really appreciate your detailed posts! Since I started using EchoAPI in VS Code, it’s truly transformed my development process.