Engineering Journal
Ginexys
Ginexys

Preventing Monorepo Bloat in VS Code Package Bundles (.vsix)

2026-06-03

TLDR

When building VS Code extensions inside pnpm monorepos, running vsce 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 ConfigurationPackage Size OutputArtifact ContentsVerification Command
Default .vscodeignore55 MB (Bloated)Sibling packages, root scripts, parent configsvsce package
Monorepo-Scoped .vscodeignore216 KB (Optimized)Compiled out/ JS, assets, package manifestvsce 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:


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 using vsce 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 run vsce ls to audit included package files before publishing extensions from a monorepo. Ensure .vscodeignore explicitly excludes all sibling paths (../<sibling>/*) and root files (../../).
Read this post in the full Engineering Journal →