Skip to content

Commit b58c860

Browse files
committed
fix(resolve): respect exports env key order
fix #1418
1 parent 9eab790 commit b58c860

File tree

14 files changed

+84
-45
lines changed

14 files changed

+84
-45
lines changed

packages/playground/resolve/__tests__/resolve.spec.ts

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ test('deep import with exports field + mapped dir', async () => {
2222
)
2323
})
2424

25+
test('Respect exports field env key priority', async () => {
26+
expect(await page.textContent('.exports-env')).toMatch('[success]')
27+
})
28+
2529
test('omitted index/*', async () => {
2630
expect(await page.textContent('.index')).toMatch('[success]')
2731
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const msg = 'fail (browser.js)'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const msg = '[success] exports env (browser.mjs)'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const msg = 'fail (fallback.umd.js)'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "resolve-exports-env",
3+
"version": "1.0.0",
4+
"exports": {
5+
"import": {
6+
"browser": "./browser.mjs"
7+
},
8+
"browser": "./browser.js",
9+
"default": "./fallback.umd.js"
10+
}
11+
}

packages/playground/resolve/conditional-exports/package.json renamed to packages/playground/resolve/exports-path/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "resolve-conditional-exports",
2+
"name": "resolve-exports-path",
33
"version": "1.0.0",
44
"exports": {
55
".": {

packages/playground/resolve/index.html

+10-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ <h2>Deep import with exports field + exposed directory</h2>
1515
<h2>Deep import with exports field + mapped directory</h2>
1616
<p class="exports-deep-mapped-dir">fail</p>
1717

18+
<h2>Exports field env priority</h2>
19+
<p class="exports-env">fail</p>
20+
1821
<h2>Resolve /index.*</h2>
1922
<p class="index">fail</p>
2023

@@ -56,21 +59,24 @@ <h2>Inline package</h2>
5659
))
5760

5861
// exports field
59-
import { msg } from 'resolve-conditional-exports'
62+
import { msg } from 'resolve-exports-path'
6063
text('.exports-entry', msg)
6164

6265
// deep import w/ exports
63-
import { msg as deepMsg } from 'resolve-conditional-exports/deep.js'
66+
import { msg as deepMsg } from 'resolve-exports-path/deep.js'
6467
text('.exports-deep', deepMsg)
6568

6669
// deep import w/ exposed dir
67-
import { msg as exposedDirMsg } from 'resolve-conditional-exports/dir/dir'
70+
import { msg as exposedDirMsg } from 'resolve-exports-path/dir/dir'
6871
text('.exports-deep-exposed-dir', exposedDirMsg)
6972

7073
// deep import w/ mapped dir
71-
import { msg as mappedDirMsg } from 'resolve-conditional-exports/dir-mapped/dir'
74+
import { msg as mappedDirMsg } from 'resolve-exports-path/dir-mapped/dir'
7275
text('.exports-deep-mapped-dir', mappedDirMsg)
7376

77+
import { msg as exportsEnvMsg } from 'resolve-exports-env'
78+
text('.exports-env', exportsEnvMsg)
79+
7480
// implicit index resolving
7581
import { foo } from './util'
7682
text('.index', foo())

packages/playground/resolve/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"debug": "node --inspect-brk ../../vite/bin/vite"
99
},
1010
"dependencies": {
11-
"resolve-conditional-exports": "link:./conditional-exports",
11+
"resolve-exports-path": "link:./exports-path",
12+
"resolve-exports-env": "link:./exports-env",
1213
"resolve-browser-field": "link:./browser-field",
1314
"@babel/runtime": "^7.12.5",
1415
"normalize.css": "^8.0.1"

packages/vite/src/node/plugins/resolve.ts

+45-35
Original file line numberDiff line numberDiff line change
@@ -381,17 +381,7 @@ export function resolvePackageEntry(
381381
// https://nodejs.org/api/packages.html#packages_package_entry_points
382382
const { exports: exportsField } = data
383383
if (exportsField) {
384-
if (typeof exportsField === 'string') {
385-
entryPoint = exportsField
386-
} else if (Array.isArray(exportsField)) {
387-
entryPoint = exportsField[0]
388-
} else if (isObject(exportsField)) {
389-
if ('.' in exportsField) {
390-
entryPoint = resolveConditionalExports(exportsField['.'])
391-
} else {
392-
entryPoint = resolveConditionalExports(exportsField)
393-
}
394-
}
384+
entryPoint = resolveConditionalExports(exportsField, '.')
395385
}
396386
}
397387

@@ -439,24 +429,13 @@ function resolveDeepImport(
439429

440430
// map relative based on exports data
441431
if (exportsField) {
442-
let isExported = false
443432
if (isObject(exportsField) && !Array.isArray(exportsField)) {
444-
if (relativeId in exportsField) {
445-
relativeId = resolveConditionalExports(exportsField[relativeId])
446-
isExported = true
447-
} else {
448-
for (const key in exportsField) {
449-
if (key.endsWith('/') && relativeId.startsWith(key)) {
450-
// directory mapping
451-
const replacement = resolveConditionalExports(exportsField[key])
452-
relativeId = replacement && relativeId.replace(key, replacement)
453-
isExported = true
454-
break
455-
}
456-
}
457-
}
433+
relativeId = resolveConditionalExports(exportsField, relativeId)
434+
} else {
435+
// not exposed
436+
relativeId = undefined
458437
}
459-
if (!isExported || !relativeId) {
438+
if (!relativeId) {
460439
throw new Error(
461440
`Package subpath '${relativeId}' is not defined by "exports" in ` +
462441
`${path.join(dir, 'package.json')}.`
@@ -481,20 +460,51 @@ function resolveDeepImport(
481460
}
482461
}
483462

484-
function resolveConditionalExports(exp: any): string | undefined {
463+
const ENV_KEYS = [
464+
'esmodules',
465+
'import',
466+
'module',
467+
'require',
468+
'browser',
469+
'node',
470+
'default'
471+
]
472+
473+
function resolveConditionalExports(exp: any, id: string): string | undefined {
485474
if (typeof exp === 'string') {
486475
return exp
487476
} else if (isObject(exp)) {
488-
if (typeof exp.browser === 'string') {
489-
return exp.browser
490-
} else if (typeof exp.import === 'string') {
491-
return exp.import
492-
} else if (typeof exp.default === 'string') {
493-
return exp.default
477+
let isFileListing: boolean | undefined
478+
let fallback: string | undefined
479+
for (const key in exp) {
480+
if (isFileListing === undefined) {
481+
isFileListing = key[0] === '.'
482+
}
483+
if (isFileListing) {
484+
if (key === id) {
485+
return resolveConditionalExports(exp[key], id)
486+
} else if (key.endsWith('/') && id.startsWith(key)) {
487+
// mapped directory
488+
const replacement = resolveConditionalExports(exp[key], id)
489+
return replacement && id.replace(key, replacement)
490+
}
491+
} else if (ENV_KEYS.includes(key)) {
492+
// https://github.com/vitejs/vite/issues/1418
493+
// respect env key order
494+
// but intentionally de-prioritize "require" and "default" keys
495+
if (key === 'require' || key === 'default') {
496+
if (!fallback) fallback = key
497+
} else {
498+
return resolveConditionalExports(exp[key], id)
499+
}
500+
}
501+
if (fallback) {
502+
return resolveConditionalExports(exp[key], id)
503+
}
494504
}
495505
} else if (Array.isArray(exp)) {
496506
for (let i = 0; i < exp.length; i++) {
497-
const res = resolveConditionalExports(exp[i])
507+
const res = resolveConditionalExports(exp[i], id)
498508
if (res) return res
499509
}
500510
}

yarn.lock

+8-4
Original file line numberDiff line numberDiff line change
@@ -7067,17 +7067,21 @@ requires-port@^1.0.0:
70677067
version "0.0.0"
70687068
uid ""
70697069

7070-
"resolve-conditional-exports@link:./packages/playground/resolve/conditional-exports":
7071-
version "0.0.0"
7072-
uid ""
7073-
70747070
resolve-cwd@^3.0.0:
70757071
version "3.0.0"
70767072
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
70777073
integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
70787074
dependencies:
70797075
resolve-from "^5.0.0"
70807076

7077+
"resolve-exports-env@link:./packages/playground/resolve/exports-env":
7078+
version "0.0.0"
7079+
uid ""
7080+
7081+
"resolve-exports-path@link:./packages/playground/resolve/exports-path":
7082+
version "0.0.0"
7083+
uid ""
7084+
70817085
resolve-from@^4.0.0:
70827086
version "4.0.0"
70837087
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"

0 commit comments

Comments
 (0)