isolate-package is a tool for isolating monorepo workspace packages into
self-contained directories with their internal dependencies and adapted
lockfiles. It's particularly useful for deploying to platforms like Firebase
from a monorepo without complex scripting.
- Package Isolation: Extracts a package from a monorepo with all its internal dependencies
- Lockfile Adaptation: Generates or adapts lockfiles for the isolated package structure
- Multi-Package Manager Support: Works with NPM, PNPM, Yarn, and partially with Bun
- Firebase Integration: Special support for Firebase deployments
- Use TypeScript for all source files
- Target ES modules (ESM) - the project uses
"type": "module" - Use path aliases:
~maps tosrc/directory - Prefer
node:prefix for Node.js built-in modules (e.g.,node:path,node:assert) - Use
satisfiesoperator for type-safe object literals where appropriate
- Prefer functional approaches over class-based ones (as seen in the recent Config refactor)
- Use pure functions where possible
- Avoid unnecessary state management
- Use
remedafor functional utilities (not lodash)
- Use
assertfromnode:assertfor critical validations - Use the
getErrorMessageutility for consistent error message extraction - Provide clear, actionable error messages
- Use the centralized logger from
lib/logger - Follow the log level hierarchy: debug < info < warn < error
- Use
debugfor detailed implementation info - Use
infofor important user-facing information - Include context in log messages (file paths, package names, etc.)
src/
├── lib/
│ ├── config.ts # Configuration management
│ ├── logger.ts # Logging utilities
│ ├── types.ts # Shared type definitions
│ ├── lockfile/ # Lockfile processing logic
│ ├── manifest/ # Package.json manipulation
│ ├── output/ # Output generation
│ ├── package-manager/ # Package manager detection/handling
│ ├── registry/ # Package registry management
│ └── utils/ # General utilities
├── isolate.ts # Main isolation logic
├── isolate-bin.ts # CLI entry point
└── index.ts # Library export
- Use Vitest for testing
- Place test files next to the source files with
.test.tssuffix - Write focused unit tests for utility functions
- Use descriptive test names with
describeandit
- Use
fs-extrainstead of nativefsfor enhanced file operations - Use
consolafor logging (via the centralized logger inlib/logger) - Use
yamlpackage for YAML parsing/writing - Use
globfor file pattern matching
// Always use the centralized detection
const packageManager = detectPackageManager(workspaceRootDir);
// or for singleton usage within a module
const packageManager = usePackageManager();- Always use
path.join()for cross-platform compatibility - Never use string concatenation for paths
- Use utility functions for consistent path formatting:
getRootRelativeLogPath()for logging paths relative to rootgetIsolateRelativeLogPath()for paths relative to isolate dir
- Read manifests with
readTypedJson<PackageManifest>() - Write manifests with
writeManifest() - Always preserve unknown fields when modifying manifests
- Strip
devDependenciesandscriptsfrom internal package manifests
- Use async/await consistently
- Parallelize operations where possible with
Promise.all() - Handle file system operations carefully with proper error handling
- Zero-config by default - most users shouldn't need configuration
- Configuration file:
isolate.config.json - Environment variables for debugging:
DEBUG_ISOLATE_CONFIG=true - Validate configuration keys and warn about unknown options
- Preserve
workspace:*specifiers in isolated output - Copy or generate
pnpm-workspace.yaml - Handle Rush workspaces specially (generate workspace config)
- Prune lockfiles before writing
- Replace workspace specifiers with
file:paths - Preserve original resolved versions and integrity by reading the root
package-lock.jsonvia ArboristloadVirtualand copying matching entries into the isolated lockfile - Fall back to Arborist's
buildIdealTree(generating from node_modules) when no rootpackage-lock.jsonexists (forceNpmfrom non-npm monorepos, or modern Yarn v2+)
- Replace workspace specifiers with file paths
- Yarn v1: copy
yarn.lockand run a localyarn installto prune - Yarn v2+: fall through to the NPM generator
- Keep changes focused and atomic
- Update tests for any logic changes
- Update README.md for user-facing changes
- Include clear commit messages
- Consider backward compatibility
Always create a PR summary when completing a task that involves code changes:
- Create or overwrite the
PR_SUMMARY.mdfile at the project root- Note: This file is not in version control and may already exist from previous tasks
- Always completely overwrite the existing content with new summary
- Include the following sections:
- Problem: Clear description of the issue being solved
- Root Cause: Technical explanation of why the issue occurred
- Solution: Code changes made with examples
- Benefits: List of improvements and guarantees
- Testing: Verification steps taken (tests, compilation, build)
- Impact: How this affects users and resolves the original issue
- Link to relevant GitHub issues/PRs using markdown format
- Use clear, technical language suitable for code review
- Include code snippets to illustrate key changes
This documentation helps maintain project history and assists with code reviews.
- Don't assume a specific package manager - always detect
- Don't use Windows-incompatible path operations
- Don't forget to handle Rush workspaces specially
- Don't include unnecessary files in the isolated output
- Don't modify the original workspace files
- Pack/unpack operations can be slow - show progress in debug mode
- Reuse package registry across operations
- Clean up temporary directories only on success (aids debugging)
- Use streaming operations for large files when possible
- Validate all file paths to prevent directory traversal
- Be careful with shell command execution
- Don't expose sensitive configuration in logs
- Design APIs to be extensible
- Keep backward compatibility in mind
- Document breaking changes clearly
- Use semantic versioning
When logLevel is set to "debug":
- Log all major operations
- Include file paths and package names
- Show timing information for slow operations
- Keep temporary directories for inspection
- Support both 1st and 2nd generation functions
- Handle
firebase.jsonconfiguration - Copy
.npmrcfiles for authentication - Consider the firebase-tools-with-isolate fork