网络扩展
Visual Studio Code 可以作为浏览器中的编辑器运行。一个示例是在 GitHub 中浏览存储库或 Pull 请求时github.dev
按(句点键)即可到达的用户界面。.
当 VS Code 在 Web 中使用时,安装的扩展将在浏览器中的扩展主机(称为“Web 扩展主机”)中运行。可以在 Web 扩展主机中运行的扩展称为“Web 扩展”。
Web 扩展与常规扩展共享相同的结构,但考虑到不同的运行时,不要使用与为 Node.js 运行时编写的扩展相同的代码来运行。Web 扩展仍然可以访问完整的 VS Code API,但不再可以访问 Node.js API 和模块加载。相反,Web 扩展受到浏览器沙箱的限制,因此与普通扩展相比具有局限性。
VS Code 桌面也支持 Web 扩展运行时。如果您决定将扩展创建为 Web 扩展,则VS Code for Web(包括vscode.dev
和github.dev
)以及桌面和GitHub Codespaces等服务将支持该扩展。
Web 扩展剖析
Web 扩展的结构与常规扩展类似。扩展清单 ( package.json
) 定义扩展源代码的入口文件并声明扩展贡献。
对于 Web 扩展,主条目文件由browser
属性定义,而不是main
像常规扩展那样由属性定义。
该contributes
属性对于 Web 扩展和常规扩展的工作方式相同。
下面的示例显示了package.json
一个简单的 hello world 扩展,该扩展仅在 Web 扩展主机中运行(它只有一个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.74.0"
},
"categories": ["Other"],
"activationEvents": [],
"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"
}
}
注意:如果您的扩展针对 1.74 之前的 VS Code 版本,则必须
onCommand:helloworld-web-sample.helloWorld
在activationEvents
.
只有main
入口点但没有入口点的扩展browser
不是 Web 扩展。它们会被 Web 扩展主机忽略,并且无法在扩展视图中下载。
仅具有声明性贡献(仅contributes
、无main
或browser
)的扩展可以是 Web 扩展。它们可以在VS Code for the Web中安装和运行,无需扩展作者进行任何修改。具有声明性贡献的扩展示例包括主题、语法和片段。
扩展可以同时具有browser
和main
入口点,以便在浏览器和 Node.js 运行时中运行。将现有扩展更新为 Web 扩展部分展示了如何迁移扩展以在两个运行时中工作。
Web扩展启用部分列出了用于决定扩展是否可以加载到 Web 扩展主机中的规则。
Web 扩展主文件
Web 扩展的主文件由属性定义browser
。该脚本在Browser WebWorker环境中的 Web 扩展主机中运行。它受到浏览器工作沙箱的限制,并且与 Node.js 运行时中运行的普通扩展相比具有局限性。
- 不支持导入或要求其他模块。
importScripts
也不可用。因此,代码必须打包到单个文件中。 - VS Code API可以通过模式加载
require('vscode')
。这将起作用,因为有一个垫片require
,但该垫片不能用于加载其他扩展文件或其他节点模块。它仅适用于require('vscode')
. - Node.js 全局变量和库(例如
process
、os
、setImmediate
、 、path
、util
)url
在运行时不可用。但是,可以使用 webpack 等工具添加它们。webpack配置部分解释了这是如何完成的。 - 打开的工作区或文件夹位于虚拟文件系统上。访问工作区文件需要通过 VS Code文件系统API,可访问
vscode.workspace.fs
. - 扩展上下文位置 (
ExtensionContext.extensionUri
) 和存储位置 (ExtensionContext.storageUri
,globalStorageUri
) 也在虚拟文件系统上,需要经过vscode.workspace.fs
。 - 要访问 Web 资源,必须使用Fetch API。访问的资源需要支持跨源资源共享(CORS)
- 无法创建子进程或运行可执行文件。但是,可以通过Worker API创建 Web Worker 。这用于运行语言服务器,如Web 扩展中的语言服务器协议部分中所述。
- 与常规扩展一样,扩展的
activate/deactivate
功能需要通过模式导出exports.activate = ...
。
开发网络扩展
值得庆幸的是,像 TypeScript 和 webpack 这样的工具可以隐藏许多浏览器运行时限制,并允许您像常规扩展一样编写 Web 扩展。Web 扩展和常规扩展通常可以从相同的源代码生成。
例如,生成器Hello Web Extension
创建的仅在构建脚本上有所不同。您可以像传统 Node.js 扩展一样运行和调试生成的扩展,方法是使用提供的启动配置(可使用“调试:选择并开始调试”命令访问)。yo code
创建网络扩展
要构建新的 Web 扩展,请使用yo code
并选择New Web Extension。确保安装了最新版本的生成器代码(>=生成器代码@1.6)。要更新生成器,请运行npm i -g yo generator-code
.
创建的扩展由扩展的源代码(显示 hello world 通知的命令)、清单package.json
文件和 webpack 配置文件组成。
src/web/extension.ts
是扩展的入口源代码文件。它与常规的 hello 扩展相同。package.json
是扩展清单。- 它指向使用
browser
属性的入口文件。 - 它提供了脚本:
compile-web
、watch-web
和package-web
来编译、监视和打包。
- 它指向使用
webpack.config.js
是 webpack 配置文件,它将扩展源编译并捆绑到单个文件中。.vscode/launch.json
包含运行 Web 扩展的启动配置以及使用 Web 扩展主机在 VS Code 桌面中进行的测试(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 扩展主机中。
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
字段包含扩展和测试套件的主要入口点。- 您可能需要调整此路径以适当地指向扩展的入口点。
- 对于现有扩展,您可以首先将此路径指向您当前正在使用
main
的package.json
. - 如果您不想打包测试,则可以省略测试套件字段。
- 该
output
字段指示编译文件的位置。[name]
将被替换为 中使用的密钥entry
。所以在生成的配置文件中,它会产生dist/web/extension.js
和dist/web/test/suite/index.js
。
- 该
target
字段指示编译后的 JavaScript 文件将运行的环境类型。对于网络扩展,您希望它是webworker
. - 该
resolve
字段包含为在浏览器中不起作用的节点库添加别名和后备的功能。- 如果您使用像 之类的库
path
,则可以指定如何path
在 Web 编译上下文中解析。例如,您可以指向项目中定义path
为path: path.resolve(__dirname, 'src/my-path-implementation-for-web.js')
.path-browserify
或者您可以使用名为并指定的Browserify 节点打包版本的库path: require.resolve('path-browserify')
。 - 有关 Node.js 核心模块 polyfill 的列表,请参阅webpackresolve.fallback 。
- 如果您使用像 之类的库
- 本
plugins
节使用DefinePlugin 插件来填充全局变量,例如process
Node.js 全局变量。
测试您的网络扩展
目前,在将 Web 扩展发布到 Marketplace 之前,可以通过三种方法对其进行测试。
- 使用在桌面上运行的 VS Code,并可选择
--extensionDevelopmentKind=web
在 VS Code 中运行的 Web 扩展主机中运行 Web 扩展。 - 使用@vscode/test-web节点模块打开包含 VS Code for the Web 的浏览器,其中包括从本地服务器提供的扩展。
- 将您的扩展旁加载到vscode.dev以在实际环境中查看您的扩展。
在桌面上运行的 VS Code 中测试您的 Web 扩展
为了使用现有的 VS Code 扩展开发体验,在桌面上运行的 VS Code 支持运行 Web 扩展主机以及常规 Node.js 扩展主机。
使用新 Web 扩展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扩展提供。
在启动的扩展开发主机实例中,Web 扩展将可用并在 Web 扩展主机中运行。运行Hello World
命令以激活扩展。
打开正在运行的扩展视图(命令:开发人员:显示正在运行的扩展)以查看哪些扩展正在 Web 扩展主机中运行。
使用 @vscode/test-web 在浏览器中测试您的 Web 扩展
@vscode/test-web节点模块提供了 CLI 和 API 来在浏览器中测试 Web 扩展。
Node 模块提供了一个 npm 二进制文件vscode-test-web
,可以从命令行打开 VS Code for the Web:
- 它将 VS Code 的网页下载到
.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=. ."
}
检查@vscode/test-web 自述文件以获取更多 CLI 选项:
选项 | 参数说明 |
---|---|
--browserType | 要启动的浏览器:(chromium 默认),firefox 或webkit |
--extensionDevelopmentPath | 指向要包含的正在开发的扩展的路径。 |
--extensionTestsPath | 要运行的测试模块的路径。 |
--permission | 授予打开的浏览器的权限:例如clipboard-read 、clipboard-write 。查看完整的选项列表。参数可以多次提供。 |
--folder-uri | 用于打开 VS Code 的工作区的 URI。folderPath 提供时被忽略 |
--extensionPath | 指向包含要包含的其他扩展的文件夹的路径。 参数可以多次提供。 |
folderPath | 用于打开 VS Code 的本地文件夹。 文件夹内容将作为虚拟文件系统提供并作为工作区打开。 |
VS Code 的 Web 部分被下载到一个文件夹中.vscode-test-web
。您想将其添加到您的.gitignore
文件中。
在 vscode.dev 中测试您的 Web 扩展
在发布扩展以供所有人在 VS Code 网页版 上使用之前,您可以验证扩展在实际vscode.dev环境中的行为方式。
要在 vscode.dev 上查看您的扩展,您首先需要从您的计算机托管它,以便 vscode.dev 下载并运行。
首先,您需要安装mkcert
.
然后,将localhost.pem
和localhost-key.pem
文件生成到不会丢失的位置(例如$HOME/certs
):
$ mkdir -p $HOME/certs
$ cd $HOME/certs
$ mkcert -install
$ mkcert localhost
然后,从扩展程序的路径中,通过运行以下命令启动 HTTP 服务器npx serve
:
$ npx serve --cors -l 5000 --ssl-cert $HOME/certs/localhost.pem --ssl-key $HOME/certs/localhost-key.pem
npx: installed 78 in 2.196s
┌────────────────────────────────────────────────────┐
│ │
│ Serving! │
│ │
│ - Local: https://localhost:5000 │
│ - On Your Network: https://172.19.255.26:5000 │
│ │
│ Copied local address to clipboard! │
│ │
└────────────────────────────────────────────────────┘
最后,打开vscode.dev ,从命令面板 ( ⇧⌘P (Windows, Linux Ctrl+Shift+P ) )运行Developer: Install Extension From Location... ,在示例中粘贴上面的 URL,然后选择Install。https://localhost:5000
检查日志
您可以在浏览器的开发人员工具控制台中检查日志,以查看扩展程序中的任何错误、状态和日志。
您可能会看到 vscode.dev 本身的其他日志。此外,您无法轻松设置断点,也无法查看扩展的源代码。这些限制使得在 vscode.dev 中进行调试并不是最愉快的体验,因此我们建议在侧载到 vscode.dev 之前使用前两个选项进行测试。在发布扩展之前,旁加载是一个很好的最终健全性检查。
网络扩展测试
支持 Web 扩展测试,并且可以像常规扩展测试一样实现。请参阅测试扩展文章以了解扩展测试的基本结构。
@vscode/test-web节点模块相当于@vscode/test- Electron(以前名为vscode-test
)。它允许您在 Chromium、Firefox 和 Safari 上从命令行运行扩展测试。
该实用程序执行以下步骤:
- 从本地 Web 服务器启动 Web 编辑器的 VS Code。
- 打开指定的浏览器。
- 运行提供的测试运行程序脚本。
您可以在连续构建中运行测试,以确保扩展程序适用于所有浏览器。
测试运行器脚本在 Web 扩展主机上运行,具有与Web 扩展主文件相同的限制:
- 所有文件都捆绑到一个文件中。它应该包含测试运行程序(例如,Mocha)和所有测试(通常
*.test.ts
)。 - 仅
require('vscode')
支持。
由 Web 扩展生成器创建的Webpack配置yo code
有一个用于测试的部分。它期望测试运行器脚本位于./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 (Insiders) 桌面中运行(和调试)扩展测试,请使用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 扩展与其他扩展一起托管在Marketplace上。
确保使用最新版本vsce
来发布您的扩展。vsce
标记所有属于 Web 扩展的扩展。为此,请使用Web 扩展启用vsce
部分中列出的规则。
将现有扩展更新为 Web 扩展
无代码扩展
没有代码、只有贡献点的扩展(例如主题、片段和基本语言扩展)不需要任何修改。它们可以在 Web 扩展主机中运行,并且可以从扩展视图安装。
不需要重新发布,但是在发布新版本的扩展时,请确保使用最新版本的vsce
.
使用代码迁移扩展
具有源代码(由main
属性定义)的扩展需要提供一个Web 扩展主文件并browser
在package.json
.
使用以下步骤为浏览器环境重新编译扩展代码:
- 添加 webpack 配置文件,如webpack 配置部分所示。如果您已经有 Node.js 扩展代码的 webpack 文件,则可以为 web 添加一个新部分。查看vscode-css-formatter作为示例。
- 添加
launch.json
和文件,如测试您的 Web 扩展tasks.json
部分所示。 - 在 webpack 配置文件中,将输入文件设置为现有的 Node.js 主文件或为 Web 扩展创建一个新的主文件。
- 在 中
package.json
,添加 abrowser
和属性,如Web 扩展剖析scripts
部分所示。 - 运行
npm run compile-web
以调用 webpack 并查看需要在哪里工作才能使您的扩展在网络中运行。
为了确保尽可能多的源代码可以被重用,这里有一些技巧:
- 要填充 Node.js 核心模块(例如 ) ,请向resolve.fallback
path
添加一个条目。 - 要提供 Node.js 全局,例如
process
使用DefinePlugin 插件。 - 使用可在浏览器和节点运行时运行的节点模块。节点模块可以通过定义
browser
和main
入口点来做到这一点。Webpack 将自动使用与其目标匹配的那个。执行此操作的节点模块的示例是request-light和vscode-nls。 - 要为节点模块或源文件提供替代实现,请使用resolve.alias。
- 将代码分为浏览器部分、Node.js 部分和公共部分。通常,仅使用可在浏览器和 Node.js 运行时运行的代码。为在 Node.js 和浏览器中具有不同实现的功能创建抽象。
- 注意
path
,URI.file
,context.extensionPath
,的用法rootPath
。uri.fsPath
。这些不适用于虚拟工作区(非文件系统),因为它们在 VS Code for the Web 中使用。而是使用带有URI.parse
,的 URIcontext.extensionUri
。vscode-uri节点模块提供joinPath
,dirName
,baseName
,extName
,resolvePath
。 - 留意 的用法
fs
。使用 vscode 替换workspace.fs
。
当您的扩展程序在网络中运行时,提供较少的功能是可以的。使用when 子句上下文来控制哪些命令、视图和任务在 Web 虚拟工作区中运行时可用或隐藏。
- 使用
virtualWorkspace
上下文变量来查明当前工作区是否是非文件系统工作区。 - 用于
resourceScheme
检查当前资源是否为file
资源。 shellExecutionSupported
如果存在平台 shell,则使用。- 实现替代命令处理程序,显示一个对话框来解释该命令不适用的原因。
WebWorkers 可以用作分叉流程的替代方案。我们更新了多种语言服务器以作为 Web 扩展运行,包括内置的JSON、CSS和HTML语言服务器。下面的语言服务器协议部分提供了更多详细信息。
浏览器运行环境仅支持 JavaScript 和WebAssembly的执行。用其他编程语言编写的库需要交叉编译,例如有工具将C/C++和Rust编译为 WebAssembly。例如, vscode-anycode 扩展使用tree - sitter,它是编译为 WebAssembly 的 C/C++ 代码。
Web 扩展中的语言服务器协议
vscode-languageserver-node是语言服务器协议(LSP)的实现,用作JSON、CSS和HTML等语言服务器实现的基础。
从3.16.0开始,客户端和服务器现在也提供了浏览器实现。服务器可以在 Web Worker 中运行,并且连接基于 WebWorkerspostMessage
协议。
浏览器的客户端可以在“vscode-languageclient/browser”中找到:
import { LanguageClient } from `vscode-languageclient/browser`;
服务器位于vscode-languageserver/browser
.
lsp -web-extension-sample展示了它是如何工作的。
Web 扩展启用
如果出现以下情况,VS Code 会自动将扩展视为 Web 扩展:
- 扩展清单 (
package.json
) 有browser
入口点。 - 扩展清单没有
main
入口点,也没有以下贡献点:localizations
,debuggers
,terminal
,typescriptServerPlugins
。
如果扩展想要提供也在 Web 扩展主机中工作的调试器或终端,则browser
需要定义一个入口点。