Skip to content

JS: Overhaul import resolution #19391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: main
Choose a base branch
from

Conversation

asgerf
Copy link
Contributor

@asgerf asgerf commented Apr 28, 2025

Updates JS import resolution to avoid depending on the TypeScript compiler, which ultimately led to a completely rewrite of import resolution.

Deprecating PathExpr

This PR deprecates PathExpr, PathString, and Path, in favor of the parameterised modules Folder::Resolve and ResolveExpr and extended models of tsconfig.json and package.json files.

PathExpr tried to represent multiple things simultaneously:

  • expressions that we need to resolve as a path
  • expressions that we need to constant-fold
  • expressions that we're able to constant-fold

The new implementation has a clear separation between these and can do more powerful constant folding as a result.

The old abstraction also could not properly support path mapping. It had a concept of "search root" but assumed that the value to resolve did not depend on the search root, which is not true for mappings like @/* -> src/*, where the @/ prefix must be chopped off.

It also forced all path-resolution logic to happen within a single layer, which complicated library models that need import resolution (Angular). Attempts to refactor things often led to negative recursion due to the Angular model. Parameterised modules don't have this problem as any model can resolve whatever paths they need in the layer they need it.

Evaluation

Evaluation shows neutral performance and about 5k new import edges, and about 30k new call edges, and a few lost imports and call as well.

The alert changes aren't so interesting. Some results were gained in a copy of jQuery, and two alerts were lost as we lost a library input, but not one that seemed likely to be user-controlled.

Review notes

Commit-by-commit view is strongly recommended.

A bunch of unit tests are added in a single commit. The annotations initially represent what we resolve using the baseline implementation (relying on the TypeScript compiler) and you may not want to worry too much about whether those initial annotation are correct; they just represent the baseline.

@github-actions github-actions bot added the JS label Apr 28, 2025
Comment on lines +4 to +6
/**
* Extension of `PackageJson` with some internal path-resolution predicates.
*/

Check warning

Code scanning / CodeQL

Class QLDoc style. Warning

The QLDoc for a class should start with 'A', 'An', or 'The'.
@asgerf asgerf force-pushed the js/typescript-path-resolution branch 5 times, most recently from 82b8d58 to 56deae6 Compare April 28, 2025 13:27
@asgerf asgerf force-pushed the js/typescript-path-resolution branch from 56deae6 to 7a81e48 Compare April 29, 2025 07:43
@asgerf asgerf force-pushed the js/typescript-path-resolution branch from 7a81e48 to c008ba4 Compare April 29, 2025 10:54
@asgerf asgerf force-pushed the js/typescript-path-resolution branch from c008ba4 to 9ae6d8b Compare April 29, 2025 11:12
asgerf added 7 commits April 29, 2025 13:23
This moves the test for the babel `root-import` plugin into the new
unit test for import resolution, so we only have one set of tests to
maintain.

The actual implementation is added in the next commit.
To avoid negative recursion in some upcoming changes, we want to make sure the modeling of createRequire does not depend on getImportedPath().
@asgerf asgerf force-pushed the js/typescript-path-resolution branch from 9ae6d8b to 620ce66 Compare April 29, 2025 11:24
@asgerf asgerf changed the title JS: Update import resolution JS: Overhaul import resolution Apr 29, 2025
asgerf added 4 commits April 29, 2025 16:06
path.resolve() and template expressions are now working.

Previously they could not be resolved because Import.getImportedPath() returned a PathExpr,
and these were not instances of PathExpr.
… name clash

'getTargetFile' was originally named to avoid the clash with 'getImportedFile' from a subclass. But we now just merge the two predicates.
We don't extract node_modules folders by default so these tests aren't
that relevant anymore, and we no longer follow node_modules resolution
rules directly.

Instead, these imports are resolved based on the monorepo support which
simply requires a package.json file to exist. There is not a good enough
reason to support node_modules directly, so we're accepting some
minor regression in these tests.
@asgerf asgerf force-pushed the js/typescript-path-resolution branch from 620ce66 to b0f73f1 Compare April 29, 2025 14:06
@asgerf asgerf marked this pull request as ready for review April 29, 2025 14:29
@asgerf asgerf requested a review from a team as a code owner April 29, 2025 14:29
@asgerf asgerf added the no-change-note-required This PR does not need a change note label Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JS no-change-note-required This PR does not need a change note
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant