freezepak
Freeze and unfreeze node_modules dependencies for portable deployment.
Problem
When you use local file: dependencies during development, npm creates symlinks (Linux/Mac) or junctions (Windows) in node_modules pointing back to the source directories. This is great for development — changes are reflected immediately — but these links break when you copy or deploy the project to another machine.
Solution
freezepak --freeze replaces every symlink/junction in node_modules with a real copy of the target directory. The project becomes fully self-contained and portable. It also adds a preinstall guard to package.json that blocks npm install from accidentally restoring the links and undoing the freeze.
freezepak --unfreeze removes the guard and runs npm install to restore normal linked dependencies.
Installation
npm install -g @bobfrankston/freezepak
CLI Usage
freezepak [path] --freeze # Replace links with real copies
freezepak [path] --unfreeze # Restore links via npm install
freezepak [path] --pack # Freeze, pack to .tgz, then unfreeze
freezepak -v # Show version
The optional path argument specifies the project directory (defaults to the current directory).
Library Usage
freezepak can also be imported and used programmatically:
import { freezepak, freezeDependencies, unfreezeDependencies } from '@bobfrankston/freezepak';
const tgzPath: string = freezepak('/path/to/project');
freezeDependencies('/path/to/project');
unfreezeDependencies('/path/to/project');
Idempotency
Both operations are idempotent — safe to run multiple times:
-
--freeze skips entries that are already real directories (not links). Running freeze twice on the same project just reports 0 frozen packages the second time. The preinstall guard is overwritten with the same value.
-
--unfreeze checks for the preinstall guard before acting. If there's no guard (already unfrozen), it reports "nothing to unfreeze" and exits without running npm install.
Reversibility
The dependencies field in package.json is never modified — your file: paths remain intact. This is what makes unfreeze possible: npm install reads those paths and recreates the links. The only package.json change is the preinstall guard in scripts, which unfreeze removes.
How it works
Freeze
- Walks
node_modules (including @scope/ directories)
- For each entry, checks if it's a symlink or junction (comparing
realpathSync to the entry path)
- If linked: removes the link, copies the real target directory in its place via
fs.cpSync
- Saves any existing
preinstall script as frozen-preinstall
- Sets
preinstall to a guard that blocks npm install with an error message
Unfreeze
- Restores the original
preinstall script (if one was saved as frozen-preinstall), or removes the guard entirely
- Runs
npm install which reads the preserved file: paths in dependencies and recreates proper symlinks/junctions
License
MIT