Skip to content

fix: bundled npm compile output naming#35459

Open
nathanwhitbot wants to merge 6 commits into
denoland:mainfrom
nathanwhitbot:orcha/impl-7bc2eb20
Open

fix: bundled npm compile output naming#35459
nathanwhitbot wants to merge 6 commits into
denoland:mainfrom
nathanwhitbot:orcha/impl-7bc2eb20

Conversation

@nathanwhitbot

Copy link
Copy Markdown
Contributor

Summary

  • Preserve the original compile source specifier for output name inference when deno compile --bundle rewrites the entrypoint to a temporary bundle file
  • Add coverage for bundled npm entrypoint name inference so scoped npm packages use the package/bin-derived name instead of .deno_compile_bundle_*
  • Keep pure bundled npm output free of node_modules embedding while preserving existing bundle/runtime npm coverage

Validation

  • Focused compile/bundle tests and targeted Rust tests were run by the implementer; see worker report for exact commands and caveats.

@nathanwhitbot nathanwhitbot changed the title Fix bundled npm compile output naming fix: bundled npm compile output naming Jun 23, 2026
@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up commit adding the required reason to the #[allow(dead_code)] in cli/tools/compile.rs, which fixes the clippy allow_attributes_without_reason lint failure. Also retitled the PR to fix: bundled npm compile output naming so the title lint passes.

@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Pushed fix: serialize workflow lint generators to address the lint failure. The workflow YAML lint check now runs generator scripts sequentially, avoiding the Windows Deno cache race seen when multiple generator processes fetched/read the same JSR dependencies concurrently.

@bartlomieju bartlomieju left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff plus how needs_npm_embed flows into the binary writer. The naming fix itself is clean and well-tested, but the needs_npm_embed change looks like it can drop npm embedding for managed-npm bundles. Flagging as a comment rather than approving.

🔴 path_is_in_node_modules misses managed-npm (global cache) paths

run_bundle_for_compile now sets needs_npm_embed only when a referenced path contains a literal node_modules component (cli/tools/compile.rs:319-322, 345-348, helper at :528), replacing the old main_rewrite.rewrote_paths.

But for managed npm without a node_modules dir (the default), packages resolve from the global cache:

<DENO_DIR>/npm/registry.npmjs.org/<name>/<version>/...

— no node_modules segment. This is exactly why pkg_folder_node_modules_root() has the .unwrap_or(folder.as_path()) fallback in cli/standalone/binary.rs:1258.

So a bundle whose CJS-from-ESM wrapper require()s an npm package resolved from the global cache now computes needs_npm_embed = false and silently skips npm embedding → runtime require() failure. The old rewrote_paths flag fired for these and embedded correctly. This is the headline deno compile --bundle npm:<pkg> flow (no package.json).

Why the existing tests don't catch it: cjs_import_from_esm, native_addon, and cjs_deep_graph all ship a package.json, which auto-enables a node_modules dir, so their referenced paths do contain node_modules. The new npm_entrypoint_default_name test uses a pure-JS package (correctly no embed). Nothing exercises the global-cache + external-require combination.

Suggested fix: decide embedding based on whether a referenced path maps to an npm package (reuse the resolver / npm-cache-root logic already in collect_bundle_required_packages), not a literal node_modules string match — and add a test for compile --bundle npm:<cjs-or-native-pkg> with no node_modules dir.

nit: duplicated logic

path_is_in_node_modules (cli/tools/compile.rs:528) duplicates the inline path.components().any(|c| c.as_os_str() == "node_modules") at cli/tools/compile.rs:247-248. Use the helper in both places. (Note that inline check shares the same global-cache blind spot when deciding whether to add a path to the include set, though that part is pre-existing.)

nit: scope — tools/lint.js

Serializing the workflow YAML generators is unrelated to compile output naming and touches CI tooling. Fine if it's needed to unblock CI, but per repo convention CI tooling changes usually want @bartlomieju's review, and this could be a separate PR.

Other

  • CI: no checks are visible yet — please confirm the compile/bundle spec suite is green across all OSes before merge.
  • The #[allow(dead_code, reason = ...)] on rewrote_paths (now read only by unit tests) is appropriately justified. 👍

Nice work on the inference plumbing and the unit + spec coverage for the naming case.

@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Addressed the managed-npm global-cache case: referenced bundle paths are now classified through the npm resolver instead of only checking for a node_modules path component, and the include filtering uses the same classification. I also added a no-package.json compile --bundle npm:@denotest/esm-import-cjs-default regression spec and reverted the unrelated tools/lint.js workflow serialization change out of this PR.

@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up formatting fix for cli/standalone/native_addons.rs; the failed Linux lint job was dprint rejecting the new resolve_bundle_npm_referenced_paths expression layout.

@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up fix after rebasing onto latest main: added the missing app_name field to the bundled npm compile test initializer and boxed the enlarged compile() future at the two clippy-reported call sites.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants