proper-lockfile vs lockfile vs lockfile-lint
Lockfile Management
proper-lockfilelockfilelockfile-lintSimilar Packages:
Lockfile Management

Lockfile management libraries in Node.js help developers handle package-lock.json or yarn.lock files, which are automatically generated by package managers to ensure consistent installations across environments. These libraries provide tools for reading, writing, validating, and modifying lockfiles, making it easier to manage dependencies, detect issues, and maintain reproducible builds. They are particularly useful in CI/CD pipelines, automated scripts, and projects with strict dependency management requirements. lockfile is a simple utility for reading and writing lockfiles, lockfile-lint focuses on validating and linting lockfiles to ensure their integrity, while proper-lockfile provides a more comprehensive solution for managing lockfiles with features like adding, removing, and updating dependencies while preserving the file's structure and integrity.

Npm Package Weekly Downloads Trend
3 Years
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
proper-lockfile4,340,414262-215 years agoMIT
lockfile2,200,089260-128 years agoISC
lockfile-lint176,68182838 kB37 months agoApache-2.0
Feature Comparison: proper-lockfile vs lockfile vs lockfile-lint

Lockfile Reading and Writing

  • proper-lockfile:

    proper-lockfile offers comprehensive reading and writing capabilities, including the ability to modify existing lockfiles. It supports adding, removing, and updating dependencies while preserving the lockfile's integrity, making it a more versatile choice for complex projects.

  • lockfile:

    lockfile provides basic functionality for reading and writing lockfiles. It allows you to parse existing lockfiles and generate new ones, but it does not offer advanced features like modifying or validating the lockfile structure.

  • lockfile-lint:

    lockfile-lint focuses on validating lockfiles rather than reading or writing them. It checks the lockfile for common issues, such as duplicate entries, missing fields, and incorrect formatting, ensuring that the lockfile is consistent and reliable.

Lockfile Validation

  • proper-lockfile:

    proper-lockfile does not focus on validation but ensures that the lockfile is written correctly when making modifications. It maintains the lockfile's structure and integrity during read and write operations, reducing the risk of introducing errors.

  • lockfile:

    lockfile does not include any validation features. It simply reads and writes lockfiles without checking their integrity or structure, which means it relies on the developer to ensure the lockfile is correct.

  • lockfile-lint:

    lockfile-lint provides robust validation of lockfiles. It checks for various issues that could affect dependency resolution, such as duplicate package entries, missing version ranges, and incorrect formatting. This makes it a valuable tool for maintaining high-quality lockfiles.

Dependency Modification

  • proper-lockfile:

    proper-lockfile excels at modifying dependencies within the lockfile. It provides APIs for adding, removing, and updating packages, making it a powerful tool for managing dependencies programmatically while ensuring the lockfile remains accurate.

  • lockfile:

    lockfile does not support modifying dependencies directly. It is primarily a read/write utility, so any changes to the lockfile must be done manually or with another tool.

  • lockfile-lint:

    lockfile-lint does not modify dependencies; it only validates the lockfile. It can help identify issues that need to be fixed, but it does not make any changes to the lockfile or the dependencies themselves.

Integration with CI/CD

  • proper-lockfile:

    proper-lockfile can be used in CI/CD pipelines for managing lockfiles, especially when modifications are needed. Its ability to programmatically update the lockfile makes it useful for automated scripts that need to adjust dependencies as part of the build process.

  • lockfile:

    lockfile can be integrated into CI/CD pipelines for basic lockfile operations, such as reading and writing lockfiles during build processes. However, it does not provide any built-in validation or error handling, so additional scripts may be needed to ensure proper usage.

  • lockfile-lint:

    lockfile-lint is highly suitable for CI/CD integration, as it automatically validates lockfiles and reports any issues. This helps catch problems early in the development process and ensures that only clean, validated lockfiles are merged into the codebase.

Ease of Use: Code Examples

  • proper-lockfile:

    Modifying Lockfiles with proper-lockfile

    const properLockfile = require('proper-lockfile');
    
    // Add a dependency
    await properLockfile.add('package-lock.json', 'new-package', '1.0.0');
    
    // Remove a dependency
    await properLockfile.remove('package-lock.json', 'old-package');
    
    // Update a dependency
    await properLockfile.update('package-lock.json', 'existing-package', '2.0.0');
    
  • lockfile:

    Reading and Writing Lockfiles with lockfile

    const lockfile = require('lockfile');
    
    // Read a lockfile
    const data = lockfile.readSync('package-lock.json');
    console.log(data);
    
    // Write a lockfile
    lockfile.writeSync('package-lock.json', data);
    
  • lockfile-lint:

    Validating Lockfiles with lockfile-lint

    const { lint } = require('lockfile-lint');
    
    // Lint a lockfile
    lint({ path: 'package-lock.json' }).then((result) => {
      console.log(result);
    });
    
How to Choose: proper-lockfile vs lockfile vs lockfile-lint
  • proper-lockfile:

    Choose proper-lockfile if you need a robust solution for managing lockfiles with advanced features like adding, removing, and updating dependencies while maintaining the lockfile's structure. It is suitable for larger projects or monorepos where more control over lockfile management is required.

  • lockfile:

    Choose lockfile if you need a lightweight and straightforward tool for reading and writing lockfiles without any additional complexity. It is ideal for simple projects or scripts where you need basic lockfile manipulation.

  • lockfile-lint:

    Choose lockfile-lint if you want to ensure the integrity and consistency of your lockfiles. It is particularly useful for teams and CI/CD pipelines where validating lockfiles before merging changes is important to prevent issues with dependency resolution.

README for proper-lockfile

proper-lockfile

NPM version Downloads Build Status Coverage Status Dependency status Dev Dependency status

An inter-process and inter-machine lockfile utility that works on a local or network file system.

Installation

$ npm install proper-lockfile

Design

There are various ways to achieve file locking.

This library utilizes the mkdir strategy which works atomically on any kind of file system, even network based ones. The lockfile path is based on the file path you are trying to lock by suffixing it with .lock.

When a lock is successfully acquired, the lockfile's mtime (modified time) is periodically updated to prevent staleness. This allows to effectively check if a lock is stale by checking its mtime against a stale threshold. If the update of the mtime fails several times, the lock might be compromised. The mtime is supported in almost every filesystem.

Comparison

This library is similar to lockfile but the latter has some drawbacks:

  • It relies on open with O_EXCL flag which has problems in network file systems. proper-lockfile uses mkdir which doesn't have this issue.

O_EXCL is broken on NFS file systems; programs which rely on it for performing locking tasks will contain a race condition.

  • The lockfile staleness check is done via ctime (creation time) which is unsuitable for long running processes. proper-lockfile constantly updates lockfiles mtime to do proper staleness check.

  • It does not check if the lockfile was compromised which can lead to undesirable situations. proper-lockfile checks the lockfile when updating the mtime.

  • It has a default value of 0 for the stale option which isn't good because any crash or process kill that the package can't handle gracefully will leave the lock active forever.

Compromised

proper-lockfile does not detect cases in which:

  • A lockfile is manually removed and someone else acquires the lock right after
  • Different stale/update values are being used for the same file, possibly causing two locks to be acquired on the same file

proper-lockfile detects cases in which:

  • Updates to the lockfile fail
  • Updates take longer than expected, possibly causing the lock to become stale for a certain amount of time

As you see, the first two are a consequence of bad usage. Technically, it was possible to detect the first two but it would introduce complexity and eventual race conditions.

Usage

.lock(file, [options])

Tries to acquire a lock on file or rejects the promise on error.

If the lock succeeds, a release function is provided that should be called when you want to release the lock. The release function also rejects the promise on error (e.g. when the lock was already compromised).

Available options:

  • stale: Duration in milliseconds in which the lock is considered stale, defaults to 10000 (minimum value is 5000)
  • update: The interval in milliseconds in which the lockfile's mtime will be updated, defaults to stale/2 (minimum value is 1000, maximum value is stale/2)
  • retries: The number of retries or a retry options object, defaults to 0
  • realpath: Resolve symlinks using realpath, defaults to true (note that if true, the file must exist previously)
  • fs: A custom fs to use, defaults to graceful-fs
  • onCompromised: Called if the lock gets compromised, defaults to a function that simply throws the error which will probably cause the process to die
  • lockfilePath: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass file as <dir path> and options.lockfilePath as <dir path>/dir.lock
const lockfile = require('proper-lockfile');

lockfile.lock('some/file')
.then((release) => {
    // Do something while the file is locked

    // Call the provided release function when you're done,
    // which will also return a promise
    return release();
})
.catch((e) => {
    // either lock could not be acquired
    // or releasing it failed
    console.error(e)
});

// Alternatively, you may use lockfile('some/file') directly.

.unlock(file, [options])

Releases a previously acquired lock on file or rejects the promise on error.

Whenever possible you should use the release function instead (as exemplified above). Still there are cases in which it's hard to keep a reference to it around code. In those cases unlock() might be handy.

Available options:

  • realpath: Resolve symlinks using realpath, defaults to true (note that if true, the file must exist previously)
  • fs: A custom fs to use, defaults to graceful-fs
  • lockfilePath: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass file as <dir path> and options.lockfilePath as <dir path>/dir.lock
const lockfile = require('proper-lockfile');

lockfile.lock('some/file')
.then(() => {
    // Do something while the file is locked

    // Later..
    return lockfile.unlock('some/file');
});

.check(file, [options])

Check if the file is locked and its lockfile is not stale, rejects the promise on error.

Available options:

  • stale: Duration in milliseconds in which the lock is considered stale, defaults to 10000 (minimum value is 5000)
  • realpath: Resolve symlinks using realpath, defaults to true (note that if true, the file must exist previously)
  • fs: A custom fs to use, defaults to graceful-fs
  • lockfilePath: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass file as <dir path> and options.lockfilePath as <dir path>/dir.lock
const lockfile = require('proper-lockfile');

lockfile.check('some/file')
.then((isLocked) => {
    // isLocked will be true if 'some/file' is locked, false otherwise
});

.lockSync(file, [options])

Sync version of .lock().
Returns the release function or throws on error.

.unlockSync(file, [options])

Sync version of .unlock().
Throws on error.

.checkSync(file, [options])

Sync version of .check(). Returns a boolean or throws on error.

Graceful exit

proper-lockfile automatically removes locks if the process exits, except if the process is killed with SIGKILL or it crashes due to a VM fatal error (e.g.: out of memory).

Tests

$ npm test
$ npm test -- --watch during development

The test suite is very extensive. There's even a stress test to guarantee exclusiveness of locks.

License

Released under the MIT License.