Skip to content

Commit

Permalink
fix(resolve): respect order of browser in mainFields when resolving
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikg committed Nov 24, 2023
1 parent 0654d1b commit 33678c2
Showing 1 changed file with 53 additions and 43 deletions.
96 changes: 53 additions & 43 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -982,52 +982,15 @@ export function resolvePackageEntry(
)
}

// handle edge case with browser and module field semantics
if (!entryPoint && targetWeb && options.mainFields.includes('browser')) {
// check browser field
// https://github.com/defunctzombie/package-browser-field-spec
const browserEntry =
typeof data.browser === 'string'
? data.browser
: isObject(data.browser) && data.browser['.']
if (browserEntry) {
// check if the package also has a "module" field.
if (
!options.isRequire &&
options.mainFields.includes('module') &&
typeof data.module === 'string' &&
data.module !== browserEntry
) {
// if both are present, we may have a problem: some package points both
// to ESM, with "module" targeting Node.js, while some packages points
// "module" to browser ESM and "browser" to UMD/IIFE.
// the heuristics here is to actually read the browser entry when
// possible and check for hints of ESM. If it is not ESM, prefer "module"
// instead; Otherwise, assume it's ESM and use it.
const resolvedBrowserEntry = tryFsResolve(
path.join(dir, browserEntry),
options,
)
if (resolvedBrowserEntry) {
const content = fs.readFileSync(resolvedBrowserEntry, 'utf-8')
if (hasESMSyntax(content)) {
// likely ESM, prefer browser
entryPoint = browserEntry
} else {
// non-ESM, UMD or IIFE or CJS(!!! e.g. firebase 7.x), prefer module
entryPoint = data.module
}
}
} else {
entryPoint = browserEntry
}
}
}

// fallback to mainFields if still not resolved
if (!entryPoint) {
for (const field of options.mainFields) {
if (field === 'browser') continue // already checked above
if (field === 'browser' && targetWeb) {
entryPoint = tryResolveBrowserEntry(dir, data, options)
if (entryPoint) {
break
}
}
if (typeof data[field] === 'string') {
entryPoint = data[field]
break
Expand Down Expand Up @@ -1257,6 +1220,53 @@ function tryResolveBrowserMapping(
}
}

function tryResolveBrowserEntry(
dir: string,
data: PackageData['data'],
options: InternalResolveOptions,
) {
// handle edge case with browser and module field semantics

// check browser field
// https://github.com/defunctzombie/package-browser-field-spec
const browserEntry =
typeof data.browser === 'string'
? data.browser
: isObject(data.browser) && data.browser['.']
if (browserEntry) {
// check if the package also has a "module" field.
if (
!options.isRequire &&
options.mainFields.includes('module') &&
typeof data.module === 'string' &&
data.module !== browserEntry
) {
// if both are present, we may have a problem: some package points both
// to ESM, with "module" targeting Node.js, while some packages points
// "module" to browser ESM and "browser" to UMD/IIFE.
// the heuristics here is to actually read the browser entry when
// possible and check for hints of ESM. If it is not ESM, prefer "module"
// instead; Otherwise, assume it's ESM and use it.
const resolvedBrowserEntry = tryFsResolve(
path.join(dir, browserEntry),
options,
)
if (resolvedBrowserEntry) {
const content = fs.readFileSync(resolvedBrowserEntry, 'utf-8')
if (hasESMSyntax(content)) {
// likely ESM, prefer browser
return browserEntry
} else {
// non-ESM, UMD or IIFE or CJS(!!! e.g. firebase 7.x), prefer module
return data.module
}
}
} else {
return browserEntry
}
}
}

/**
* given a relative path in pkg dir,
* return a relative path in pkg dir,
Expand Down

0 comments on commit 33678c2

Please sign in to comment.