Vanilla JS + GitHub Actions CI/CD + VS Marketplace & Open VSX deploy.
Build your extension. Push to publish.
English | 한국어
Part of Starter Series — Stop explaining CI/CD to your AI every time. Clone and start.
Docker Deploy · Discord Bot · Telegram Bot · Browser Extension · Electron App · npm Package · React Native · VS Code Extension · MCP Server · Python MCP Server · Cloudflare Pages
Via create-starter (recommended):
npx @starter-series/create my-vscode-extension --template vscode-extension
cd my-vscode-extension && npm install
npm run build
# Open in VS Code and press F5 to launch Extension Development HostOr clone directly:
git clone https://github.com/starter-series/vscode-extension-starter my-vscode-extension
cd my-vscode-extension && npm install
npm run build
# Open in VS Code and press F5Then open Command Palette (Ctrl+Shift+P) → Hello World or Show Webview Panel.
Everything below is backed by code on disk and exercised by Jest (40 tests passing, 100% statement coverage).
- Vanilla JS extension scaffold —
src/extension.js(activate/deactivate),src/commands/helloWorld.js(command example),src/webview/panel.js(CSP + nonce + bidirectional messaging). - CI pipeline (
.github/workflows/ci.yml) —npm audit, ESLint v9 flat config, Jest with coverage gate,vsce packagebuild verification. - CD pipeline (
.github/workflows/cd.yml) — version-tag guard,vsce publishto VS Marketplace,ovsx publishto Open VSX, GitHub Release with.vsixattached, manual trigger via Actions tab. - Supply-chain hardening —
npm ci --ignore-scriptsacross CI/CD, pinned gitleaks 8.30.1 with sha256 checksum verification, CodeQL on push/PR + weekly, Dependabot for npm + actions. - Webview security defaults —
default-src 'none', per-loadcrypto.randomBytes(16)nonce,localResourceRootsscoped tosrc/webview/,enableScriptspanel-local. - Version bumper —
scripts/bump-version.jsexposed asnpm run version:patch|minor|major. - Maintenance workflows — weekly CI health check (auto-issues on failure), stale bot (30d label → 7d close).
├── src/
│ ├── extension.js # Main entry (activate/deactivate)
│ ├── commands/helloWorld.js # Example command
│ └── webview/panel.js # Webview panel (CSP + nonce + messaging)
├── tests/
│ ├── __mocks__/vscode.js # VS Code API mock for Jest
│ ├── bump-version.test.js
│ ├── extension.test.js
│ ├── overrides-regression.test.js
│ └── webview.test.js
├── .github/workflows/
│ ├── ci.yml # Lint, test, package verification
│ ├── cd.yml # Publish to VS Marketplace + Open VSX
│ ├── codeql.yml # Static security analysis
│ ├── maintenance.yml # Weekly CI health check
│ └── stale.yml # Inactive issue/PR janitor
├── docs/
│ ├── MARKETPLACE_SETUP.md # VS Marketplace PAT setup
│ └── OPENVSX_SETUP.md # Open VSX token setup
└── scripts/bump-version.js # Semver version bumper
- None on the public roadmap. This starter is feature-complete for its scope.
- Vanilla JS, zero build step. LLMs generate clean JavaScript directly; a TypeScript + bundler stack forces the model to also reason about
tsconfig.json,outDir, source maps, and bundler entry points before the extension can even be tested. Removing those layers shortens the iteration loop. - Dual publishing (VS Marketplace + Open VSX) baked in, not bolted on. Open VSX is the only registry available to VS Codium, Gitpod, and Coder users. A starter that publishes to only one registry quietly excludes that audience.
- Webview as a unit-testable pure function.
src/webview/panel.jsexports the message handler separately from VS Code API binding, so it can be tested without mocking theWebviewobject. This is the pattern most starters skip. - CI/CD assumes the secret will be missing on first run. Both publish steps are conditional on the secret existing — the template is safe to fork without immediately breaking CD.
- Security is the default, not a checklist item.
--ignore-scripts, sha256-pinned gitleaks, CodeQL,npm auditon every push, and webview CSP with nonce are all turned on out of the box.
- No TypeScript by default. If you need it, the README section below shows the four-step opt-in. Forcing TS on every fork would defeat the zero-build-step philosophy.
- No webpack / esbuild / Rollup. Extensions that genuinely need bundling can add it; most don't.
- No
@vscode/test-electron. Jest with avscodeAPI mock covers structural and unit-level tests without the cost of spinning up an Electron host on every PR. Integration-level VS Code testing is out of scope for the starter; it belongs in projects that need it. - No marketplace-listing assets. Icon, banner, gallery screenshots, and the long-form description are author choices and should not be templated.
- No telemetry, no analytics, no remote config. A starter shouldn't ship phone-home behavior to forks.
- None.
| Step | What it does |
|---|---|
| Security audit | npm audit for dependency vulnerabilities |
| Lint | ESLint v9 flat config |
| Test | Jest with coverage gate |
| Build / package verification | Runs npm run build / vsce package and verifies .vsix succeeds |
| Workflow | What it does |
|---|---|
CodeQL (codeql.yml) |
Static analysis for security vulnerabilities (push/PR + weekly) |
Maintenance (maintenance.yml) |
Weekly CI health check — auto-creates issue on failure |
Stale (stale.yml) |
Labels inactive issues/PRs after 30 days, auto-closes after 7 more |
| Step | What it does |
|---|---|
| CI | Runs full CI pipeline first |
| Version guard | Fails if git tag already exists for this version |
| Build | vsce package to create .vsix |
| VS Marketplace | vsce publish to VS Code Marketplace |
| Open VSX | ovsx publish to Open VSX Registry |
| GitHub Release | Creates a tagged release with .vsix attached |
| Artifact | Saves .vsix as GitHub Actions artifact |
How to deploy:
- Set up GitHub Secrets (see below).
- Bump version:
npm run version:patch(orversion:minor/version:major). - Commit and push to
main. - Go to Actions → Publish Extension → Run workflow.
| Secret | Workflow | Description |
|---|---|---|
VSCE_PAT |
cd.yml |
VS Code Marketplace Personal Access Token |
OVSX_PAT |
cd.yml |
Open VSX Registry access token |
See docs/MARKETPLACE_SETUP.md for VS Marketplace setup. See docs/OPENVSX_SETUP.md for Open VSX setup.
Open Command Palette (Ctrl+Shift+P) and run My Extension: Show Webview Panel (command id my-extension.showWebview). The panel demonstrates a minimal, production-ready pattern for building UI inside VS Code.
Security defaults baked in:
default-src 'none'— nothing loads unless explicitly allowed- Per-load nonce generated with
crypto.randomBytes(16)— inline scripts without it are blocked localResourceRootslimited tosrc/webview/— the webview cannot read arbitrary filesenableScripts: truescoped to this panel only
Bidirectional messaging — extension host ↔ webview:
// Webview side (inline <script nonce="...">)
const vscode = acquireVsCodeApi();
document.getElementById('ask').addEventListener('click', () => {
vscode.postMessage({ type: 'getWorkspace' });
});
// Extension side (src/webview/panel.js)
panel.webview.onDidReceiveMessage((message) => {
if (message.type === 'getWorkspace') {
panel.webview.postMessage({ type: 'workspace', data: { /* ... */ } });
}
});The message handler in src/webview/panel.js is a pure function that accepts a postMessage callback, so it's unit-testable without the real Webview API. See tests/webview.test.js.
Full docs: VS Code Webview API guide.
# Launch Extension Development Host (in VS Code, press F5)
# Bump version (updates package.json)
npm run version:patch # 0.1.0 → 0.1.1
npm run version:minor # 0.1.0 → 0.2.0
npm run version:major # 0.1.0 → 1.0.0
# Build .vsix package
npm run build
npm run package
# Lint & test
npm run lint
npm testThe Yeoman VS Code generator is the official scaffolding tool. This template takes a different approach:
| This template | Yeoman generator | |
|---|---|---|
| Philosophy | Thin starter with CI/CD | Scaffolding without CI/CD |
| Build system | None (vanilla JS) | TypeScript compilation (default) |
| CI/CD | Full pipeline included | Not included |
| Dependencies | 6 dev, 0 runtime | 10+ dev |
| Dual publishing | VS Marketplace + Open VSX | Not included |
| AI/vibe-coding | LLMs generate clean vanilla JS | LLMs must handle TS + bundler config |
Choose this template if:
- You want production CI/CD out of the box
- You prefer vanilla JavaScript without a build step
- You need dual publishing (VS Marketplace + Open VSX)
- You're using AI tools to generate extension code
Choose Yeoman if:
- You want TypeScript with full type checking
- You need the official VS Code testing framework (
@vscode/test-electron) - You want webpack/esbuild bundling built in
This template intentionally uses vanilla JavaScript to keep the zero-build-step philosophy. If you need TypeScript:
- Add
typescriptto devDependencies - Add a
tsconfig.json - Add a
tscbuild step topackage.json - Rename
.jsfiles to.ts
This keeps TypeScript opt-in rather than forcing a build pipeline on everyone.
PRs welcome. Please use the PR template.