Loading repository data…
Loading repository data…
DiegoLibonati / repository
VSCode Extension Ts Boilerplate is a TypeScript-based template for building VS Code extensions with a fully configured development environment and a clean layered architecture ready to extend.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
This project was created primarily for educational and learning purposes.
While it is well-structured and could technically be used in production, it is not intended for commercialization.
The main goal is to explore and demonstrate best practices, patterns, and technologies in software development.
VSCode Extension Ts Boilerplate is a TypeScript-based template for building VS Code extensions with a fully configured development environment and a clean layered architecture ready to extend.
What it is: A production-ready boilerplate for building VS Code extensions with TypeScript — giving you a clean, pre-configured foundation so you can focus on writing your extension's actual logic from day one.
The problem it solves: Every new VS Code extension requires the same repetitive setup: wiring up esbuild, configuring TypeScript with strict mode, mocking the vscode API for tests, setting up ESLint + Prettier + pre-commit hooks, and deciding how to organize commands, helpers, and types. This template makes all of those decisions once so you never have to again.
What it includes:
scripts/build.ts) with path alias support (@/ → src/, @__tests__/ → __tests__/) and a problem-matcher plugin for VS Code's watch task integrationsrc/, __tests__/, scripts/, and a shared tsconfig.base.json with strict mode fully enabled (exactOptionalPropertyTypes, noUncheckedIndexedAccess, etc.)vscode API mock (__tests__/__mocks__/vscode.mock.ts) and ExtensionContext mock — unit tests run without a VS Code instance; 70% coverage threshold enforcedtypescript-eslint strict rules: explicit return types, no any, consistent type imports, no unused variableseslint-plugin-prettier to avoid conflicts.ts file, blocking commits with errorssrc/commands/ (VS Code API layer), src/helpers/ (utility functions — pure logic by default, free to import vscode when needed), src/constants/ + src/types/ (shared values and contracts).vscode/ workspace config: two launch configurations (build-once and watch-mode), recommended extensions, and build tasks wired to the debug runnerHow to use it: Clone the repo, update the extension name, displayName, publisher, and command IDs in package.json, rename or delete the example aliveCommand.ts, and start adding your own register*Command() functions in src/commands/ — the architecture and tooling are already wired up.
No production dependencies - Pure Vanilla TypeScript
"@eslint/js": "^9.0.0"
"@semantic-release/changelog": "^6.0.3"
"@semantic-release/exec": "^7.1.0"
"@semantic-release/git": "^10.0.1"
"@types/jest": "^29.5.14"
"@types/node": "^22.0.0"
"@types/vscode": "^1.99.0"
"@vscode/vsce": "^3.0.0"
"esbuild": "^0.25.10"
"eslint": "^9.23.0"
"eslint-config-prettier": "^9.0.0"
"eslint-plugin-prettier": "^5.0.0"
"globals": "^15.0.0"
"husky": "^9.0.0"
"jest": "^29.7.0"
"lint-staged": "^15.0.0"
"prettier": "^3.0.0"
"semantic-release": "^25.0.3"
"ts-jest": "^29.3.2"
"tsx": "^4.19.3"
"typescript": "^5.6.3"
"typescript-eslint": "^8.0.0"
Now that you know what the boilerplate provides, here's how to spin it up locally:
npm installF5 or go to Run > Start DebuggingCtrl+Shift+P) and run VSCode Extension Ts Boilerplate: AliveFor active development outside the debug runner, you can run the bundler directly in watch mode:
npm run dev
No .env file is required to run the extension — see Env Keys for the variables consumed by the publish pipeline.
The pre-commit pipeline is already wired up via Husky + lint-staged. On every commit, staged .ts files are automatically linted and formatted, and the commit is blocked if there are unfixable errors.
The hook runs:
any, consistent type imports, no unused variables) — auto-fixes what it can.To trigger the same checks manually:
npm run lint # Check linting errors in src/
npm run lint:fix # Auto-fix linting errors in src/
npm run lint:all # Auto-fix linting errors in src/ + __tests__/
npm run format # Format src/ with Prettier
npm run format:check # Check formatting without writing
npm run format:all # Format src/ + __tests__/ with Prettier
npm run check-types # Type-check all tsconfigs (src, tests, scripts)
This extension does not consume any runtime environment variables — installed users do not need to configure anything, and contributors do not need a .env to run it locally.
The only secret in the toolchain belongs to the publish pipeline: an Azure DevOps Personal Access Token (PAT) used by vsce to push the extension to the Marketplace. It is not loaded from a .env file; vsce prompts for it on first publish and caches it locally, or you can pass it explicitly. See Production → Publish to the Marketplace for the full flow.
| Variable | Scope | Required | Description |
|---|---|---|---|
VSCE_PAT | Publishing only | Optional | Azure DevOps PAT with Marketplace publish permissions. Can be exported as an env var or passed via npx vsce publish --pat <token> to skip the interactive prompt. |
With the project running, here's how the codebase is organized:
vscode-extension-ts-boilerplate/
├── __tests__/ # Test suite
│ ├── __mocks__/ # Shared mock data and module mocks
│ │ ├── extensionContext.mock.ts # Mock for vscode.ExtensionContext
│ │ └── vscode.mock.ts # Mock for the vscode API
│ ├── commands/ # Tests for command modules
│ ├── helpers/ # Tests for helper functions
│ └── jest.setup.ts # Jest global setup
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions CI/CD pipeline
├── public/ # Static assets
│ └── icon.png # Extension icon
├── scripts/
│ └── build.ts # esbuild bundler script
├── src/
│ ├── commands/ # One file per registered VS Code command
│ │ └── aliveCommand.ts # Example command
│ ├── constants/ # App-wide constant values
│ │ └── vars.ts # General constants
│ ├── helpers/ # Utility functions (may import vscode when needed)
│ │ └── getFullPathFile.ts # Path joining helper
│ ├── types/ # TypeScript type definitions
│ │ └── app.ts # Domain model types
│ └── extension.ts # Extension entry point (activate / deactivate)
├── .vscode/
│ ├── extensions.json # Recommended VS Code extensions
│ ├── launch.json # Debug / run configurations
│ ├── settings.json # Workspace settings
│ └── tasks.json # Build tasks used by launch.json
├── .editorconfig # Editor-agnostic formatting rules
├── .npmrc # npm settings (engine-strict)
├── .nvmrc # Pinned Node version (used by CI)
├── CHANGELOG.md # Release notes (Keep a Changelog)
├── eslint.config.mjs # ESLint flat config
├── jest.config.mjs # Jest configuration
├── tsconfig.app.json # TypeScript config for src/
├── tsconfig.base.json # Shared TypeScript base config
├── tsconfig.scripts.json # TypeScript config for scripts/
├── tsconfig.test.json # TypeScript config for __tests__/
└── package.json # Project metadata and scripts
| Folder / File | Description |
|---|---|
__tests__/ | All test files, grouped by source category |
__tests__/__mocks__/ | Reusable mocks — vscode API and ExtensionContext |
src/commands/ | One file per VS Code command; each exports a register* function |
src/constants/ | Centralized constants with typed values from src/types/ |
src/helpers/ | Utility functions; may import vscode when wrapping the API |
src/types/ | TypeScript interfaces and types, split by concern |
src/extension.ts | Entry point — registers all commands via context.subscriptions |
scripts/build.ts | esbuild bundler with path alias and problem matcher plugins |
.vscode/launch.json | Two run configs: build-once and watch mode |
The extension follows a layered architecture with strict separation between the VS Code API surface and pure application logic:
extension.ts (entry point)
│
├── commands/ (VS Code API layer — registers commands, handles Disposables)
│
├── helpers/ (utility layer — pure logic preferred, vscode allowed when needed)
│
├── constants/ (shared values — typed via types/)
│
└── types/ (TypeScript contracts)
extension.ts acts as the composition root: it imports every register*Command() function and pushes the returned Disposable into context.subscriptions, delegating lifecycle management entirely to VS Code.
helpers/ favors pure functions so they can be tested with plain Jest — no mocking required. When a helper genuinely needs the VS Code API (e.g. a thin wrapper around vscode.window.showQuickPick), importing vscode is allowed; the global vscode mock in __tests__/__mocks__/ covers those cases at test time.
Command Pattern
Each VS Code command is encapsulated in its own module inside src/commands/. Every module exposes a single register*Command(): vscode.Disposable function that wires the command ID to its handler internally. extension.ts only calls register* — it never knows about the underlying handler logic.
// src/commands/aliveCommand.ts
const aliveCommand = (): void => {
vscode.window.showInformationMessage("...");
};
export const registerAliveCommand = (): vscode.Disposable => {
return vscode.commands.registerCommand(
"vscode-extension-ts-boilerplate.alive",
aliveCommand
);
};
Disposable Pattern
VS Code's resource lifecycle is managed thro