Skip to content

perf(web): use hash-wasm SHA-1 with pure-JS fallback for upload hashing#30107

Open
mosh-dev wants to merge 4 commits into
immich-app:mainfrom
mosh-dev:feat/wasm-sha1-hashing
Open

perf(web): use hash-wasm SHA-1 with pure-JS fallback for upload hashing#30107
mosh-dev wants to merge 4 commits into
immich-app:mainfrom
mosh-dev:feat/wasm-sha1-hashing

Conversation

@mosh-dev

Copy link
Copy Markdown

Description

File upload hashing in the web client currently runs SHA-1 entirely in pure JS (@noble/hashes) inside a Web Worker. This is a CPU-bound bottleneck for large file uploads, since JS-implemented SHA-1 is slower than a compiled/WASM implementation.

This PR adds a WebAssembly-accelerated SHA-1 path using hash-wasm, which is tried first. If WebAssembly is unsupported in the runtime, or the WASM path throws for any reason, hashing falls back to the existing pure-JS @noble/hashes implementation, so correctness and browser compatibility are preserved.

Benchmarked ~1.68x faster (on Intel 13th Gen 13650HX hardware) than the pure-JS path on large files, with identical hash output between the two implementations.

I'm a personal Immich user. A recent update's slower hashing made me curious whether I could improve it, so I looked into this and thought it might be a good speed boost. Please feel free to reject this pull request if there are any major concerns, and I'm happy to discuss further if any clarification is needed.

Fixes # (issue)

How Has This Been Tested?

Added web/src/lib/workers/hash-file.spec.ts covering:

  • hashFileJs produces the correct known SHA-1 hex digest for a fixed input
  • hashFileWasm produces the correct known SHA-1 hex digest for the same input
  • hashFileWasm and hashFileJs produce identical output across a range of file sizes (0, 1, 1024, 10000 bytes)
  • hashFile falls back to the JS implementation when the WASM path throws (mocked hash-wasm rejection)
  • hashFile uses the WASM path when available and matches the JS output

Checklist:

  • I have carefully read CONTRIBUTING.md
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation if applicable
  • I have no unrelated changes in the PR.
  • I have confirmed that any new dependencies are strictly necessary.
  • I have written tests for new code (if applicable)
  • I have followed naming conventions/patterns in the surrounding code
  • All code in src/services/ uses repositories implementations for database calls, filesystem operations, etc.
  • All code in src/repositories/ is pretty basic/simple and does not have any immich specific logic (that belongs in src/services/)

Please describe to which degree, if any, an LLM was used in creating this pull request.

This utility function was previously implemented, tested in production, and used inside a web worker for another project that's still in production. I asked the LLM (Claude Code) to reuse that function for this change. Claude Code wrote the spec file and ran the tests; the WebAssembly-support detection/fallback logic is hand-written by me and tested across different browsers. I reviewed the diff, understand the change, and take responsibility for it.

Adds a WebAssembly-accelerated SHA-1 path (hash-wasm) for hashing files during
upload, tried first and falling back to the existing @noble/hashes pure-JS
implementation if the WASM path throws for any reason. Benchmarked ~1.68x
faster than the pure-JS path on large files, with identical hash output
between the two.
@mosh-dev
mosh-dev requested a review from danieldietzler as a code owner July 21, 2026 14:37
@immich-push-o-matic

immich-push-o-matic Bot commented Jul 21, 2026

Copy link
Copy Markdown

Label error. Requires exactly 1 of: changelog:.*. Found: 🖥️web. A maintainer will add the required label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant