Skip to content

Improve cache hit rate by normalizing requests to their containing package #449

@dmichon-msft

Description

@dmichon-msft

Within the boundary of a npm package (defined as being in a subpath of a folder containing a package.json), barring exotic circumstances, the following types of module resolution are invariant to the requesting file's relativePath from the descriptionFileRoot:

  1. Absolute paths. These may only be altered by alias or other plugins, and are generally unaffected by the requesting package at all.
  2. Bare specifiers, e.g. react, @nodelib/fs.scandir. These are only impacted by the presence of node_modules folders, which no normal package manager will create in subfolders of a package without there being a nested package.json. As such, resolution can ignore the relativePath component of the requesting file.
  3. Imports that map through the package.json imports field via ala #some/request. These do not provide any means for the relativePath component of the requesting file to impact resolution.
  4. A relative import ../foo from a/bar is exactly the same as a relative import ./foo from a.

Based on the above, we can optimize the caching layer for resolution requests as follows:

  1. Assume that a cache key contains internal, path, request, query, fragment (there may be other fields that it still splits on, but these are generally the majority of the differentiation)
  2. If the request is a relative path, update request = joinRelativePreservingLeadingDot(relativePath, request)
  3. Set path = descriptionFileRoot in the cache key in all cases

Testing in a large local project, this mapping reduced the number of unique requests seen by the resolver by about 33%, which both reduces the size of the cache and improves the cache hit rate.

This optimization is particularly relevant for packages that contain a lot of subfolders.

One can further optimize the cache hit rate by having a cache layer and performing request normalization any time the descriptionFileRoot property of the request object changes, for example upon resolving the request to a target package.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions