Skip to content

fix: prefer search paths over parent-relative node_modules walk#224

Open
benpalevsky wants to merge 1 commit into
godotjs:mainfrom
hatgg:4-resolver-search-path
Open

fix: prefer search paths over parent-relative node_modules walk#224
benpalevsky wants to merge 1 commit into
godotjs:mainfrom
hatgg:4-resolver-search-path

Conversation

@benpalevsky

Copy link
Copy Markdown
Contributor

Problem

When your code imports a bare package name — like require("immer") — GodotJS has to figure out which file that means. It has two ways to look:

  1. The configured search paths (for example res://.godot/GodotJS/), where clean, pre-bundled copies of dependencies live.
  2. A node_modules walk up the folder tree, the way Node.js resolves packages. With Bun/pnpm symlinks, this lands on the raw npm package.

The old code tried the node_modules walk first. So require("immer") found the raw npm file node_modules/immer/dist/cjs/index.js, whose first real statement checks process.env.NODE_ENV. There is no process in the GodotJS runtime, so it broke. The clean pre-bundled copy at .godot/GodotJS/immer.js (which Bun had already processed to strip out the process references) was sitting right there on a search path, but it never got the chance to win.

What this changes

Flip the order: try the search paths first, and only fall back to the parent-relative node_modules walk if the search paths don't have the module. Note that res://node_modules is itself the last configured search path, so a hoisted root node_modules package still resolves when no curated bundle exists; the parent-relative walk now only matters for nested (non-hoisted) node_modules directories, which consequently no longer shadow a same-named module sitting on a search path.

Relationship to the recent recursion fix

This is built on top of upstream's recent fix for "default (index.js) module resolution infinite recursion." That fix lives in a different file (the module resolver) and is reached the same way no matter which lookup runs first, so reordering the two lookups does not weaken it. Verified directly: the recursion guard is untouched, and a package directory with no exports/main field still falls through to its index.js exactly as before.

How to verify

Rebuild, then run a project headless (godot --headless --path <project>) where a script does require("<dep>") and both res://.godot/GodotJS/<dep>.js and node_modules/<dep> exist; confirm the curated bundle loads (no process is not defined). Also confirm a directory import of an exports-less package still resolves to its index.js without hanging.

A changeset is included.

For bare module specifiers, try `find_module_resolver(normalized_id)`
(which iterates the configured search paths) before the parent-relative
node_modules chain walk. The walk remains as a fallback for non-hoisted
pnpm/yarn layouts where a curated `.godot/GodotJS/<dep>.js` bundle isn't
present.

Without this, `require("immer")` resolved via the Bun symlink chain to
`node_modules/immer/dist/cjs/index.js`, whose first real statement is
`if (process.env.NODE_ENV === 'production')` — undefined in our runtime.
The pre-bundled `.godot/GodotJS/immer.js` (which Bun processed to strip
`process` references) was reachable via search path 1
(`res://.godot/GodotJS`) but never won the resolution race.

Reconciled on top of a8e2567 ("fix: default (index.js) module resolution
infinite recursion"). That fix lives entirely in
bridge/jsb_module_resolver.cpp (check_package_file_path, the empty
p_module_id guard), reached identically via find_module_resolver from
both the search-path lookup and the node_modules walk in
bridge/jsb_environment.cpp. Reordering the two find_module_resolver calls
does not bypass or weaken the recursion guard: any exports-less package
root lookup still returns false and lets check_absolute_file_path fall
through to the explicit module_id/index.js probe.
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.

1 participant