📝

翻訳: VS Code Web拡張機能

2022/01/22に公開

Web拡張機能

Visual Studio Codeはブラウザ上のエディタとして実行することができます。その一例であるgithub.devはGitHubでリポジトリやプルリクエストを閲覧している際に、.(ピリオドキー)を押すことで表示できるユーザーインターフェースです。VS CodeがWeb上で使われる場合、インストールされた拡張機能は「Web拡張機能ホスト」と呼ばれるブラウザ上の拡張機能ホストで実行されます。このWeb拡張機能ホストで実行される拡張機能が「Web拡張機能」と呼ばれます。

Web拡張機能は、通常の拡張機能と同じ構造を共有しますが、異なるランタイムで動作するため、Node.jsランタイム用に書かれた拡張機能と同じコードでは実行できません。Web拡張機能はVS Code APIへのフルアクセスは依然として持ちますが、Node.jsのAPIやモジュール読み込み機能へのアクセスすることはできません。それだけでなく、Web拡張機能はブラウザのサンドボックスによって保護されているため、通常の拡張機能と比べていくつかの制限があります。

Web拡張機能ランタイムは、デスクトップ版のVS Codeでもサポートされています。拡張機能をWeb拡張機能として開発した場合、その拡張機能はVS Code for Webvscode.devgithub.devが含まれます)でサポートされると同時に、デスクトップやGitHub Codespacesでもサポートされることになります。

Web拡張機能の構造

Web拡張機能は通常の拡張機能とほとんど同じ構造を持ちます。すなわちマニフェストファイル(package.json)が拡張機能のソースコードへのエントリーファイルを定義し、拡張機能のコントリビューションを宣言します。

ただし、Web拡張機能ではメインエントリーファイルがbrowserプロパティによって定義され、通常の拡張機能のようにmainプロパティでは定義されません。

contributesプロパティーはWeb拡張機能でも通常の拡張機能と同じように機能します。

次の例は、Web拡張機能ホストのみで動作する、シンプルなhello world拡張機能のpackage.jsonです(browserエントリーポイントだけがあります)。

{
  "name": "helloworld-web-sample",
  "displayName": "helloworld-web-sample",
  "description": "HelloWorld example for VS Code in the browser",
  "version": "0.0.1",
  "publisher": "vscode-samples",
  "repository": "https://github.com/microsoft/vscode-extension-samples/helloworld-web-sample",
  "engines": {
    "vscode": "^1.58.0"
  },
  "categories": ["Other"],
  "activationEvents": ["onCommand:helloworld-web-sample.helloWorld"],
  "browser": "./dist/web/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "helloworld-web-sample.helloWorld",
        "title": "Hello World"
      }
    ]
  },
  "scripts": {
    "vscode:prepublish": "npm run package-web",
    "compile-web": "webpack",
    "watch-web": "webpack --watch",
    "package-web": "webpack --mode production --devtool hidden-source-map",
  },
  "devDependencies": {
    "@types/vscode": "^1.59.0",
    "ts-loader": "^9.2.2",
    "webpack": "^5.38.1",
    "webpack-cli": "^4.7.0",
    "@types/webpack-env": "^1.16.0",
    "process": "^0.11.10"
  }
}

mainエントリーポイントしかなく、browserエントリーポイントのない拡張機能は、Web拡張機能ではありません。そのような拡張機能は、Web拡張機能ホストでは無視され、拡張機能ビューでダウンロードすることもできません。

拡張機能ビュー

コントリビューションを宣言するだけの拡張機能(contributesだけで、mainbrowserもない)はWeb拡張機能となることができます。そのような拡張機能は、一切変更を加えることなく、VS Code for the Webにインストールし実行することができます。そのような宣言的なコントリビューションを持つ拡張機能の例には、テーマ、文法、スニペットなどがあります。

拡張機能はbrowsermain両方のエントリーポイントを持つことで、ブラウザとNode両方のランタイムで実行できるようになります。既存の拡張機能をWeb拡張機能にアップデートするでは、拡張機能を両方のランタイムで動作するよう移行する方法を説明しています。

Web拡張機能の有効化ではWeb拡張機能ホストが拡張機能を読み込み可能かどうかを判断する際のルールが示されています。

Web拡張機能のメインファイル

Web拡張機能のメインファイルはbrowserプロパティによって定義されます。スクリプトはWeb拡張機能ホストにおいて、ブラウザWebWorker環境で実行されます。ブラウザワーカーのサンドボックスに保護されているため、Nodeランタイムで実行される通常の拡張機能と比べ次のような制限があります。

  • 他のモジュールのインポートやrequireはサポートされません。importScriptsも使用できません。そのため、コードは単一のファイルとしてパッケージされなければなりません。
  • VS Code APIはrequire('vscode')というパターンによって読み込むことができます。これが可能なのはrequireのシムが提供されているからですが、このシムは他の追加のファイルやモジュールを読み込むのには使えません。可能なのはrequire('vscode')のみです。
  • Node.jsのグローバルやライブラリ、すなわちprocessossetImmediatepathutilurlなどはランタイム上にはありません。ただし、webpackのようなツールによって追加することはできます。その方法はwebpackの設定で説明しています。
  • 開かれたワークスペースやフォルダーは仮想ファイルシステム上にあります。ワークスペースファイルへのアクセスは、vscode.workspace.fsからアクセス可能なVS CodeのファイルシステムAPIを通して行う必要があります。
  • 拡張機能コンテクストの場所(ExtensionContext.extensionUri)とストレージの場所(ExtensionContext.storageUriglobalStorageUri)もまた仮想ファイルシステム上にあり、vscode.workspace.fsからアクセスする必要があります。
  • Webリソースへのアクセスには、Fetch APIを用いなければなりません。アクセスされるリソースはオリジン間リソース共有(CORS)をサポートしている必要があります。
  • 子プロセスの作成や実行ファイルの実行はできません。ただし、Worker APIを通してのWebワーカーの作成は可能です。Webワーカーは、Web拡張機能における言語サーバープロトコルの記述にあるように、言語サーバーを実行するのに使うこともできます。
  • 拡張機能のactivate/deactivate関数は、通常の拡張機能と同じようにexports.activate = ...のパターンでエクスポートされる必要があります。

Web拡張機能を開発する

ありがたいことに、TypeScriptやwebpackのようなツールによってブラウザランタイムの制約の多くを隠蔽し、Web拡張機能を通常の拡張機能と同じように書くことができます。Web拡張機能と通常の拡張機能は多くの場合、同じソースコードから生成することが可能です。

たとえばyo codeジェネレーターによって作成されるHello Web Extensionはビルドスクリプトだけが異なります。生成した拡張機能は、与えられた起動構成を使うことで、従来のNode.js拡張機能と同じようにDebug: 選択してデバッグを開始コマンドから実行、デバッグすることができます。

Web拡張機能を作成する

新しい拡張機能の雛形を作成するには、yo codeを使ってNew Web Extensionを選びます。その際、最新バージョンのgenerator-code(>= generator-code@1.6)がインストールされていることを確認してください。ジェネレーターとyoをアップデートするには、npm i -g yo generator-codeを実行します。

作成された拡張機能は、拡張機能のソースコード(コマンドでhello worldを通知として表示します)、package.jsonマニフェストファイル、webpackの設定ファイルからなります。

  • src/web/extension.tsは拡張機能のエントリーソースコードファイルです。これは通常のhello拡張機能とまったく同じものです。
  • package.jsonは拡張機能マニフェストです。
    • browserプロパティを使ってエントリーファイルを指し示しています。
    • 次のスクリプトを提供します: compile-webwatch-webpackage-web(それぞれコンパイル、ウォッチ、パッケージするためのものです)
  • webpack.config.jsはwebpackの設定ファイルで、拡張機能のソースコードを一つのファイルへとコンパイル、バンドルします。
  • .vscode/launch.jsonには、VS CodeデスクトップをWeb拡張機能ホストとして、拡張機能やテストを実行する起動構成が含まれています(extensions.webWorkerの設定はもう必要ありません)。
  • .vscode/task.jsonには、起動構成で使われるビルドタスクが含まれています。ここではnpm run watch-webが使われており、webpackに特化したts-webpack-watchプロブレムマッチャーに依存しています。
  • .vscode/extensions.jsonはプロブレムマッチャーを提供する拡張機能が含まれています。これらの拡張機能は起動構成のためにインストールされている必要があります。
  • tsconfig.jsonには、webworkerランタイムに適したコンパイルオプションが定義されています。

helloworld-web-sampleのソースコードが、ジェネレーターにより作成されるものと似たものになっています。

webpackの設定

webpackの設定ファイルはyo codeによって自動的に生成されます。これによって、拡張機能のソースコードが一つのJavaScriptにバンドルされ、Web拡張機能ホストで読み込めるようになります。

webpack.config.js

const path = require('path');
const webpack = require('webpack');

/** @typedef {import('webpack').Configuration} WebpackConfig **/
/** @type WebpackConfig */
const webExtensionConfig = {
  mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
  target: 'webworker', // extensions run in a webworker context
  entry: {
    'extension': './src/web/extension.ts', // source of the web extension main file
    'test/suite/index': './src/web/test/suite/index.ts' // source of the web extension test runner
  },
  output: {
    filename: '[name].js',
    path: path.join(__dirname, './dist/web'),
    libraryTarget: 'commonjs',
    devtoolModuleFilenameTemplate: '../../[resource-path]'
  },
  resolve: {
    mainFields: ['browser', 'module', 'main'], // look for `browser` entry point in imported node modules
    extensions: ['.ts', '.js'], // support ts-files and js-files
    alias: {
      // provides alternate implementation for node module and source files
    },
    fallback: {
      // Webpack 5 no longer polyfills Node.js core modules automatically.
      // see https://webpack.js.org/configuration/resolve/#resolvefallback
      // for the list of Node.js core module polyfills.
      'assert': require.resolve('assert')
    }
  },
  module: {
    rules: [{
      test: /\.ts$/,
      exclude: /node_modules/,
      use: [{
          loader: 'ts-loader'
      }]
    }]
  },
  plugins: [
    new webpack.ProvidePlugin({
      process: 'process/browser', // provide a shim for the global `process` variable
    }),
  ],
  externals: {
    'vscode': 'commonjs vscode', // ignored because it doesn't exist
  },
  performance: {
    hints: false
  },
  devtool: 'nosources-source-map' // create a source map that points to the original source file
};
module.exports = [webExtensionConfig];

webpack.config.jsの重要なフィールドとしては、

  • entryフィールドは、拡張機能へのメインエントリーポイントとテストスイートを含んでいます。
    • 拡張機能のエントリーポイントを適切に指し示すよう、このパスの修正が必要なこともあります。
    • 既存の拡張機能の場合、このパスを現在のpackage.jsonmainプロパティで使っているファイルのパスにして始めることもできます。
    • テストをパッケージしない場合、テストスイートのフィールドは省いても構いません。
  • outputフィールドはコンパイルされたファイルが配置される場所を指し示します。
    • [name]entryで使われれているキーに置換されます。そのため生成された設定ファイルの場合、dist/web/extension.jsdist/web/test/suite/index.jsが生成されることになります。
  • targetフィールドには、コンパイルされたJavaScriptファイルが実行される環境のタイプを指定します。Web拡張機能の場合は、webworkerにします。
  • resolveフィールドでは、ブラウザでは動作しないNodeライブラリのためのエイリアスやフォールバックを追加することができます。
    • pathのようなライブラリを使っている場合、コンパイルされたWebのコンテクストでpathがどのように解決されるかを指定することができます。例えば、pathpath: path.resolve(__dirname, 'src/my-path-implementation-for-web.js')のように、プロジェクト内のファイルを指定して定義することが可能です。あるいは、BrowserifyによってパッケージングされたバージョンのNodeライブラリ、path-browserifyを使ってpath: require.resolve('path-browserify')と指定することもできます。
  • pluginsセクションでは、processのようなNode.jsのグローバルをポリフィルするためにDefinePluginプラグインが使われています。

Web拡張機能をテストする

現在、Web拡張機能をマーケットプレイスへの公開前にテストする方法として、次の3つの方法があります。

  • デスクトップのVS Codeを--extensionDevelopmentKind=webオプション付きで実行し、VS Codeで動作するWeb拡張機能ホストでWeb拡張機能を実行する。
  • @vscode/test-webNodeモジュールを使って、VS Code for the Webと拡張機能をローカルサーバーから提供し、ブラウザで開く。
  • 拡張機能をvscode.devサイドロードし、実際の環境で拡張機能を確認する。

Web拡張機能をデスクトップ版のVS Codeでテストする

既存のVS Code拡張機能の開発経験を流用する場合、通常のNode.js拡張機能ホストと同様、デスクトップで動作するVS CodeによるWeb拡張機能ホストの実行がサポートされています。

New Web Extensionジェネレーターが提供するpwa-extensionhost起動構成を使います。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Run Web Extension in VS Code",
      "type": "pwa-extensionHost",
      "debugWebWorkerHost": true,
      "request": "launch",
      "args": [
        "--extensionDevelopmentPath=${workspaceFolder}",
        "--extensionDevelopmentKind=web"
      ],
      "outFiles": [
        "${workspaceFolder}/dist/web/**/*.js"
      ],
      "preLaunchTask": "npm: watch-web"
    }
  ]
}

ここではnpm: watch-webタスクがnpm run watch-webを呼ぶことで拡張機能をコンパイルしています。このタスクはtasks.jsonにあることが想定されます。

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "watch-web",
      "group": "build",
      "isBackground": true,
      "problemMatcher": [
        "$ts-webpack-watch"
      ]
    }
  ]
}

$ts-webpack-watch はwebpackツールからの出力をパースすることができるプロブレムマッチャーです。このプロブレムマッチャーは、TypeScript + Webpack Problem Matchers拡張機能が提供しています。

この構成によって起動されるExtension Development Hostインスタンスでは、開発中のWeb拡張機能が利用可能となっており、それをWeb拡張機能ホストで実行するようになっているはずです。拡張機能をアクティブにするにはHello Worldコマンドを実行します。

実行中の拡張機能ビュー(コマンド: 開発者: 実行中の拡張機能の表示)を開くと、Web拡張機能ホストでどの拡張機能が実行中なのかを確認することができます。

Web拡張機能を@vscode/test-webを使ってブラウザでテストする

@vscode/test-webNodeモジュールはWeb拡張機能をブラウザでテストするためのCLIとAPIを提供します。

このNodeモジュールが提供するnpmバイナリのvscode-test-webを使うことで、VS Code for Webをコマンドラインから開けるようになります。

  • VS CodeのWeb部分を.vscode-test-webにダウンロードする。
  • localhost:3000でローカルサーバーを起動する。
  • ブラウザ(Chromium、Firefox、またはWebkit)を開く。

これをコマンドラインから実行できます。

npx @vscode/test-web --extensionDevelopmentPath=$extensionFolderPath $testDataPath

あるいは@vscode/test-webを開発依存パッケージに追加しておき、スクリプトから呼び出すほうがいいかもしれません。

  "devDependencies": {
    "@vscode/test-web": "*"
  },
  "scripts": {
    "open-in-browser": "vscode-test-web --extensionDevelopmentPath=. ."
  }

CLIのオプションについては@vscode/test-webのREADMEにより多く記載されています。

オプション 引数の説明
--browserType 起動するブラウザ: chromium(デフォルト)、firefoxwebkit
--extensionDevelopmentPath インクルードする開発中の拡張機能を指すパス。
--extensionTestsPath 実行するテストモジュールへのパス。
--permission 開かれるブラウザに与えられるパーミッション: clipboard-readclipboard-writeなど。
全オプションのリストを参照。引数は複数与えることができます。
--folder-uri VS Codeで開くワークスペースのURI。folderPathが与えられた場合は無視されます。
--extensionPath インクルードする他の拡張機能を含んだフォルダを指すパス。
引数は複数与えることができます。
folderPath VS Codeで開くローカルフォルダ。
フォルダの内容は、仮想ファイルシステムとして利用可能となり、ワークスペースとして開かれます。

VS CodeのWeb部分は.vscode-test-webフォルダにダウンロードされます。これは.gitignoreに追加しておくとよいでしょう。

Web拡張機能をvscode.devでテストする

拡張機能をVS Code for the Webですべての人が利用できるよう公開する前に、拡張機能が実際のvscode.devの環境でどのように動作するかを検証することが可能です。

拡張機能をvscode.devで確認するには、まずマシンから拡張機能をホストし、vscode.devがダウンロードして実行できるようにする必要があります。

まず拡張機能のパスからHTTPサーバーを起動するために、npx serve --cors -l 5000を実行します。

$ npx serve --cors -l 5000
npx: installed 78 in 2.196s

   ┌───────────────────────────────────────────────────┐
   │                                                   │
   │   Serving!                                        │
   │                                                   │
   │   - Local:            http://localhost:5000       │
   │   - On Your Network:  http://172.19.255.26:5000   │
   │                                                   │
   │   Copied local address to clipboard!              │
   │                                                   │
   └───────────────────────────────────────────────────┘

次に別のターミナルを開き、npx localtunnel -p 5000を実行します。

$ npx localtunnel -p 5000
npx: installed 22 in 1.048s
your url is: https://hungry-mole-48.loca.lt/

重要: このとき生成されたURL(この場合https://hungry-mole-48.loca.lt/)をクリックし、Click to Continue.を選択してください。

「Click to Continue」というテキストを持つクリックするようハイライトされたボタンを表すスクリーンショット

最後に、vscode.devを開き、コマンドパレット(Ctrl+Shift+P/⇧⌘P)から Developer: Install Web Extension... を実行します。そして上で示された生成されたURL、この例ではhttps://hungry-mole-48.loca.lt/、をペーストし、Installを選択します。

ログを確認する

拡張機能からのエラーやステータス、ログなどは、ブラウザの開発者ツールのコンソールのログから確認可能です。

コンソールにはvscode.dev自体からのログも表示されます。加えて、ブレークポイントの設定や拡張機能のソースコードの確認も簡単にはできません。これらの制約によってvscode.devでのデバッグは最適な体験とはなっていないため、vscode.devへサイドロードする前に、最初の二つの選択肢を使ってテストすることをお勧めします。サイドロードは拡張機能を公開する前の最終的な健全性チェックとして有効です。

Web拡張機能テスト

Web拡張機能テストも通常の拡張機能テストと同様にサポートされており、同じように実装することができます。拡張機能テストの基本的な構造を学ぶにはTesting Extensionsを参照してください。

@vscode/test-webNodeモジュールが、@vscode/test-electron(以前の名前はvscode-test)に対応します。このモジュールによって、Chromium、Firefox、およびSafariでの拡張機能テストを、コマンドラインから実行できるようになります。

このユーティリティは次のステップを行います。

  1. VS Code for the WebのエディターをローカルWebサーバーに起動します。
  2. 指定されたブラウザを開きます。
  3. 与えられたテストランナースクリプトを実行します。

テストを継続的ビルドで実行することで、拡張機能がすべてのブラウザで動作することを確認することもできます。

テストランナースクリプトはWeb拡張機能のメインファイルと同じ制限のもとWeb拡張機能ホストで実行されます。

  • すべてのファイルは単一のファイルにバンドルします。これはテストランナー(例えばMocha)と全てのテスト(典型的には*.test.ts)を含んでいる必要があります。
  • require('vscode')のみがサポートされます。

yo codeWeb拡張機能ジェネレーターによって作成されるwebpackの設定にはテスト用のセクションがあります。

この設定では、テストランナースクリプトが./src/web/test/suite/index.tsにあることが想定されています。ここで提供されているテストランナースクリプトではMochaのWebバージョンと、全てのテストファイルをインポートするためのwebpack特有の構文が使用されています。

require('mocha/mocha'); // import the mocha web build

export function run(): Promise<void> {

  return new Promise((c, e) => {
    mocha.setup({
      ui: 'tdd',
      reporter: undefined
    });

    // bundles all files in the current directory matching `*.test`
    const importAll = (r: __WebpackModuleApi.RequireContext) => r.keys().forEach(r);
    importAll(require.context('.', true, /\.test$/));

    try {
      // Run the mocha test
      mocha.run(failures => {
        if (failures > 0) {
          e(new Error(`${failures} tests failed.`));
        } else {
          c();
        }
      });
    } catch (err) {
      console.error(err);
      e(err);
    }
  });
}

Webテストをコマンドラインから実行するには、package.jsonに下記を追加し、npm testを実行します。

  "devDependencies": {
    "@vscode/test-web": "*"
  },
  "scripts": {
    "test": "vscode-test-web --extensionDevelopmentPath=. --extensionTestsPath=dist/web/test/suite/index.js"
  }

VS Codeをテストデータの入ったフォルダで実行するには、ローカルフォルダのパス(folderPath)を最後のパラメーターとして渡します。

拡張機能テストをVS Code(インサイダー)デスクトップで実行(デバッグ)するには、Extension Tests in VS Code起動構成を使用します。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Extension Tests in VS Code",
      "type": "extensionHost",
      "debugWebWorkerHost": true,
      "request": "launch",
      "args": [
        "--extensionDevelopmentPath=${workspaceFolder}",
        "--extensionDevelopmentKind=web",
        "--extensionTestsPath=${workspaceFolder}/dist/web/test/suite/index"
      ],
      "outFiles": [
        "${workspaceFolder}/dist/web/**/*.js"
      ],
      "preLaunchTask": "npm: watch-web"
    }
  ]
}

Web拡張機能を公開する

Web拡張機能はマーケットプレイスに他の拡張機能と一緒にホストされます。

拡張機能を公開する際は、必ず最新バージョンのvsceを使うようにしてください。vsceはすべてのWeb拡張機能をタグ付けします。そのときvsceが使用するルールはWeb拡張機能の有効化で示されています。

既存の拡張機能をWeb拡張機能にアップデートする

コードのない拡張機能

拡張機能がコードを持たず、コントリビューションポイントだけを持っている場合(テーマ、スニペット、言語の基本拡張機能など)は一切修正する必要がありません。そのままWeb拡張機能ホストで実行することができ、拡張機能ビューからインストールすることができます。

再公開は不要です。ただし、新しいバージョンの拡張機能を公開する際は、必ず最新バージョンのvsceを使用するようにしてください。

コードのある拡張機能を移行する

拡張機能にコードがある(mainプロパティによって定義されます)場合、Web拡張機能のメインファイルを提供し、package.jsonbrowserプロパティに指定する必要があります。

拡張機能のソースコードをブラウザ環境のために再コンパイルするには、次の手順を踏みます。

  • webpackの設定にあるように、webpackの設定ファイルを追加します。Node.js拡張機能のコード用に既にwebpackファイルが存在する場合、Web用のセクションを新たに追加することができます。例としてはvscode-css-formatterが参考になります。
  • Web拡張機能をテストするにあるように、launch.jsonファイルとtasks.jsonファイルを追加します。
  • webpackの設定ファイルに、既存のNode.jsメインファイルを入力ファイルとして指定するか、新しいメインファイルをWeb拡張機能のために作成します。
  • Web拡張機能の構造にあるように、package.jsonbrowserプロパティとscriptsプロパティを追加します。
  • npm run compile-web を実行してwebpackを呼び出し、拡張機能をWebで実行するのに作業が必要なところがないかを確かめます。

可能な限り多くのソースコードが再利用できるようにするためのテクニックには、次のようなものがあります。

  • resolve.fallbackにエントリーを追加し、Node.jsのコアモジュール、pathなどをポリフィルします。
  • DefinePluginプラグインを使って、Node.jsのグローバル、 processなどを提供します。
  • ブラウザとNode両方のランタイムで動作するNodeモジュールを使います。これを実現するために、Nodeモジュールはbrowsermain両方のエントリーポイントを定義します。そのようなNodeモジュールの例としてはrequest-lightvscode-nlsがあります。
  • NodeモジュールやNodeのソースファイルに代わりの実装を提供するには、resolve.aliasを使用します。
  • コードをブラウザ用の部分とNode.js用の部分、そして共通部分に分離します。共通部分にはブラウザとNode.js両方のランタイムで動作するコードを使用し、Node.jsとブラウザで異なる実装を持つ機能には抽象化をほどこします。
  • pathURI.filecontext.extensionPathrootPathuri.fsPathなどが使われているところを探します。これらはVS Code for the Webで使われている仮想ワークスペース(ファイルシステムではない)では動作しないので、代わりにURIをURI.parsecontext.extensionUriと使います。joinPathdirNamebaseNameextNameresolvePathvscode-uriNodeモジュールが提供しています。
  • fsが使われているところを探して、vscode.workspace.fsで置き換えます。

拡張機能がWebで動作するとき、機能を少なくしてもかまいません。その場合、Web上の仮想ワークスペースで、どのコマンド、ビュー、タスクを利用可能にするか、あるいは隠すかを、when節コンテクストを使ってコントロールすることができます。

  • virtualWorkspaceコンテクスト変数は、現在のワークスペースがファイルシステムではないワークスペースか調べるのに使えます。
  • resourceSchemeは、現在のリソースがファイルリソースかを確かめるのに使えます。
  • shellExecutionSupportedは、プラットフォームのシェルが存在するかに使用します。
  • コマンドがなぜ適用不可能かを説明するダイアログを表示する代わりのコマンドハンドラーを実装します。

WebWorkerはプロセスをフォークする代替手段として使うことができます。いくつかの言語サーバーはすでにWeb拡張機能として動作するようアップデートされており、その中にはビルトインのJSONCSSHTML の言語サーバーが含まれています。詳細は次のWeb拡張機能における言語サーバープロトコルを参照してください。

ブラウザランタイム環境がサポートするのは、JavaScriptとWebAssemblyの実行のみです。その他のプログラミング言語で書かれたライブラリはクロスコンパイルされる必要があり、たとえばC/C++RustからWebAssemblyにコンパイルするツールが存在しています。例としてvscode-anycode 拡張機能は、C/C++のコードからWebAssemblyにコンパイルされたtree-sitterを使っています。

Web拡張機能における言語サーバープロトコル

vscode-languageserver-nodeは、言語サーバープロトコル (Language Server Protocol、LSP)の一実装で、JSONCSSHTMLなどの言語サーバーを実装する基盤として用いられています。

3.16.0からは、クライアントとサーバーのブラウザ実装も追加で提供されています。サーバーはWebワーカーで実行可能で、それらはWebワーカーのpostMessageプロトコルに基づいてやりとりします。

ブラウザ用のクライアントはvscode-languageclient/browserにあります。

import { LanguageClient } from `vscode-languageclient/browser`

サーバーはvscode-languageserver/browserです。

これらがどのように動くかは、lsp-web-extension-sampleに示されています。

Web拡張機能の有効化

VS Codeは次の場合に、拡張機能を自動的にWeb拡張機能として扱います。

  • 拡張機能マニフェスト(package.json)がbrowserエントリーポイントを持つ。
  • 拡張機能マニフェストがmainエントリーポイントを持たず、かつ次のコントリビューションポイントを含まない: localizationsdebuggersterminaltypescriptServerPlugins

拡張機能でWeb拡張機能ホストでも動作するデバッガーやターミナルを提供したい場合、browserエントリーポイントが定義されている必要があります。

サンプル

Discussion