DEV Community

Cover image for Build VS Code Extensions Fast with vsceasy
Jairo Fernández
Jairo Fernández

Posted on

Build VS Code Extensions Fast with vsceasy

vsceasy promo

▶ Watch the full 30-second promo (MP4)

If you've ever tried to build a VS Code extension with a UI, you know the pain: hand-wiring postMessage channels between the extension host and the webview, stringly-typed messages, a fragile build setup, and a package.json#contributes block that grows into a swamp.

vsceasy (pronounced "vee-see-easy") removes that boilerplate. It scaffolds extensions with a React UI, a typed RPC bridge between extension and webview, and a zero-config build — so you spend time on features, not plumbing.

Quick start

No install needed:

bunx @vsceasy/cli create my-extension   # or: npx @vsceasy/cli create my-extension
cd my-extension
bun run dev
# press F5 in VS Code to launch the Extension Development Host
Enter fullscreen mode Exit fullscreen mode

Or fully scripted with flags:

bunx @vsceasy/cli create \
  --name my-extension \
  --displayName "My Extension" \
  --publisher my-publisher \
  --type ui --ui react \
  --git --install
Enter fullscreen mode Exit fullscreen mode

New to a project? vsceasy wizard detects whether you're inside one and menus the common generators.

The killer feature: typed RPC

This is what makes vsceasy worth it. Define your contract once:

// src/shared/api.ts
export interface DashboardApi {
  listFiles(pattern: string): Promise<string[]>;
}
Enter fullscreen mode Exit fullscreen mode

Implement it on the extension side:

const handlers: DashboardApi = {
  async listFiles(pattern) {
    const uris = await vscode.workspace.findFiles(pattern);
    return uris.map(u => vscode.workspace.asRelativePath(u));
  },
};
createRpcServer(webviewTransport(panel.webview), handlers);
Enter fullscreen mode Exit fullscreen mode

Call it from the webview with full type inference:

const api = createRpcClient<DashboardApi>(vscodeApiTransport(vscode));
const files = await api.listFiles('**/*.ts');  // typed as string[]
Enter fullscreen mode Exit fullscreen mode

No manual postMessage. No string-typed message channels. Change the interface and TypeScript flags both sides instantly.

Three extension types

create asks what you're building:

Type What you get
ui (default) React webview + typed RPC bridge
language TextMate grammar, language config, snippets, opt-in file-icon theme
empty Bare activate/deactivate

Want to see a full extension built step by step? The docs have a "Build a Todo extension" tutorial — database, typed model, CRUD UI, and a background reminder, one command at a time (Tour-of-Heroes style).

Generators for everything

Structure is vsceasy <resource> <verb>. Every command runs interactively (prompts) or fully scripted (flags):

vsceasy panel add       # webview panel + optional typed RPC
vsceasy command add     # palette command + menu entry + keybinding
vsceasy menu add        # sidebar tree view
vsceasy treeview add    # data-driven tree (getChildren/getTreeItem)
vsceasy statusBar add   # status bar item
vsceasy rpc add         # add a typed RPC method to a panel
vsceasy db init         # mini-ORM database scaffold
vsceasy job add         # recurring / event-triggered jobs
vsceasy publish init    # marketplace preflight
Enter fullscreen mode Exit fullscreen mode

Contributions stay clean

package.json#contributes is split. vsceasy regenerates the parts it owns (commands, keybindings, views) on every build. Everything else — languages, grammars, snippets, themes, walkthroughs — lives in a contributes.extra.json file and gets deep-merged in. No more manual edits clobbered by codegen.

Why it matters

  • Typed RPC kills the most error-prone part of extension UIs.
  • Zero-config build — esbuild for the extension, Vite for the webview, already wired.
  • File-based registry + generators keep large extensions organized.

Give it a spin:

bunx @vsceasy/cli create my-extension
Enter fullscreen mode Exit fullscreen mode

⭐ Star it on GitHub if it saves you time. Feedback and issues welcome.

Top comments (0)