feat: add --fallback-to-source flag for bytecode failures#246
Merged
robertsLando merged 3 commits intomainfrom Apr 17, 2026
Merged
feat: add --fallback-to-source flag for bytecode failures#246robertsLando merged 3 commits intomainfrom
robertsLando merged 3 commits intomainfrom
Conversation
The automatic fallback to source introduced in 46a7f8e shipped plain source whenever V8 bytecode fabrication failed, without the user explicitly opting in. This moves that behaviour behind a new --fallback-to-source flag. Default (no flag): warn about the failure, mention --fallback-to-source in the warning, and skip the file. The empty VFS key is cleaned up so the prelude no longer hits "Error: UNEXPECTED-20" (#87, #181). With --fallback-to-source: ship the file as plain source (previous automatic behaviour). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Default (no --fallback-to-source): warn, mark the stripe as skipped, and emit a zero-byte buffer — identical to the pre-46a7f8e behaviour. If the file is required at runtime the prelude now throws a descriptive UNEXPECTED-20 error naming the file and suggesting --fallback-to-source, --no-bytecode, or --sea. test-50-extensions needs source at runtime during cross-compile so it now passes --fallback-to-source explicitly. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The walker emits both STORE_BLOB and STORE_CONTENT stripes for public files (lib/walker.ts:987-1003), so when bytecode fabrication fails the source is still available at runtime. No --fallback-to-source needed. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR adds a new --fallback-to-source CLI flag to control what happens when V8 bytecode generation fails during packaging (commonly in cross-compilation scenarios). The intent is to make the default behavior “warn and skip the file” (instead of silently falling back to shipping source), while preserving the prior fallback behavior when the flag is explicitly enabled.
Changes:
- Add
--fallback-to-sourceto CLI parsing and help output, and plumb the option into the producer pipeline. - Change bytecode fabrication failure handling to either (a) ship plaintext source (flag enabled) or (b) warn and skip the file (default).
- Update docs to describe the new flag and recommended mitigations; update an existing test to pass the new flag.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
lib/index.ts |
Adds the new boolean CLI flag and passes it into producer() options. |
lib/producer.ts |
Implements flag-driven behavior on bytecode fabrication failures; introduces Stripe.skip. |
lib/packer.ts |
Extends Stripe type with optional skip metadata. |
prelude/bootstrap.js |
Improves the runtime error message when a VFS entry has neither source nor bytecode. |
lib/help.ts |
Documents the new flag in pkg --help output. |
test/test-50-extensions/main.js |
Updates an existing integration test invocation to include --fallback-to-source. |
docs-site/guide/targets.md |
Adds “fallback to source” as an option in cross-compilation guidance. |
docs-site/guide/getting-started.md |
Adds the flag to the CLI reference table. |
docs-site/guide/bytecode.md |
Adds a new section documenting fallback-to-source behavior. |
Comments suppressed due to low confidence (1)
lib/producer.ts:455
- The new
skipmechanism only prevents recording the previous stripe’s payload range, but the VFS key is still pre-created earlier and other stripes for the samesnap(notablySTORE_STAT) will still be recorded. This leaves a VFS entry thatexistsSync/statSyncconsiders present, butreadFileSynclater fails with UNEXPECTED-20. To truly “skip the file”, ensure no VFS entry (and noSTORE_STAT) is emitted for that snap—e.g., build VFS entries lazily when adding a store, and/or track skipped snaps and suppress all subsequent stripes for them (and delete any pre-created VFS key).
if (count === 2) {
if (prevStripe && !prevStripe.skip) {
const { store } = prevStripe;
let { snap } = prevStripe;
snap = snapshotify(snap, slash);
const vfsKey = makeKey(doCompress, snap, slash);
vfs[vfsKey][store] = [track, meter.bytes];
track += meter.bytes;
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--fallback-to-sourceCLI flag--fallback-to-sourcein the warning, and skips the file. The empty VFS key is cleaned up so the prelude no longer crashes withUNEXPECTED-20(NodeJS 22/24 issues/feedbacks tracker #87, Cross-compilation from macOS to Linux on arm64 broken on >=22 #181)--fallback-to-source: ships the file as plain source instead of skipping it (the behaviour from 46a7f8e)Test plan
--fallback-to-source→ verify warning is logged with flag hint and file is skipped (no UNEXPECTED-20 crash)--fallback-to-source→ verify warning is logged and file is shipped as plain sourcepkg --helpshows the new flag🤖 Generated with Claude Code