forked from vercel/pkg
-
-
Notifications
You must be signed in to change notification settings - Fork 61
Permalink
Choose a base ref
{{ refName }}
default
Choose a head ref
{{ refName }}
default
Comparing changes
Choose two branches to see what’s changed or to start a new pull request.
If you need to, you can also or
learn more about diff comparisons.
Open a pull request
Create a new pull request by comparing changes across two branches. If you need to, you can also .
Learn more about diff comparisons here.
base repository: yao-pkg/pkg
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v6.16.0
Could not load branches
Nothing to show
Loading
Could not load tags
Nothing to show
{{ refName }}
default
Loading
...
head repository: yao-pkg/pkg
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v6.17.0
Could not load branches
Nothing to show
Loading
Could not load tags
Nothing to show
{{ refName }}
default
Loading
- 3 commits
- 25 files changed
- 3 contributors
Commits on Apr 18, 2026
-
docs: add in-depth comparison vs Bun and Deno (#249)
Adds docs-site/guide/vs-bun-deno.md covering native addon support, bundle format, cross-compile, bytecode, binary size, plus a real @anthropic-ai/claude-code bundling case study across all three tools. Includes a self-critical verdict section to prevent the page from reading as marketing. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 0cf75a8 - Browse repository at this point
Copy the full SHA 0cf75a8View commit details -
feat(sea): add per-file compression to SEA archive (closes #250) (#251)
* feat(sea): add per-file compression to SEA archive (--compress Brotli/GZip/Zstd) Extends the existing --compress flag to enhanced SEA mode, matching what Standard mode has had for years. Each file in the SEA archive is compressed independently with gzip / brotli / zstd and decompressed lazily at first fs.readFileSync() / require(), so the cold-start cost is proportional to the files actually read — not the full archive. Measured on claude-code@1.0.100 (node22-linux-x64): 194 MB → 152 MB with --compress Zstd (41 MB saved, no measurable startup regression), and 194 MB → 147 MB with --compress Brotli (~3 min build). Closes most of the size gap between SEA-mode binaries and competitors like Bun. - lib/compress_type.ts: add Zstd = 3 - lib/index.ts: accept "Zstd"/"zs" at --compress; refuse --compress for simple SEA mode (no walker → nothing to compress) - lib/producer.ts: wire Zstd compressor into Standard-mode producer too, so the flag is consistent across modes - lib/sea-assets.ts: compress each entry during archive write; record manifest.compression = numeric CompressType; keep stats[key].size as the uncompressed length so fs.statSync() reports the real file size - lib/sea.ts, lib/types.ts: thread doCompress through seaEnhanced() - prelude/bootstrap.js: add Zstd branch to payloadFile/payloadFileSync - prelude/sea-vfs-setup.js: pick a decompressor once at SEAProvider construction; decompress on first read, cache the result in _fileCache - test/test-93-sea-compress: build the same fixture with None/GZip/ Brotli/Zstd (Zstd gated on zlib.zstdCompressSync availability) and assert every packaged binary prints identical output - docs: update compression.md, sea-mode.md, sea-vs-standard.md, ARCHITECTURE.md, and vs-bun-deno.md with the new feature and the re-measured claude-code numbers Closes #250 * docs(vs-bun-deno): note trimmed-Node build as a path to further shrink SEA binaries Binary-size gap to Bun isn't all archive — ~30 MB of the remaining delta is full-ICU in the stock Node binary pkg-fetch ships. Spell out that ./configure --without-intl --without-inspector --without-npm --without-corepack --fully-static (a pkg-fetch concern, not a pkg one) would close most of what's left. * docs(vs-bun-deno): update startup times with fresh first-run measurements Re-ran all four pkg --sea variants on the same host with consistent methodology (first-run, cold ~/.cache/pkg, /usr/bin/time -f %e for ./binary --version). Bun/Deno rows are unchanged from the morning run. - None: 979 → 610 ms - GZip: 590 ms (new) - Zstd: 560 ms (new) - Brotli: 590 ms (new) Compression adds ≤0 ms vs uncompressed on this workload because claude-code's --version path only touches a handful of files, so the sync zlib/zstd decode cost is dwarfed by the startup savings from the smaller archive being memory-mapped. * docs(vs-bun-deno): re-measure all three runtimes side by side Ran pkg --sea (4 codecs), bun --compile, bun --compile --bytecode, and deno compile on the same host with matching methodology (fresh fixture, cold ~/.cache/pkg, /usr/bin/time -f %e for ./bin --version first run): Bun 510 ms (108 MB) Bun --bytecode 530 ms (190 MB) pkg --sea 560 ms (194 MB) pkg --sea --zstd 570 ms (152 MB) pkg --sea --gzip 580 ms (154 MB) pkg --sea --brotli 590 ms (147 MB) Deno 740 ms (183 MB) The previous numbers (797 Bun / 1256 Deno / 979 pkg) were measured on a different run/method, not apples-to-apples. These six are. Bun is still fastest and smallest; pkg SEA with compression is within ~60 ms of Bun while shipping stock Node.js; Deno is the slowest starter on this workload. Narrative paragraphs updated to match. * refactor(sea): harden compression paths, unify codec picker, restore streaming Security / correctness: - prelude/sea-vfs-setup.js: cap per-file decompression via maxOutputLength and assert decompressed length matches manifest stats.size; use Number.isInteger for offset/length/size bounds (rejects NaN and non-integer floats that the prior typeof-number guard let through). - lib/sea-assets.ts: synthesize a stats entry for records that had STORE_CONTENT but no STORE_STAT, so every compressed stripe has an authoritative size for the runtime to cross-check against. Make resolveCompressor exhaustive — a new CompressType without a matching case now fails the build instead of shipping an archive that claims compression but contains raw bytes. Performance: - lib/sea-assets.ts: restore createReadStream path for unmodified disk-resident files; the prior always-readFileAsync forced peak RSS to grow with total asset size even when compression was disabled. - Resolve the decompressor/compressor exactly once per path: at module load in prelude/bootstrap.js, at SEAProvider construction in sea-vfs-setup.js, before the stripe loop in sea-assets.ts, and before Multistream in producer.ts. Fails fast when the runtime is missing a Zstd API instead of mid-stripe. Skips _fileCache entirely for uncompressed archives so archive subarrays aren't pinned unnecessarily. DRY / surface: - prelude/bootstrap-shared.js: single source of truth for COMPRESS_* constants, pickDecompressorSync/Async, and a context-aware zstdMissingError (build-host vs end-user remediation). Classical bootstrap and SEA VFS both consume it; the local zlib require in bootstrap.js is gone. - lib/compress_type.ts: getZstdCompressSync / getZstdCompressStream replace the duplicated 'zlib as unknown as { ... }' casts in producer.ts and sea-assets.ts and emit a single build-error string (now also includes process.version). - lib/help.ts: add Zstd to the --compress description and examples. - lib/index.ts: the 'invalid compression algorithm' error now lists the real accepted tokens (None/none, Brotli/br, GZip/gz/gzip, Zstd/zs/zstd); the compression banner goes through log.info instead of console.log. Tests: - test/test-93-sea-compress: assert each compressed binary is at least 50 KB smaller than the None build so a silent fallback to uncompressed fails the test (the prior byte-equality check couldn't detect that regression). - test/test-80-compression: cover --compress Zstd in the classical pipeline (lib/producer.ts and prelude/bootstrap.js zstd branches) when zlib.createZstdCompress is available on the build host. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(sea): prune dead code and optimize VFS hot paths Dead code: - Drop SeaAssetsResult.entryIsESM — seaEnhanced destructures only { assets, manifestPath } and the value is read via manifest.entryIsESM at runtime, so the return-shape field was carrying a stale copy. - Drop the 'syscall' parameter from SEAProvider._resolveSymlink: all five callers pass only the path, and ELOOP is rare enough that hardcoding err.syscall = 'stat' is fine. - Drop the 'context' parameter from pickDecompressorSync/Async and merge zstdMissingError into a single runtime-wording string: only 'runtime' was ever passed (build-side Zstd errors go through lib/compress_type.ts's own zstdBuildError). - Drop unused COMPRESS_GZIP/BROTLI/ZSTD exports from bootstrap-shared — callers now go through pickDecompressor and only COMPRESS_NONE is read directly by sea-vfs-setup. - Remove the redundant process.argv[1] = entrypoint assignment in sea-bootstrap.js; sea-bootstrap-core.js already sets it to the same value. - Inline the single-use ZSTD_MISSING_BUILD_REMEDIATION constant. Hot paths (~30K lookups per startup on large projects): - toManifestKey: skip the backslash→slash regex on POSIX hosts where paths already match the manifest shape; keep the replace on win32 where it's mandatory. - _resolveSymlink: short-circuit before entering the MAX_SYMLINK_DEPTH loop when the path isn't a symlink key (the common case). Comments: - sea-assets.ts: rename the Zstd-resolution rationale to point at zstdBuildError, which is where the wording now lives. - bootstrap-shared.js: tighten the COMPRESS_NONE comment now that only it is exported. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(sea-compress): fix Windows CI failure from CRLF in payload.txt Root cause: payload.txt starts with 0x0a; on a Windows checkout git's autocrlf converted it to 0x0d 0x0a, so PAYLOAD.slice(0, 32) contained a leading \r\n that survived in `expected` but got stripped from `actual` via the existing replace(/\r\n/g, '\n'), causing the equality assertion to fail across every Windows job. Fix: - Add .gitattributes so payload.txt is checked out LF on every platform; the SEA archive bytes are now deterministic cross-platform, which also keeps the compressed-size assertion stable. - Normalize CRLF in `expected` as defense-in-depth so an existing Windows clone (cloned before .gitattributes landed) still passes the test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(sea): drop redundant post-decompress size assert Per review feedback on PR #251: an attacker who can rewrite the SEA blob can also rewrite `manifest.stats[p].size` to match the payload they ship, so the post-decompression `buf.length === expected` check does not survive a consistent tamper — it only fires on accidental corruption, which is a narrow and unlikely case. Keep `maxOutputLength`: it bounds the zlib allocation up front so a blob with a plausible-but-inflated manifest can't request unbounded memory before we discover the size mismatch. That bound is cheap and standard Node zlib hygiene. Also keep the `stats.size` validation: `maxOutputLength` requires a finite integer, so NaN / negative / missing values must still be rejected before reaching zlib. Tightened the comment to reflect the actual threat model (bounded allocation vs. tamper detection) instead of the earlier bomb-defense framing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for fdf8046 - Browse repository at this point
Copy the full SHA fdf8046View commit details -
Configuration menu - View commit details
-
Copy full SHA for eca804e - Browse repository at this point
Copy the full SHA eca804eView commit details
Loading
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v6.16.0...v6.17.0