Skip to content

Commit

Permalink
fix: use browser field if likely esm (fixes #9652) (#9653)
Browse files Browse the repository at this point in the history
  • Loading branch information
sapphi-red authored Aug 12, 2022
1 parent c261fe6 commit 85e387a
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 10 deletions.
18 changes: 8 additions & 10 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'node:path'
import colors from 'picocolors'
import type { PartialResolvedId } from 'rollup'
import { resolve as _resolveExports } from 'resolve.exports'
import { hasESMSyntax } from 'mlly'
import type { Plugin } from '../plugin'
import {
DEFAULT_EXTENSIONS,
Expand Down Expand Up @@ -850,25 +851,22 @@ export function resolvePackageEntry(
) {
// 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.
// "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 UMD. If it is UMD, prefer "module"
// 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 (
(/typeof exports\s*==/.test(content) &&
/typeof module\s*==/.test(content)) ||
/module\.exports\s*=/.test(content)
) {
// likely UMD or CJS(!!! e.g. firebase 7.x), prefer module
entryPoint = data.module
} else {
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 {
Expand Down
4 changes: 4 additions & 0 deletions playground/resolve/__tests__/resolve.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ test('Resolve module field if browser field is likely UMD or CJS', async () => {
expect(await page.textContent('.browser-module2')).toMatch('[success]')
})

test('Resolve module field if browser field is likely IIFE', async () => {
expect(await page.textContent('.browser-module3')).toMatch('[success]')
})

test('css entry', async () => {
expect(await page.textContent('.css')).toMatch('[success]')
})
Expand Down
1 change: 1 addition & 0 deletions playground/resolve/browser-module-field3/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default '[success] this should run in browser'
7 changes: 7 additions & 0 deletions playground/resolve/browser-module-field3/index.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var browserModuleField3 = (function () {
'use strict'

var main = '[fail] this should not run in the browser'

return main
})()
7 changes: 7 additions & 0 deletions playground/resolve/browser-module-field3/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "resolve-browser-module-field3",
"private": true,
"version": "1.0.0",
"module": "index.js",
"browser": "index.web.js"
}
6 changes: 6 additions & 0 deletions playground/resolve/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ <h2>Resolve browser field even if module field exists</h2>
<h2>Resolve module field if browser field is likely UMD or CJS</h2>
<p class="browser-module2">fail</p>

<h2>Resolve module field if browser field is likely IIFE</h2>
<p class="browser-module3">fail</p>

<h2>Don't resolve to the `module` field if the importer is a `require` call</h2>
<p class="require-pkg-with-module-field">fail</p>

Expand Down Expand Up @@ -225,6 +228,9 @@ <h2>resolve package that contains # in path</h2>
import browserModule2 from 'resolve-browser-module-field2'
text('.browser-module2', browserModule2)

import browserModule3 from 'resolve-browser-module-field3'
text('.browser-module3', browserModule3)

import { msg as requireButWithModuleFieldMsg } from 'require-pkg-with-module-field'
text('.require-pkg-with-module-field', requireButWithModuleFieldMsg)

Expand Down
1 change: 1 addition & 0 deletions playground/resolve/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"resolve-browser-field": "link:./browser-field",
"resolve-browser-module-field1": "link:./browser-module-field1",
"resolve-browser-module-field2": "link:./browser-module-field2",
"resolve-browser-module-field3": "link:./browser-module-field3",
"resolve-custom-condition": "link:./custom-condition",
"resolve-custom-main-field": "link:./custom-main-field",
"resolve-exports-env": "link:./exports-env",
Expand Down
5 changes: 5 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 85e387a

Please sign in to comment.