Preventing Monorepo Bloat in VS Code Package Bundles (.vsix)
TLDR
When building VS Code extensions inside pnpm monorepos, runningvsce package follows symlinked node_modules paths by default. This causes vsce to bundle sibling workspace packages, parent directories, and root scripts, inflating a tiny 216KB extension package into a 55MB monster. The fix requires explicit relative ignore patterns (../<sibling>/* and ../../) inside every sub-package .vscodeignore.
| Packaging Configuration | Package Size Output | Artifact Contents | Verification Command |
|---|---|---|---|
Default .vscodeignore | 55 MB (Bloated) | Sibling packages, root scripts, parent configs | vsce package |
Monorepo-Scoped .vscodeignore | 216 KB (Optimized) | Compiled out/ JS, assets, package manifest | vsce ls |
Uncontrolled symlink traversal inflates .vsix bundles to 55MB
Running vsce package in packages/core resulted in either:
ERROR: invalid relative path: extension/../../pnpm-workspace.yaml or a .vsix file that built successfully but weighed in at 55 MB.
Inspecting the contents of the .vsix archive revealed that vsce had recursively slurped:
../tafne/,../pdf/,../schema/(sibling extensions)../../pnpm-workspace.yaml,../../package.json../../scripts/build-media.sh../../.vscode/launch.json
Bundlers recursively traverse relative node_modules paths
pnpm represents monorepo workspace dependencies as physical symlinks inside node_modules/.pnpm/.
When vsce package traverses node_modules during bundling, its file system crawler follows symlinks out of the sub-package root and up into sibling directories. Traditional .vscodeignore files only exclude local sub-paths like node_modules/ or src/, failing to block parent-relative traversal paths like ../ or ../../.
+-------------------------------------------------------------+
pnpm Symlink Traversal vsce package crawler / \ v v [Follows Symlink] [Parent-Relative] node_modules/.pnpm .vscodeignore rules v v Sibling Packages Exclude ../ and ../../ (55MB Bloat) (216KB Bundle)
+-------------------------------------------------------------+
Parent-relative exclusion rules isolate monorepo sub-packages
To force vsce to ignore sibling and parent monorepo directories, update .vscodeignore in every package directory:
# 1. Source files: ship only compiled JS output in out/
src/
tsconfig.json
2. Block sibling workspace package traversal
../core/**
../tafne/**
../pdf/**
../schema/**
../pack/**
3. Block monorepo root traversal
../../*
../../.vscode/**
../../scripts/**
4. Standard dev artifacts
node_modules/
.vscode/
*/.map
*/.ts
!out/*/.d.ts
pnpm-lock.yaml
Run vsce ls to verify package list outputs
Always inspect the manifest file list usingvsce ls before creating production bundles:
cd packages/core
vsce ls
If the output lists any paths starting with ../, your ignore rules have a gap. A clean output should list only compiled files in out/, static assets, and package metadata.
Rule of thumb: Always runvsce lsto audit included package files before publishing extensions from a monorepo. Ensure.vscodeignoreexplicitly excludes all sibling paths (../<sibling>/*) and root files (../../).