How it Works
hashup produces a deterministic hash in four steps:
- Resolve the entry file against
baseDir(defaults toprocess.cwd()). - Walk the import graph starting at the entry. Each file is parsed with
es-module-lexerto extract its static imports, which are then resolved withenhanced-resolve— the same resolver Webpack uses. This honorstsconfigpaths, packageexports, conditional exports, and extension resolution. - Hash each file's content (SHA-256). Results are cached per absolute path so a file reachable through multiple paths is hashed once.
- Combine all hashes — the entry's graph plus any
extras— into a single deterministic SHA-256 digest.
Determinism
The final hash depends only on:
- The resolved set of files
- Each file's content
- The order in which hashes are combined (stable for a given graph)
It does not depend on:
- Timestamps
- Absolute paths on disk (only file content)
- The working directory (when
baseDiris explicit)
What Is Not Included
- Type-only imports (
import type) — erased at compile time. - Dynamic imports whose specifier is not a static string literal.
- Files outside the reachable import graph, unless passed via
extras.
If you care about changes in those (e.g. a lockfile determining which package version is installed), pass them explicitly via extras.