evanw / evanw/esbuild

FR: Walk directories in leaf -> root order

Open
#4,036 2 comments 0 reactions 0 assignees View on GitHub
unactionable
Dominant language
Go
Stars
40.1k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Description

## Problem

During the build process, esbuild walks the directory hierarchy, looking for `package.json` files along the way (in [resolver.go]). For reasons explained below, there are two problems with the current arrangement:

1. **The traversal happens in root -> leaf order.** If it's being run in `/Volumes/src/my-project/my-package`, then it'll read:
1. `/package.json` (if it exists)
2. `/Volumes/package.json` (if it exists)
3. `/Volumes/src/package.json` (if it exists)
4. `/Volumes/src/my-project/package.json` (if it exists)
5. `/Volumes/src/my-project/my-package/package.json` (if it exists)
2. **There's no way to stop the traversal.** Other projects provide a way to designate a known "root", to prevent higher traversal.
- ESLint, for example, provides a `root: true` [configuration option][root: true]

This setup creates a problem for us. Our project exists within a monorepo, and we're building with [BuildXL]. We're working to enable the `enforceSourceReadsUnderPackageRoots` [configuration option][source-reads] build flag, which prevents processes from reading outside of their declared dependency tree.

## Proposal

The proposal is to invert the logic: read from the leaf down. Along the way, the process could be aborted with a similar mechanism to indicate "this is the root, please stop traversing" to ESLint.

This pattern has other precedence in configuration of other projects in the JS ecosystem.

## Workarounds

Our current workaround is to add our top-level `package.json` to the allow-list of files which can be read outside of the declared dependencies. This is suboptimal, since it opens up the window for _other_ processes to read the file when they shouldn't.

[resolver.go]:
https://github.com/evanw/esbuild/blob/df815ac27b84f8b34374c9182a93c94718f8a630/internal/resolver/resolver.go#L1585-L1596
[root: true]:
https://archive.eslint.org/docs/7.0.0/user-guide/configuring#:~:text=ESLint%20will%20stop%20looking%20in%20parent%20folders%20once%20it%20finds%20a%20configuration%20with%20%22root%22%3A%20true.
[buildxl]:
https://github.com/microsoft/BuildXL
[source-reads]:
https://github.com/microsoft/BuildXL/blob/main/Documentation/Wiki/Frontends/js-misc-options.md#enforcesourcereadsunderpackageroots-boolean

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the directory traversal in internal/resolver/resolver.go at the linked lines, then review how package.json files are discovered during resolution. The change is complete when traversal proceeds from the leaf toward the root and provides a way to stop at a designated project root; add or update coverage for both behaviors if the resolver has corresponding tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, javascript
Domain
build-system, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.