Refactor the shim to use a lightweight provider interface that excludes heavy dependencies.
Problem
The shim imports full runtime providers which pull in dependencies not needed at runtime:
net/http (~2MB) - used only by ListAvailable()
download package - used only by Install()
progressbar/v3 (~500KB) - used by download
- Detection code for nvm/pyenv/fnm - used only by
DetectInstalled()
Shim's Actual Needs
The shim only uses these provider methods:
type ShimProvider interface {
Name() string
DisplayName() string
Shims() []string
ExecutablePath(version string) (string, error)
IsInstalled(version string) (bool, error)
ShouldReshimAfter(shimName string, args []string) bool
}
It does not need:
Install() / Uninstall()
ListAvailable() / ListInstalled()
DetectInstalled()
GlobalPackages() / InstallGlobalPackages()
Proposed Solutions
Option A: Build Tags
Use //go:build !shim to exclude heavy methods from shim builds:
//go:build !shim
func (p *Provider) ListAvailable() ([]runtime.AvailableVersion, error) {
// HTTP code here
}
Pros: Minimal code changes, single provider file
Cons: Build complexity, easy to forget tags
Option B: Interface Split
Create separate ShimProvider and FullProvider interfaces:
src/internal/runtime/
├── provider.go # Full interface
└── shim_provider.go # Lite interface for shim
src/runtimes/node/
├── provider.go # Core methods (both interfaces)
├── install.go # Install/download (full only)
└── detect.go # Detection code (full only)
Pros: Clean separation, explicit dependencies
Cons: More files, some duplication
Option C: Lazy Loading
Only import heavy packages when methods are called (using plugin or reflection).
Pros: No build changes
Cons: Complex, runtime overhead, not idiomatic Go
Expected Impact
- Shim binary size: ~7.2MB → ~3-4MB (after symbol stripping)
- Removes
net/http initialization overhead
- Faster cold starts
Related
Refactor the shim to use a lightweight provider interface that excludes heavy dependencies.
Problem
The shim imports full runtime providers which pull in dependencies not needed at runtime:
net/http(~2MB) - used only byListAvailable()downloadpackage - used only byInstall()progressbar/v3(~500KB) - used by downloadDetectInstalled()Shim's Actual Needs
The shim only uses these provider methods:
It does not need:
Install()/Uninstall()ListAvailable()/ListInstalled()DetectInstalled()GlobalPackages()/InstallGlobalPackages()Proposed Solutions
Option A: Build Tags
Use
//go:build !shimto exclude heavy methods from shim builds:Pros: Minimal code changes, single provider file
Cons: Build complexity, easy to forget tags
Option B: Interface Split
Create separate
ShimProviderandFullProviderinterfaces:Pros: Clean separation, explicit dependencies
Cons: More files, some duplication
Option C: Lazy Loading
Only import heavy packages when methods are called (using plugin or reflection).
Pros: No build changes
Cons: Complex, runtime overhead, not idiomatic Go
Expected Impact
net/httpinitialization overheadRelated