Skip to content

Project layout

A freshly scaffolded project:

my-extension/
├── src/
│ ├── extension/
│ │ ├── extension.ts # bootstrap(registry) — wires VS Code on activate
│ │ └── _registry.ts # AUTO-GENERATED by `bun run gen`
│ ├── panels/<name>.ts # one file = one webview panel (definePanel)
│ ├── commands/<name>.ts # one file = one palette command (defineCommand)
│ ├── menus/<name>.ts # activity-bar container + items (defineMenu)
│ ├── treeViews/<name>.ts # data-driven tree view (defineTreeView)
│ ├── subpanels/<name>.ts # inline webview section inside a menu
│ ├── statusBars/<name>.ts # status bar item (defineStatusBar)
│ ├── webview/
│ │ ├── panels/<name>/ # React UI per panel (App.tsx, main.tsx)
│ │ └── components/ # shared themed components (after `components add`)
│ ├── services/ # business logic (e.g. <Model>Service.ts)
│ ├── models/ # typed entities (after `model add`)
│ ├── helpers/ # db.ts, secrets.ts, … (after `db init` / `helper add`)
│ └── shared/
│ ├── api.ts # RPC contracts (interface per panel)
│ └── vsceasy/ # framework runtime — synced via `vsceasy upgrade`
├── scripts/gen.ts # registry + contributes generator
├── .vscode/launch.json # Extension Development Host launch
├── vite.config.ts # webview build
└── package.json # esbuild for extension, vite for UI

Owned vs generated

  • You own everything under panels/, commands/, webview/, services/, models/, helpers/, and shared/api.ts. Edit freely.
  • Generatedsrc/extension/_registry.ts and package.json#contributes are rewritten by gen. Don’t hand-edit them.
  • Framework runtimesrc/shared/vsceasy/* and scripts/gen.ts are owned by vsceasy. Keep them current with vsceasy upgrade; don’t edit them.

Build pipeline

  • Extension code → esbuilddist/extension.js (CJS, node target).
  • Each panel/subpanel UI → vitedist/webview/<kind>/<name>/.
  • bun run dev runs both in watch; F5 launches the dev host.
  • bun run package.vsix via @vscode/vsce.