Eclipse Theia 示例插件(Sample Plugins)完全指南:编写、打包与在 Theia 中验证 VS Code 扩展
【免费下载链接】theiaEclipse Theia is a cloud & desktop IDE framework implemented in TypeScript.项目地址: https://gitcode.com/gh_mirrors/th/theia
sample-plugins/是 Eclipse Theia 仓库中一组最小化的 VS Code 扩展集合,用于在真实 Theia 例程应用(browser / electron 示例)中演练插件运行时(plugin runtime)。本文以 sample-plugins/README.md 为主干,结合每个插件的package.json与extension.js源码,完整讲解插件的目录结构、两种安装验证方式(复制到plugins目录 / 从 Extensions 视图安装.vsix)、以及各插件所演示的运行时变体(CJS、浏览器限定、ESM、headless、LM 工具等)。读完本文,你将能够独立编写一个最小 VS Code 插件、将其打包并在 Theia 中安装、激活与验证。
一、Sample Plugins 是什么
按仓库文档 sample-plugins/README.md 的说明:
A small collection of minimal VS Code extensions used by Theia to exercise the plugin runtime.
这是一批刻意保持最小的 VS Code 扩展,其唯一目的就是让 Theia 的插件运行时(plugin runtime)有"练习对象"。每个插件都位于sample-namespace/命名空间下,并注册一条简单的Hello from <plugin-name>命令;其中一部分插件还专门演示特定的运行时变体(browser-only、ESM 等)。
从目录布局看,sample-plugins/sample-namespace 下目前包含 7 个插件:
| 插件目录 | 演示重点 |
|---|---|
plugin-a | 最经典的 CommonJS 插件模板 |
plugin-b | 与 plugin-a 结构一致的第二个 CJS 插件 |
plugin-browser | 仅在浏览器端(browser worker)运行 |
plugin-esm | 以 ESM("type": "module")方式编写的插件 |
plugin-esm-mjs | 以.mjs扩展名导出的 ESM 插件 |
plugin-gotd | headless 插件(后端无 UI 运行),并使用@theia/api-provider-sample |
plugin-lm-tools | 通过vscode.lm.registerTool注册语言模型(LM)工具 |
二、最小的插件长什么样:以 plugin-a 为例
任何一个 "Hello" 插件都由两个文件构成核心逻辑:描述插件元数据的package.json,以及实现激活逻辑的extension.js。
2.1 package.json:清单文件
以 sample-plugins/sample-namespace/plugin-a/package.json 为例:
{ "private": true, "name": "plugin-a", "version": "1.75.0", "main": "extension.js", "license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0", "publisher": "sample-namespace", "engines": { "vscode": "^1.125.0" }, "activationEvents": [ "onCommand:plugin-a.hello" ], "scripts": { "build": "vsce package --no-dependencies" }, "contributes": { "commands": [ { "command": "plugin-a.hello", "title": "Hello from plugin-a" } ] } }几个关键字段的说明:
main:插件入口文件,Theia 插件宿主会加载该文件并调用其导出的activate;engines.vscode:声明兼容的 VS Code API 版本(此处为^1.125.0),Theia 的插件兼容层以此为基准;activationEvents:声明激活事件。这里使用onCommand:plugin-a.hello,意味着只有当用户真正执行plugin-a.hello命令时插件才会被激活,属于懒加载(lazy activation)模式;contributes.commands:把命令 ID 与命令面板中显示的中文/英文标题绑定起来,标题正是Hello from plugin-a;scripts.build:vsce package --no-dependencies,用于把插件目录打成.vsix安装包(--no-dependencies表示不打包 npm 依赖);publisher:sample-namespace,与目录名sample-namespace/保持一致,这也是.vsix发布者标识;private: true:避免该包被意外发布到 npm registry。
2.2 extension.js:激活逻辑
plugin-a/extension.js 的完整实现只有几行:
const vscode = require('vscode'); exports.activate = function (context) { context.subscriptions.push(vscode.commands.registerCommand('plugin-a.hello', () => { vscode.window.showInformationMessage('Hello from plugin-a!'); })); }这里遵循 VS Code 扩展的标准生命周期约定:
activate(context)在满足activationEvents条件时被调用;vscode.commands.registerCommand('plugin-a.hello', ...)注册命令回调;- 返回值通过
context.subscriptions.push(...)登记,插件被禁用/卸载时 Theia 会自动执行对应的dispose()释放资源。
plugin-b 与 plugin-a 结构完全一致,仅命令 ID、标题与提示消息替换为plugin-b.hello/Hello from plugin-b!,可作为同一目录下多个插件并存时互相印证的最小样例。
三、运行时变体:每个插件演示什么
除了最基础的 CJS 模板,sample 集合还覆盖了 Theia 插件运行时支持的多种形态。
3.1 浏览器限定插件:plugin-browser
plugin-browser/package.json 的关键在于它没有main字段,而是使用:
"browser": "./extension.js"plugin-browser/extension.js 在激活时打印日志:
exports.activate = function (context) { console.log('[plugin-browser] activated in browser worker!'); const disposable = vscode.commands.registerCommand('plugin-browser.hello', function () { vscode.window.showInformationMessage('Hello from a browser-only extension!'); }); context.subscriptions.push(disposable); };browser字段声明该插件的入口只面向浏览器环境运行,Theia 会在前端(browser worker)中执行它,同时导出的deactivate钩子也被显式声明(此处为空实现)。这类插件对应 Theia 文档中 "browser-only" 的插件形态,适合演示前端插件不需要 Node.js 能力即可工作的场景。
3.2 ESM 插件:plugin-esm 与 plugin-esm-mjs
plugin-esm通过"type": "module"把整个包声明为 ESM:
"type": "module", "main": "extension.js"其 extension.js 使用import/export语法:
import * as vscode from 'vscode'; export function activate(context) { context.subscriptions.push(vscode.commands.registerCommand('plugin-esm.hello', () => { vscode.window.showInformationMessage('Hello from plugin-esm (ESM)!'); })); }plugin-esm-mjs则直接以.mjs扩展名作为main入口:
"main": "extension.mjs"其 extension.mjs 采用命名导入的写法:
import { commands, window } from 'vscode'; export function activate(context) { context.subscriptions.push(commands.registerCommand('plugin-esm-mjs.hello', () => { window.showInformationMessage('Hello from plugin-esm-mjs (.mjs)!'); })); }从源码结构看,这两个插件用于验证 Theia 插件宿主对 ESM 入口(无论是包级type: module还是文件级.mjs)的加载支持。
3.3 headless 插件:plugin-gotd
plugin-gotd(GotD,Greetings of the Day)演示的是headless 插件——即在后端进程(无 UI 的 headless 环境)中运行、不依赖任何界面组件的插件形态。其 package.json 中值得关注的是:
"main": "extension", "activationEvents": ["*"], "theiaPlugin": { "headless": "headless" }, "headless": { "activationEvents": ["*"], "contributes": {} }"main": "extension":默认入口(后端/前端共用),对应的 extension.js 会读取vscode.version、vscode.env.shell,并通过vscode.extensions.getExtension('<unpublished>.plugin-gotd')查询自身extensionKind与安装路径,用于诊断插件运行环境;"theiaPlugin": { "headless": "headless" }:Theia 专有扩展点,声明 headless 入口指向headless(即headless.js);- headless.js 引用
@theia/api-provider-sample包:通过gotd.greeting.createGreeter()创建问候器,监听onGreetingKindsChanged,并依次把问候类型切换为DIRECT、QUIRKY、SNARKY,把问候语打印到日志中。
这个插件同时演示了两点:一是 Theia 对 headless 插件的支持(examples/api-provider-sample 提供了对应 API 的服务端实现);二是插件运行时对@theia/api-provider-sample这类"API 提供者"包的依赖能力。
3.4 LM 工具插件:plugin-lm-tools
plugin-lm-tools演示的是最新形态的Language Model Tools——通过 VS Code API 把函数暴露给 AI 语言模型调用。清单部分在 package.json 的contributes.languageModelTools中声明了三个工具:
sample-getCurrentTime:无参数,返回 ISO 格式的当前时间;sample-calculateSum:接收numbers数组,返回求和结果(inputSchema定义了{"type":"object","properties":{"numbers":{"type":"array","items":{"type":"number"}},"required":["numbers"]}});sample-getSystemInfo:无参数,返回平台、Node 版本与运行时长。
实现部分在 extension.js 中使用vscode.lm.registerTool(name, handler)注册,并通过context.subscriptions.push(...)登记生命周期:
const timeTool = vscode.lm.registerTool('sample-getCurrentTime', { invoke(_options, _token) { const now = new Date().toISOString(); return { content: [new vscode.LanguageModelTextPart(now)] }; }, prepareInvocation(_options, _token) { return { invocationMessage: 'Getting current time...' }; } });其中sample-calculateSum的invoke还会检查token.isCancellationRequested并逐个数字延迟 2 秒求和,用于演示长耗时工具的取消(cancellation)机制;sample-getSystemInfo则演示返回LanguageModelTextPart+LanguageModelDataPart.json的混合内容。
四、在 Theia 示例应用中测试示例插件
sample-plugins/README.md 给出了两种安装验证路径,下面逐一展开。
方法 A:把插件文件夹复制进已部署的 plugins 目录
这是最快、最直接的验证方式,不需要打包:
1.(可选)先下载 VS Code 内置扩展,让示例环境更完整:
npm run download:plugins该命令在根目录 package.json 中定义为theia download:plugins,由 dev-packages 下的 Theia CLI 实现。
- 把插件目录整体复制到部署好的
plugins目录下:
cp -r sample-plugins/sample-namespace/<plugin-name> plugins/其中<plugin-name>替换为目标插件名(如plugin-a、plugin-browser、plugin-lm-tools)。
plugins目录的位置由示例应用的配置决定:在 examples/browser/package.json 中可以看到"theiaPluginsDir": "../../plugins",即浏览器示例从仓库根目录的plugins/目录加载插件;electron 示例的配置与之类似。
- 启动示例应用,例如浏览器版:
npm run start:browser在 examples/browser 内部,start脚本实际执行的是theia start --plugins=local-dir:../../plugins --ovsx-router-config=../ovsx-router-config.json(见 examples/browser/package.json),即通过local-dir:前缀把../../plugins指定为本地插件目录。
- 打开命令面板(Ctrl+Shift+P / Cmd+Shift+P),运行
Hello from <plugin-name>。此时由于activationEvents中声明了onCommand:<id>,插件会在命令执行时被激活,右下角弹出Hello from <plugin-name>!通知即表示验证成功。
提示:此方式依赖
plugins目录已被示例应用加载。若在示例应用运行时新增插件目录,通常需要重启应用使其被扫描到。
方法 B:打包成 .vsix 并从 Extensions 视图安装
这种方式更接近真实用户安装插件的路径,适合验证打包产物:
- 在插件目录内执行打包:
cd sample-plugins/sample-namespace/<plugin-name> npm run build该脚本即vsce package --no-dependencies,会在插件源文件旁生成<plugin-name>-<version>.vsix(例如plugin-a-1.75.0.vsix)。--no-dependencies表示不把 npm 依赖打进去——由于这些示例插件都只依赖vscodeAPI(由 Theia 提供),因此无需打包依赖。
- 启动 Theia:
npm run start:browser打开 Extensions 视图(左侧扩展图标)。
点击 Extensions 视图右上角的
...菜单,选择Install from VSIX...,然后选中上一步生成的.vsix文件。打开命令面板,运行
Hello from <plugin-name>验证插件已生效。
两种方式如何选择
| 维度 | 方法 A(复制目录) | 方法 B(.vsix 安装) |
|---|---|---|
| 是否打包 | 否,直接拷贝源码目录 | 是,需先npm run build |
| 适用场景 | 开发迭代期快速验证 | 验证打包产物、模拟用户安装流程 |
| 产物 | plugins/下的插件目录 | <plugin-name>-<version>.vsix |
| 触发激活 | 命令面板执行命令 | 同上,但需先经 Extensions 视图安装 |
五、验证要点与常见排查思路
- 命令找不到:确认插件目录确实位于
plugins/下(或.vsix已成功安装),且contributes.commands中的commandID 与activationEvents中的onCommand:ID 完全一致(例如plugin-a.hello); - 激活未触发:检查
activationEvents。若使用onCommand:,必须真正执行该命令才会激活;plugin-gotd与plugin-lm-tools分别使用"*"与"onStartupFinished",属于启动即激活的不同策略; - 插件类型不符:browser-only 插件(
plugin-browser)应能在纯浏览器示例中运行;涉及 Node 能力的插件请确认运行环境满足要求; - headless 插件:
plugin-gotd的日志输出在后台进程,可从后端控制台查看[GOTD-BE]/[GOTD]前缀的日志(见 headless.js); - LM 工具:
plugin-lm-tools注册的三个工具需在具备 AI/LM 能力的 Theia 环境(如 ai-chat 相关扩展)中才会被调用,控制台会打印[plugin-lm-tools]前缀的调用日志。
六、总结
sample-plugins/为 Theia 插件开发者提供了一套"从零到验证"的最小闭环:每种插件形态(CJS、browser-only、ESM/.mjs、headless、LM tools)都配有可直接运行的package.json与extension.js,而 sample-plugins/README.md 给出的两种安装方式覆盖了开发调试(复制目录)与真实分发(.vsix+ Extensions 视图)两个阶段。以此为基础,你可以把任意一个 sample 插件复制出来改名改造,快速搭建属于自己的 Theia 插件原型。
【免费下载链接】theiaEclipse Theia is a cloud & desktop IDE framework implemented in TypeScript.项目地址: https://gitcode.com/gh_mirrors/th/theia
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考