or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-resolution.mdcustom-resolvers.mderror-handling.mdindex.mdpackage-resolution.mdresolution-context.mdresolution-engine.md

package-resolution.mddocs/

0

# Package Resolution

1

2

Advanced package resolution supporting modern Node.js features like package.json exports/imports fields, conditional exports, and legacy browser field specifications. Handles both standard npm packages and complex multi-entry packages.

3

4

## Capabilities

5

6

### Package Entry Point Resolution

7

8

Resolves the main entry point of a package based on package.json fields.

9

10

```typescript { .api }

11

/**

12

* Resolve the main entry point subpath for a package

13

* @param context - Resolution context

14

* @param packageInfo - Package information including package.json

15

* @param platform - Target platform for conditional resolution

16

* @returns Entry point subpath relative to package root

17

*/

18

function getPackageEntryPoint(

19

context: ResolutionContext,

20

packageInfo: PackageInfo,

21

platform: string | null

22

): string;

23

24

interface PackageInfo {

25

readonly packageJson: PackageJson;

26

readonly rootPath: string;

27

}

28

```

29

30

**Usage Example:**

31

32

```javascript

33

const { getPackageEntryPoint } = require("metro-resolver/src/PackageResolve");

34

35

const packageInfo = {

36

packageJson: {

37

name: "my-package",

38

main: "./dist/index.js",

39

browser: "./dist/browser.js",

40

module: "./dist/esm.js"

41

},

42

rootPath: "/node_modules/my-package"

43

};

44

45

// With mainFields: ['browser', 'module', 'main']

46

const entryPoint = getPackageEntryPoint(context, packageInfo, null);

47

// Result: "./dist/browser.js"

48

```

49

50

### Package.json Structure

51

52

Standard package.json fields supported for resolution.

53

54

```typescript { .api }

55

interface PackageJson {

56

readonly name?: string;

57

readonly main?: string;

58

readonly exports?: string | ExportMap;

59

readonly imports?: ExportMap;

60

readonly browser?: string | BrowserFieldMap;

61

readonly module?: string;

62

readonly types?: string;

63

}

64

65

type BrowserFieldMap = Readonly<{

66

[key: string]: string | false;

67

}>;

68

69

type ExportMap = Readonly<{

70

[subpathOrCondition: string]: ExportMap | string | null;

71

}>;

72

```

73

74

### Package Exports Resolution

75

76

Modern package.json exports field resolution with conditional exports support.

77

78

```typescript { .api }

79

/**

80

* Resolve a package target using the exports field

81

* @param context - Resolution context

82

* @param packagePath - Absolute path to package root

83

* @param absoluteCandidatePath - Absolute path being resolved

84

* @param packageRelativePath - Relative path within package

85

* @param exportsField - Package exports configuration

86

* @param platform - Target platform

87

* @returns Resolved file resolution or null if not found

88

*/

89

function resolvePackageTargetFromExports(

90

context: ResolutionContext,

91

packagePath: string,

92

absoluteCandidatePath: string,

93

packageRelativePath: string,

94

exportsField: ExportsField,

95

platform: string | null

96

): FileResolution | null;

97

98

type ExportsField = string | ExportMap;

99

```

100

101

**Exports Field Examples:**

102

103

```json

104

{

105

"exports": {

106

".": "./dist/index.js",

107

"./utils": "./dist/utils.js",

108

"./package.json": "./package.json"

109

}

110

}

111

```

112

113

```json

114

{

115

"exports": {

116

".": {

117

"import": "./dist/esm/index.js",

118

"require": "./dist/cjs/index.js",

119

"browser": "./dist/browser/index.js"

120

}

121

}

122

}

123

```

124

125

**Platform-Specific Exports:**

126

127

```json

128

{

129

"exports": {

130

".": {

131

"react-native": "./dist/native.js",

132

"browser": "./dist/browser.js",

133

"default": "./dist/node.js"

134

}

135

}

136

}

137

```

138

139

### Package Imports Resolution

140

141

Package.json imports field resolution for subpath imports (starting with `#`).

142

143

```typescript { .api }

144

/**

145

* Resolve a package target using the imports field

146

* @param context - Resolution context

147

* @param packagePath - Absolute path to package root

148

* @param importSpecifier - Import specifier (e.g., "#utils/helper")

149

* @param importsField - Package imports configuration

150

* @param platform - Target platform

151

* @returns Resolved file resolution or null if not found

152

*/

153

function resolvePackageTargetFromImports(

154

context: ResolutionContext,

155

packagePath: string,

156

importSpecifier: string,

157

importsField: ExportMap,

158

platform: string | null

159

): FileResolution | null;

160

```

161

162

**Imports Field Example:**

163

164

```json

165

{

166

"imports": {

167

"#utils/*": "./src/utils/*.js",

168

"#config": {

169

"development": "./config/dev.js",

170

"production": "./config/prod.js"

171

}

172

}

173

}

174

```

175

176

**Usage Example:**

177

178

```javascript

179

// In a file within the package, you can use:

180

import helper from "#utils/helper"; // Resolves to ./src/utils/helper.js

181

import config from "#config"; // Resolves based on condition

182

```

183

184

### Conditional Exports

185

186

Support for conditional exports based on environment and platform.

187

188

```typescript { .api }

189

interface ConditionalExports {

190

[condition: string]: string | ConditionalExports | null;

191

}

192

```

193

194

**Common Conditions:**

195

- `import`: ESM import

196

- `require`: CommonJS require

197

- `browser`: Browser environment

198

- `node`: Node.js environment

199

- `react-native`: React Native platform

200

- `development`/`production`: Build mode

201

202

**Example:**

203

204

```json

205

{

206

"exports": {

207

".": {

208

"import": {

209

"browser": "./dist/esm/browser.js",

210

"node": "./dist/esm/node.js"

211

},

212

"require": {

213

"browser": "./dist/cjs/browser.js",

214

"node": "./dist/cjs/node.js"

215

}

216

}

217

}

218

}

219

```

220

221

### Package Redirection

222

223

Module path redirection through package.json browser field and custom redirections.

224

225

```typescript { .api }

226

/**

227

* Redirect a module path based on package configuration

228

* @param context - Resolution context

229

* @param modulePath - Original module path

230

* @returns Redirected path, original path, or false to exclude

231

*/

232

function redirectModulePath(

233

context: ResolutionContext,

234

modulePath: string

235

): string | false;

236

```

237

238

**Browser Field Redirection:**

239

240

```json

241

{

242

"browser": {

243

"./src/node-specific.js": "./src/browser-specific.js",

244

"fs": false,

245

"path": "path-browserify"

246

}

247

}

248

```

249

250

### Legacy Resolution

251

252

Support for legacy package resolution patterns.

253

254

**Main Field Priority:**

255

1. Check configured `mainFields` in order

256

2. Default to "index" if no main field found

257

3. Attempt file resolution with extensions

258

4. Fallback to index file in directory

259

260

**Browser Field Specification:**

261

- String value: Replace main entry point

262

- Object value: Path-specific redirections

263

- `false` value: Exclude module from bundle

264

265

### Package Resolution Flow

266

267

The complete package resolution process:

268

269

1. **Exports Field Resolution**: If `unstable_enablePackageExports` is true and exports field exists

270

2. **Legacy Resolution**: Fallback to main fields and browser field

271

3. **Entry Point Resolution**: Resolve the determined entry point as a file

272

4. **Index Fallback**: If entry point resolution fails, try index file

273

274

### Error Handling in Package Resolution

275

276

Specific errors thrown during package resolution:

277

278

```typescript { .api }

279

class PackagePathNotExportedError extends Error {

280

packagePath: string;

281

subpath: string;

282

}

283

284

class InvalidPackageConfigurationError extends Error {

285

reason: string;

286

}

287

288

class PackageImportNotResolvedError extends Error {

289

importSpecifier: string;

290

reason: string;

291

}

292

```

293

294

### Subpath Pattern Matching

295

296

Pattern matching for exports and imports with wildcards.

297

298

```typescript { .api }

299

/**

300

* Match a subpath against a pattern with wildcards

301

* @param pattern - Pattern with optional wildcards (*)

302

* @param subpath - Subpath to match against

303

* @returns Match result with captured wildcard values

304

*/

305

function matchSubpathPattern(

306

pattern: string,

307

subpath: string

308

): { matched: boolean; captured: string[] };

309

```

310

311

**Pattern Examples:**

312

313

```json

314

{

315

"exports": {

316

"./lib/*": "./dist/*.js",

317

"./utils/*/helper": "./dist/utils/*/helper.js"

318

}

319

}

320

```

321

322

### Package Detection

323

324

Determine package boundaries and extract package information.

325

326

```typescript { .api }

327

interface PackageForModule extends PackageInfo {

328

/** System-separated subpath relative to package root */

329

readonly packageRelativePath: string;

330

}

331

332

/**

333

* Get package information for a module path

334

* @param absoluteModulePath - Absolute path to check

335

* @returns Package information or null if no package found

336

*/

337

function getPackageForModule(

338

absoluteModulePath: string

339

): PackageForModule | null;

340

```

341

342

**Usage Example:**

343

344

```javascript

345

const packageInfo = context.getPackageForModule('/app/node_modules/lodash/lib/map.js');

346

// Result:

347

// {

348

// packageJson: { name: 'lodash', version: '4.17.21', ... },

349

// rootPath: '/app/node_modules/lodash',

350

// packageRelativePath: 'lib/map.js'

351

// }

352

```

353

354

### Platform-Specific Package Resolution

355

356

Handling platform-specific conditions and files at the package level.

357

358

**Condition Names Configuration:**

359

360

```javascript

361

const context = {

362

unstable_conditionNames: ['import', 'require'],

363

unstable_conditionsByPlatform: {

364

ios: ['react-native', 'ios', 'native', 'import'],

365

android: ['react-native', 'android', 'native', 'import'],

366

web: ['browser', 'import']

367

}

368

};

369

```

370

371

**Platform-Specific Package Structure:**

372

373

```

374

package/

375

├── dist/

376

│ ├── index.js # Default

377

│ ├── index.native.js # React Native

378

│ ├── index.ios.js # iOS specific

379

│ └── index.web.js # Web specific

380

└── package.json

381

```