add-webview

GitHub

用于生成包含 IPC 协议、Lit 应用及注册逻辑的新 Webview 脚手架代码,支持配置名称、类型及功能属性。

.claude/skills/add-webview/SKILL.md gitkraken/vscode-gitlens

Trigger Scenarios

需要创建新的 Webview 模块 初始化带有 IPC 通信的界面组件

Install

npx skills add gitkraken/vscode-gitlens --skill add-webview -g -y
More Options

Non-standard path

npx skills add https://github.com/gitkraken/vscode-gitlens/tree/main/.claude/skills/add-webview -g -y

Use without installing

npx skills use gitkraken/vscode-gitlens@add-webview

指定 Agent (Claude Code)

npx skills add gitkraken/vscode-gitlens --skill add-webview -a claude-code -g -y

安装 repo 全部 skill

npx skills add gitkraken/vscode-gitlens --all -g -y

预览 repo 内 skill

npx skills add gitkraken/vscode-gitlens --list

SKILL.md

Frontmatter
{
    "name": "add-webview",
    "description": "Create new webviews with IPC protocol, Lit app, and registration"
}

/add-webview - Create New Webview

Scaffold a new webview with all required boilerplate.

Usage

/add-webview [name]

Information Needed

  1. Webview name — camelCase (e.g., myFeature)
  2. Display title — e.g., "My Feature"
  3. Typeview (sidebar) or panel (editor panel)
  4. Pro feature — Yes/No (affects file location)

Files to Create

1. Protocol: src/webviews/{name}/protocol.ts

import type { IpcScope } from '../ipc/models/ipc.js';
import { IpcCommand, IpcNotification, IpcRequest } from '../ipc/models/ipc.js';
import type { WebviewState } from '../protocol.js';

export const scope: IpcScope = '{name}';

export interface State extends WebviewState<'gitlens.views.{name}'> {
	loading: boolean;
}

// Commands (fire-and-forget)
export interface DoSomethingParams {
	id: string;
}
export const DoSomethingCommand = new IpcCommand<DoSomethingParams>(scope, 'doSomething');

// Requests (with response)
export interface GetDataParams {
	filter?: string;
}
export interface GetDataResponse {
	items: unknown[];
}
export const GetDataRequest = new IpcRequest<GetDataParams, GetDataResponse>(scope, 'getData');

// Notifications (host → webview)
export interface DidChangeDataParams {
	items: unknown[];
}
export const DidChangeDataNotification = new IpcNotification<DidChangeDataParams>(scope, 'data/didChange');

2. Provider: src/webviews/{name}/{name}Webview.ts

import type { Disposable } from 'vscode';
import type { Container } from '../../container.js';
import type { WebviewHost, WebviewProvider } from '../webviewProvider.js';
import { ipcCommand, ipcRequest } from '../ipc/handlerRegistry.js';
import type { IpcParams, IpcResponse } from '../ipc/models/ipc.js';
import type { State } from './protocol.js';
import { DoSomethingCommand, GetDataRequest, DidChangeDataNotification } from './protocol.js';

export class {Name}WebviewProvider implements WebviewProvider<State, State>, Disposable {
    constructor(
        private readonly container: Container,
        private readonly host: WebviewHost<'gitlens.views.{name}'>,
    ) {}

    dispose(): void {}

    async includeBootstrap(): Promise<State> {
        return {
            webviewId: this.host.id,
            webviewInstanceId: this.host.instanceId,
            loading: false,
        };
    }

    @ipcCommand(DoSomethingCommand)
    private async onDoSomething(params: IpcParams<typeof DoSomethingCommand>): Promise<void> {
        // Handle command
    }

    @ipcRequest(GetDataRequest)
    private async onGetData(params: IpcParams<typeof GetDataRequest>): Promise<IpcResponse<typeof GetDataRequest>> {
        return { items: [] };
    }
}

3. Registration: src/webviews/{name}/registration.ts

import type { WebviewsController } from '../webviewsController.js';
import type { WebviewViewProxy } from '../webviewProxy.js';
import type { State } from './protocol.js';

export type {Name}WebviewShowingArgs = [];

export function register{Name}WebviewView(
    controller: WebviewsController,
): WebviewViewProxy<'gitlens.views.{name}', {Name}WebviewShowingArgs, State> {
    return controller.registerWebviewView<'gitlens.views.{name}', State, State, {Name}WebviewShowingArgs>(
        {
            id: 'gitlens.views.{name}',
            fileName: '{name}.html',
            title: '{Title}',
            contextKeyPrefix: 'gitlens:webviewView:{name}',
            trackingFeature: '{name}View',
            type: '{name}',
            plusFeature: false,
            webviewHostOptions: { retainContextWhenHidden: true },
        },
        async (container, host) => {
            const { {Name}WebviewProvider } = await import(
                /* webpackChunkName: "webview-{name}" */ './{name}Webview.js'
            );
            return new {Name}WebviewProvider(container, host);
        },
    );
}

4. App: src/webviews/apps/{name}/{name}.ts

import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { GlAppHost } from '../shared/appHost.js';
import type { HostIpc } from '../shared/ipc.js';
import type { LoggerContext } from '../shared/contexts/logger.js';
import type { State } from '../../{name}/protocol.js';
import { {Name}StateProvider } from './stateProvider.js';
import { styles } from './{name}.css.js';

@customElement('gl-{name}-app')
export class Gl{Name}App extends GlAppHost<State, {Name}StateProvider> {
    static override styles = styles;

    protected override createStateProvider(
        bootstrap: string, ipc: HostIpc, logger: LoggerContext,
    ): {Name}StateProvider {
        return new {Name}StateProvider(this, bootstrap, ipc, logger);
    }

    override render() {
        return html`<div class="{name}"><h1>{Title}</h1></div>`;
    }
}

5. State Provider: src/webviews/apps/{name}/stateProvider.ts

import type { Disposable } from 'vscode';
import type { StateProvider } from '../shared/stateProviderBase.js';
import type { HostIpc } from '../shared/ipc.js';
import type { LoggerContext } from '../shared/contexts/logger.js';
import type { State } from '../../{name}/protocol.js';

export class {Name}StateProvider implements StateProvider<State>, Disposable {
    readonly state: State;

    constructor(
        private readonly host: Gl{Name}App,
        bootstrap: string,
        private readonly ipc: HostIpc,
        private readonly logger: LoggerContext,
    ) {
        this.state = JSON.parse(bootstrap);
    }

    dispose(): void {}
}

6. Styles: src/webviews/apps/{name}/{name}.css.ts

import { css } from 'lit';

export const styles = css`
    :host { display: block; height: 100%; }
    .{name} { padding: 1rem; }
`;

Accessibility

For accessibility requirements when creating or modifying webview components, see docs/accessibility.md.

Additional Steps

  1. Webpack entry — Add to getWebviewsConfigs() in webpack.config.mjs
  2. Register in src/webviews/webviewsController.ts
  3. View ID — Add to src/constants.views.ts
  4. Buildpnpm run build:webviews

File Locations

Component Community Pro
Protocol/Provider src/webviews/{name}/ src/webviews/plus/{name}/
App src/webviews/apps/{name}/ src/webviews/apps/plus/{name}/

Version History

  • ba869f2 Current 2026-08-20 14:21

Same Skill Collection

.claude/skills/a11y-audit/SKILL.md
.claude/skills/a11y-flow-audit/SKILL.md
.claude/skills/a11y-remediate/SKILL.md
.claude/skills/add-command/SKILL.md
.claude/skills/challenge-plan/SKILL.md
.claude/skills/commit/SKILL.md
.claude/skills/create-issue/SKILL.md
.claude/skills/deep-planning/SKILL.md
.claude/skills/deep-review/SKILL.md
.claude/skills/dev-scope/SKILL.md
.claude/skills/investigate/SKILL.md
.claude/skills/live-exercise/SKILL.md
.claude/skills/live-inspect/SKILL.md
.claude/skills/live-pair/SKILL.md
.claude/skills/live-perf/SKILL.md
.claude/skills/modern-css/SKILL.md
.claude/skills/prioritize/SKILL.md
.claude/skills/review/SKILL.md
.claude/skills/triage/SKILL.md
.claude/skills/update-issues/SKILL.md
.claude/skills/ux-review/SKILL.md
.claude/skills/worktree/SKILL.md
.claude/skills/add-icon/SKILL.md
.claude/skills/add-test/SKILL.md
.claude/skills/audit-commits/SKILL.md

Metadata

Files
0
Version
ba869f2
Hash
eab8fef6
Indexed
2026-08-20 14:21

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-25 09:05
浙ICP备14020137号-1 $방문자$