stdlib-js / stdlib-js/stdlib

[RFC]: Bringing `resolve` Dependency In-House

Offen
#11,143 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
JavaScript
Sterne
6k
Forks
1.3k
Ø Merge
1 T. 3 Std.
Gemergte PRs (30 T.)
611

Beschreibung

# Replace `resolve` Dependency with In-House `@stdlib/utils/resolve`

Replace the external [`resolve`](https://www.npmjs.com/package/resolve) npm dependency with a new stdlib-native package. This eliminates `resolve` and its **3 transitive dependencies** (`is-core-module`, `path-parse`, `supports-preserve-symlinks-flag`) from the supply chain — removing 4 third-party packages total.

## Background

The `resolve` package implements Node.js's `require.resolve()` algorithm with configurable `basedir` and `paths` options.

Only these features are used:

| Feature | Used? |
|---|---|
| `resolve(id, {basedir}, cb)` (async) | ✅ 5 files |
| `resolve.sync(id, {basedir})` | ✅ 7 files |
| `resolve.sync(id, {basedir, paths})` | ✅ 1 file |
| All other options (`packageFilter`, `pathFilter`, `extensions`, `moduleDirectory`, etc.) | ❌ |

## Proposed Changes

### New Package: `@stdlib/utils/resolve`

#### Folder Structure

```
lib/node_modules/@stdlib/utils/resolve/
├── README.md
├── package.json

├── lib/
│ ├── index.js # Entry point: exports async + .sync
│ ├── main.js # Async resolve( id, opts, clbk )
│ ├── sync.js # Sync resolve( id, opts ) → string
│ ├── validate.js # Options validation
│ ├── defaults.js # Default options (basedir, extensions)
│ ├── resolve_path.js # Core sync resolution algorithm
│ ├── async_resolve_path.js # Core async resolution algorithm
│ └── is_core_module.js # Built-in module check via module.builtinModules

├── docs/
│ ├── repl.txt
│ └── types/
│ ├── index.d.ts
│ └── test.ts

├── benchmark/
│ └── benchmark.js # Performance benchmarks (sync vs async)

├── examples/
│ └── index.js # Usage examples

└── test/
├── test.js # Main export tests
├── test.sync.js # Sync API tests
├── test.async.js # Async API tests
├── test.validate.js # Options validation tests
├── test.is_core_module.js # Core module detection tests
└── fixtures/
├── node_modules/
│ └── mock-pkg/
│ ├── package.json # { "main": "./lib/index.js" }
│ └── lib/
│ └── index.js
├── index.js # Mock directory index
├── foo.js # Mock module
└── foo.json # Mock JSON module
```

#### Key Implementation Details

**`lib/index.js`** — Entry point matching the `resolve` package's API shape:
```js
var resolve = require( './main.js' ); // async
var sync = require( './sync.js' ); // sync
resolve.sync = sync;
module.exports = resolve;
```

**`lib/resolve_path.js`**— Core Node.js resolution algorithm:
1. If `id` is a core module → return `id`
2. If `id` starts with `./` or `../` or `/` → resolve as file, then as directory
3. Otherwise → walk `node_modules` directories upward from `basedir`; if `paths` option given, also search those
4. File resolution: try exact path → `.js` → `.json` → `.node`
5. Directory resolution: read `package.json` `main` field → fallback to `index.js` → `index.json` → `index.node`

**`lib/is_core_module.js`** — Zero-dependency replacement for `is-core-module`:
```js
var builtinModules = require( 'module' ).builtinModules;
function isCoreModule( id ) {
return builtinModules.indexOf( id ) !== -1;
}
```

**Internal dependencies only** — no third-party packages:
- `path` (Node.js built-in)
- `fs` (Node.js built-in)
- `module` (Node.js built-in)
- `@stdlib/assert/is-string` (input validation)
- `@stdlib/assert/is-plain-object` (options validation)
- `@stdlib/assert/has-own-property` (options checking)
- `@stdlib/error/tools/fmtprodmsg` (error formatting)

---

### Consumer Migration (13 files)

Each migration is a 1-line `require` swap. The API shape is identical.

**Sync consumers** (8 files) — `require( 'resolve' ).sync` → `require( '@stdlib/utils/resolve' ).sync`:

| # | File |
|---|---|
| 1 | eslint/require-file-extensions/lib/main.js|
| 2 | modules/pkg-deps/lib/walk_file.sync.js |
| 3 | pkgs/browser-compatible/lib/resolve.sync.js |
| 4 | pkgs/entry-points/lib/resolve.sync.js|
| 5 | pkgs/browser-entry-points/lib/resolve.sync.js |
| 6 | utils/library-manifest/lib/main.js |
| 7 | repl/help/scripts/build.js |

**Async consumers** (6 files) — `require( 'resolve' )` → `require( '@stdlib/utils/resolve' )`:

| # | File |
|---|---|
| 8 | modules/pkg-deps/lib/walk_file.js |
| 9 | modules/pkg-deps/test/test.walk_file.js *(also update `proxyquire` mock key)* |
| 10 | pkgs/browser-compatible/lib/resolve.js|
| 11 | pkgs/entry-points/lib/resolve.js|
| 12 | pkgs/browser-entry-points/lib/resolve.js|
| 13 | lint/namespace-aliases/lib/resolve.js|

---

### Dependency Removal
```
npm uninstall resolve
```
---

## Verification Plan

### Automated Tests

stdlib uses `make test`:

* Run new package tests using stdlib's test infrastructure:

```bash
make EXAMPLES_FILTER=".*/utils/resolve/.*"" examples

make BENCHMARKS_FILTER=".*/utils/resolve/.*"" benchmark

make TESTS_FILTER=". */utils/resolve/.*"" test
```
* Run consumer regression tests (pkg-deps has the most extensive test suite):

```
make TESTS_FILTER=". */_tools/modules/pkg-deps/.*"" test
```

### Manual Verification
{TODO}

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Beginne mit der Überprüfung der vorgeschlagenen Struktur von @stdlib/utils/resolve und untersuche anschließend die aufgeführten resolve-Verbraucher, insbesondere modules/pkg-deps und dessen test/test.walk_file.js. Führe die vorhandenen Verbrauchertests aus, bevor du Abhängigkeiten änderst, füge dann die Pakettests hinzu und migriere die aufgeführten Imports. Als erledigt gilt die Aufgabe, wenn die Regressionstests bestehen und resolve sowie seine transitiven Abhängigkeiten entfernt wurden; die manuelle Überprüfung ist weiterhin als TODO markiert.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
javascript, node.js
Bereich
backend, tooling
Issue-Typ
Refactoring
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Ruhig
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.