<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jessvin Thomas</title>
    <description>The latest articles on DEV Community by Jessvin Thomas (@karrade7).</description>
    <link>https://dev.to/karrade7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1410798%2F1619a9cd-7fb3-496f-964b-f824c567f57b.png</url>
      <title>DEV Community: Jessvin Thomas</title>
      <link>https://dev.to/karrade7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/karrade7"/>
    <language>en</language>
    <item>
      <title>VS Code Extensions: Basic Concepts &amp; Architecture</title>
      <dc:creator>Jessvin Thomas</dc:creator>
      <pubDate>Thu, 02 Jan 2025 07:56:44 +0000</pubDate>
      <link>https://dev.to/karrade7/vs-code-extensions-basic-concepts-architecture-b17</link>
      <guid>https://dev.to/karrade7/vs-code-extensions-basic-concepts-architecture-b17</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I wrote this article after writing my first VS Code Extension: &lt;a href="https://marketplace.visualstudio.com/items?itemName=blueshiftindustries.vscodeassistai" rel="noopener noreferrer"&gt;VS Code Assist AI&lt;/a&gt;, a utility extension to make it easier to work with chat interface AIs like ChatGPT or Claude. I primarily did this to learn how extensions worked. In retrospect, while there were a lot of guides and step by step tutorials, I wished I had found a general architectural overview first. This article intends to provide that overview. I cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What you can extend:&lt;/strong&gt; The customization possibilities that exist to add to VS Code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Core Building blocks:&lt;/strong&gt; the main methods for application logic and UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wiring together:&lt;/strong&gt; Connecting the building blocks together &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebView UI:&lt;/strong&gt; Some key points to implementing UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hello World Example:&lt;/strong&gt; Simple stripped down extension example&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What you can extend
&lt;/h2&gt;

&lt;p&gt;First it is key to understand what can be added. These are called contribution points. In particular I was early on confused by the names VS Code used for parts of its UI. What's the sidebar vs a panel? Below is a list of some example contributions and extension points. This list is not exhaustive but provides a good starting point for understanding how you can customize VS Code:&lt;/p&gt;

&lt;h3&gt;
  
  
  Contribution Points:
&lt;/h3&gt;

&lt;p&gt;UI Related:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Activity Bar&lt;/strong&gt;: Custom icons on the left side that execute commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary Sidebar&lt;/strong&gt;: UI elements that place next to activity bar (usually opened by activity bar)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secondary Sidebar&lt;/strong&gt;: UI elements that are places on the right side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Panel&lt;/strong&gt;: The area under the editor windows where terminal and similar items go&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status Bar&lt;/strong&gt;: Custom status messages and icons at the bottom of the app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Editor Views&lt;/strong&gt;: Add specialized editors for custom file types (e.g., JSON, YAML, or proprietary formats)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhwwjw4hvota81ewni8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhwwjw4hvota81ewni8p.png" alt="VS Code UI Elements" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Commands and Menus:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Menus&lt;/strong&gt;: Add new menu items in various contexts, such as Right-click menus for files or folders in the explorer or context menus in the editor for code blocks or selections. &lt;em&gt;Example:&lt;/em&gt; Adding “Refactor Function” or “Run Tests” to a file’s right-click menu.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands&lt;/strong&gt;: Extend the Command Palette to allow users to execute your custom commands. &lt;em&gt;Example:&lt;/em&gt; Adding “Generate Documentation” or “Open Debug Dashboard” commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;!&lt;a href="https://miro.medium.com/v2/resize:fit:1260/1*QZpo3j9v7a2In9yf74aIvA.png" rel="noopener noreferrer"&gt;https://miro.medium.com/v2/resize:fit:1260/1*QZpo3j9v7a2In9yf74aIvA.png&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example Command Pallete and Menu&lt;/p&gt;

&lt;h3&gt;
  
  
  Editor &amp;amp; Language Related
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language Features&lt;/strong&gt;: Add functionality like syntax highlighting, IntelliSense (code completions), or linting for a specific language. &lt;em&gt;Examples:&lt;/em&gt; Providing autocomplete for a custom domain-specific language (DSL)., Implementing a language server for real-time syntax analysis and hover tooltips.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Actions&lt;/strong&gt;: Offer fixes or refactoring options directly in the editor (e.g., quick fixes for errors or warnings). &lt;em&gt;Examples:&lt;/em&gt; “Convert to arrow function” for JavaScript. “Add missing imports” for Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inline Decorations&lt;/strong&gt;: Enhance the editor with visual elements like highlights, icons, or annotations. &lt;em&gt;Example:&lt;/em&gt; Highlighting TODO comments or displaying real-time test results inline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Support&lt;/strong&gt;: Add custom debug configurations, launch scripts, or integrate with external debugging tools. &lt;em&gt;Example:&lt;/em&gt; A debug adapter for your programming language or framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb41al0ttqvy7h9g9wsh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb41al0ttqvy7h9g9wsh.png" alt="Example Editor Integration" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Workspace and File Management:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;File Watchers&lt;/strong&gt;: Monitor file or folder changes in the workspace and trigger logic in response. &lt;em&gt;Example:&lt;/em&gt; Automatically lint files or rebuild assets when they are saved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace Configuration&lt;/strong&gt;: Provide workspace-specific settings and manage their persistence. &lt;em&gt;Example:&lt;/em&gt; Enabling or disabling a feature based on user-defined settings in .vscode/settings.json.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Building Blocks
&lt;/h2&gt;

&lt;p&gt;Extending these points consists of using a few key items:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manifest Registration&lt;/strong&gt; — tell VS Code what you want to extend&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Activation Events&lt;/strong&gt; — tell VS Code when your extensions should kick in&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS Code API&lt;/strong&gt; — core hooks to work with VS Code&lt;/p&gt;

&lt;h3&gt;
  
  
  Manifest registration
&lt;/h3&gt;

&lt;p&gt;Many of these contributions need to be listed in package.json for VSCode to allow them. Examples include commands, menus and UI elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"contributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"configuration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Extension Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"StringtoSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"important"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Something to save"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resource"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"views"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sidebar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Extension Sidebar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Main"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"commands"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Set a Value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Extension: Set Value"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"menus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"editor/context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Special Command in Menu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"when"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editorTextFocus &amp;amp;&amp;amp; editorHasSelection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9_cutcopypaste"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Activation Events
&lt;/h3&gt;

&lt;p&gt;When to kick of these commands. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;onCommand&lt;/strong&gt;: Activates the extension when a specific command is executed (e.g., &lt;code&gt;extension.helloWorld&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onLanguage&lt;/strong&gt;: Activates the extension when a file of a specific language is opened (e.g., &lt;code&gt;javascript&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onFileSystem&lt;/strong&gt;: Activates the extension when a specific file or folder is opened (e.g., &lt;code&gt;myCustomFileSystem&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  VS Code API
&lt;/h3&gt;

&lt;p&gt;If registered these items provide useful application logic generally by using the VS Code API. This API has hundreds of methods that can be used by extensions. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;vscode.workspace.workspaceFolders()&lt;/strong&gt;: Get the currently open workspace folders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.workspace.onDidSaveTextDocument():&lt;/strong&gt; React to file save events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.TextEditor.revealRange():&lt;/strong&gt; Scroll to and reveal a specific range in the editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.commands.registerCommand():&lt;/strong&gt; Create custom commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.window.setStatusBarMessage():&lt;/strong&gt; Add a status bar message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.workspace.onDidChangeTextDocument:&lt;/strong&gt; Detect changes in a document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.languages.registerCompletionItemProvider():&lt;/strong&gt; Add autocomplete suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.languages.registerDocumentFormattingEditProvider():&lt;/strong&gt; Add formatting rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.Terminal.sendText():&lt;/strong&gt; Send commands or text to the terminal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode.secrets.store():&lt;/strong&gt; Save sensitive data securely.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wiring together
&lt;/h2&gt;

&lt;p&gt;The general concept is that a registration (package.json) identifies → application location (entry point) which describes → activation events and what do with them which calls→ either backend functions (API) or frontend functions (UI).&lt;/p&gt;

&lt;p&gt;It may be best to think of it as a webservice with UI as frontend code and App Logic as backend code. Instead of http as the communication medium, VSCode uses an internal message bus. Here is a way to think about it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23h2x4108n212h6vzcp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23h2x4108n212h6vzcp0.png" alt="Backend/Frontend Architecture" width="666" height="784"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Webview UI
&lt;/h2&gt;

&lt;p&gt;When writing UI, there are some key concepts to consider: &lt;strong&gt;Webview, Sandboxing, Messages.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  WebView Type:
&lt;/h3&gt;

&lt;p&gt;The WebView type gives you complete flexibility to create any custom interface using HTML &amp;amp; JS. This is comparison to TreeView which is only design for hierarchy. The Webview page is stand alone and has no visibility to VS Code or backend imports with one exception — API bridge. It has a special function that can act as a bridge to the backend via messages. This function is acquireVsCodeApi which returns a set of functions to send messages and store state.&lt;/p&gt;

&lt;p&gt;As for the actual UI, the Webview runs within an IFrame so it can be as simple or complex as you want. You can view this by opening Developer Tools via command palette and checking elements. You will see where ever you loaded a WebView there is an IFrame. However, this means you cannot get any information unless requested from backend. You must get it via messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Messages
&lt;/h3&gt;

&lt;p&gt;Because the frontend is essentially totally isolated, any data needs to be requested from the backend and returned to the frontend as a message. You cannot just query the backend though. You listen to messages provided by VSCode API. An example is to even load data on start you may send a message with &lt;a href="http://vscode.post/" rel="noopener noreferrer"&gt;vscode.post&lt;/a&gt; to ask for initial starting data. The backend also registers a listener and when it hears the request it sends the response as a message. Frontend is then listening for messages and when it receives a message for example with all the initial data it can process it. The detail on messages is beyond this article but it’s a critical piece to UI Extensions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sandboxing
&lt;/h3&gt;

&lt;p&gt;For security reasons, each page is complete sandboxed and runs in a specific VS Code URL that is generate at run time. For this reason you can’t just point to imports. When a webview is loaded the actual root URL it is coming from is randomly generated so any not to allow seeing the file system of the extension host. In your HTML you can can import files in the same direcotry or subdirectory with relative links like ./ but you cannot go up a directory. You cannot access things like node_modules which is not a subdirectory of source. There are workarounds to this but it out of scope for this article. Just be away that the URL is random.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello World example
&lt;/h2&gt;

&lt;p&gt;See the example below where we:1&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;register a command&lt;/strong&gt; to open a panel in &lt;strong&gt;package.json&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;activate&lt;/strong&gt; the extension and register a command in &lt;strong&gt;extension.js&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send a message&lt;/strong&gt; to frontend in &lt;strong&gt;extension.js&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup message receiving&lt;/strong&gt; and logic in &lt;strong&gt;frontend.js&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Display the content&lt;/strong&gt; and &lt;strong&gt;send back a message&lt;/strong&gt; when complete in &lt;strong&gt;frontend.js&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Package.json (manifest):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello-world-webview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"displayName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World Webview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A simple VS Code extension to show Hello World in a Webview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.80.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"activationEvents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"onCommand:helloWorld.showWebview"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extension.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"commands"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"helloWorld.showWebview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Show Hello World Webview"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  extension.js (backend)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vscode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getWebviewContent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./frontend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * Activates the extension.
 *
 * This function registers a command, creates a Webview panel,
 * and sends/receives messages between the backend and frontend.
 *
 *@param {vscode.ExtensionContext} context - The extension context.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helloWorld.showWebview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Create the Webview panel&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;panel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createWebviewPanel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helloWorldWebview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ViewColumn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;One&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enableScripts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Allow scripts in Webview&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="c1"&gt;// Set the Webview's HTML content using the imported function&lt;/span&gt;
      &lt;span class="nx"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getWebviewContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extensionUri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// Send a message to the Webview&lt;/span&gt;
      &lt;span class="nx"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle messages from the Webview&lt;/span&gt;
      &lt;span class="nx"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDidReceiveMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Message from Webview:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deactivate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;deactivate&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  frontend.js (frontend):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Generates the HTML content for the Webview.
 *
 * @param {vscode.Webview} webview - The Webview instance.
 * @param {vscode.Uri} extensionUri - The URI of the extension.
 * @returns {string} The HTML content for the Webview.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getWebviewContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;extensionUri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;!DOCTYPE html&amp;gt;
    &amp;lt;html lang="en"&amp;gt;
    &amp;lt;head&amp;gt;
      &amp;lt;meta charset="UTF-8"&amp;gt;
      &amp;lt;title&amp;gt;Hello World Webview&amp;lt;/title&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
      &amp;lt;h1 id="message"&amp;gt;Waiting for message...&amp;lt;/h1&amp;gt;
      &amp;lt;script&amp;gt;
        // Access the VS Code API
        const vscode = acquireVsCodeApi();
        // Handle messages from the backend
        window.addEventListener('message', (event) =&amp;gt; {
          const message = event.data.text;
          document.getElementById('message').innerText = message;
          // Send a response back to the backend
          vscode.postMessage({ text: &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;received&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;` });
        });
      &amp;lt;/script&amp;gt;
    &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getWebviewContent&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I found the process of creating an extension rewarding in the end because I could publish it and see work out there. There were definitely some headaches especially around bundling and importing frontend libraries that I’ll save for another time.&lt;/p&gt;

&lt;p&gt;I hope you have found this article helpful on understanding the general architecture of VS Code Extensions.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
