Skip to content

Commit 533d13c

Browse files
authoredSep 23, 2022
fix: respect mainFields when resolving browser/module field (fixes #8659) (#10071)
1 parent 6233c83 commit 533d13c

File tree

7 files changed

+60
-35
lines changed

7 files changed

+60
-35
lines changed
 

‎docs/config/shared-options.md

+10
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,16 @@ Export keys ending with "/" is deprecated by Node and may not work well. Please
158158

159159
List of fields in `package.json` to try when resolving a package's entry point. Note this takes lower precedence than conditional exports resolved from the `exports` field: if an entry point is successfully resolved from `exports`, the main field will be ignored.
160160

161+
## resolve.browserField
162+
163+
- **Type:** `boolean`
164+
- **Default:** `true`
165+
- **Deprecated**
166+
167+
Whether to enable resolving to `browser` field.
168+
169+
In future, `resolve.mainFields`'s default value will be `['browser', 'module', 'jsnext:main', 'jsnext']` and this option will be removed.
170+
161171
## resolve.extensions
162172

163173
- **Type:** `string[]`

‎packages/vite/src/node/config.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import {
4343
CLIENT_ENTRY,
4444
DEFAULT_ASSETS_RE,
4545
DEFAULT_CONFIG_FILES,
46+
DEFAULT_EXTENSIONS,
47+
DEFAULT_MAIN_FIELDS,
4648
ENV_ENTRY
4749
} from './constants'
4850
import type { InternalResolveOptions, ResolveOptions } from './plugins/resolve'
@@ -321,7 +323,7 @@ export type ResolvedConfig = Readonly<
321323
mainConfig: ResolvedConfig | null
322324
isProduction: boolean
323325
env: Record<string, any>
324-
resolve: ResolveOptions & {
326+
resolve: Required<ResolveOptions> & {
325327
alias: Alias[]
326328
}
327329
plugins: readonly Plugin[]
@@ -474,7 +476,12 @@ export async function resolveConfig(
474476
)
475477

476478
const resolveOptions: ResolvedConfig['resolve'] = {
477-
...config.resolve,
479+
mainFields: config.resolve?.mainFields ?? DEFAULT_MAIN_FIELDS,
480+
browserField: config.resolve?.browserField ?? true,
481+
conditions: config.resolve?.conditions ?? [],
482+
extensions: config.resolve?.extensions ?? DEFAULT_EXTENSIONS,
483+
dedupe: config.resolve?.dedupe ?? [],
484+
preserveSymlinks: config.resolve?.preserveSymlinks ?? false,
478485
alias: resolvedAlias
479486
}
480487

@@ -581,8 +588,8 @@ export async function resolveConfig(
581588
const server = resolveServerOptions(resolvedRoot, config.server, logger)
582589
const ssr = resolveSSROptions(
583590
config.ssr,
584-
config.legacy?.buildSsrCjsExternalHeuristics,
585-
config.resolve?.preserveSymlinks
591+
resolveOptions.preserveSymlinks,
592+
config.legacy?.buildSsrCjsExternalHeuristics
586593
)
587594

588595
const middlewareMode = config?.server?.middlewareMode
@@ -649,7 +656,7 @@ export async function resolveConfig(
649656
disabled: 'build',
650657
...optimizeDeps,
651658
esbuildOptions: {
652-
preserveSymlinks: config.resolve?.preserveSymlinks,
659+
preserveSymlinks: resolveOptions.preserveSymlinks,
653660
...optimizeDeps.esbuildOptions
654661
}
655662
},

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

+22-10
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,18 @@ const debug = createDebugger('vite:resolve-details', {
6363

6464
export interface ResolveOptions {
6565
mainFields?: string[]
66+
/**
67+
* @deprecated In future, `mainFields` should be used instead.
68+
* @default true
69+
*/
70+
browserField?: boolean
6671
conditions?: string[]
6772
extensions?: string[]
6873
dedupe?: string[]
6974
preserveSymlinks?: boolean
7075
}
7176

72-
export interface InternalResolveOptions extends ResolveOptions {
77+
export interface InternalResolveOptions extends Required<ResolveOptions> {
7378
root: string
7479
isBuild: boolean
7580
isProduction: boolean
@@ -85,7 +90,6 @@ export interface InternalResolveOptions extends ResolveOptions {
8590
tryPrefix?: string
8691
skipPackageJson?: boolean
8792
preferRelative?: boolean
88-
preserveSymlinks?: boolean
8993
isRequire?: boolean
9094
// #3040
9195
// when the importer is a ts module,
@@ -238,6 +242,7 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin {
238242

239243
if (
240244
targetWeb &&
245+
options.browserField &&
241246
(res = tryResolveBrowserMapping(fsPath, importer, options, true))
242247
) {
243248
return res
@@ -308,6 +313,7 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin {
308313

309314
if (
310315
targetWeb &&
316+
options.browserField &&
311317
(res = tryResolveBrowserMapping(
312318
id,
313319
importer,
@@ -451,7 +457,7 @@ function tryFsResolve(
451457
return res
452458
}
453459

454-
for (const ext of options.extensions || DEFAULT_EXTENSIONS) {
460+
for (const ext of options.extensions) {
455461
if (
456462
postfix &&
457463
(res = tryResolveFile(
@@ -892,7 +898,11 @@ export function resolvePackageEntry(
892898
// This is because .mjs files can technically import .cjs files which would
893899
// make them invalid for pure ESM environments - so if other module/browser
894900
// fields are present, prioritize those instead.
895-
if (targetWeb && (!entryPoint || entryPoint.endsWith('.mjs'))) {
901+
if (
902+
targetWeb &&
903+
options.browserField &&
904+
(!entryPoint || entryPoint.endsWith('.mjs'))
905+
) {
896906
// check browser field
897907
// https://github.com/defunctzombie/package-browser-field-spec
898908
const browserEntry =
@@ -903,6 +913,7 @@ export function resolvePackageEntry(
903913
// check if the package also has a "module" field.
904914
if (
905915
!options.isRequire &&
916+
options.mainFields.includes('module') &&
906917
typeof data.module === 'string' &&
907918
data.module !== browserEntry
908919
) {
@@ -933,7 +944,8 @@ export function resolvePackageEntry(
933944
}
934945

935946
if (!entryPoint || entryPoint.endsWith('.mjs')) {
936-
for (const field of options.mainFields || DEFAULT_MAIN_FIELDS) {
947+
for (const field of options.mainFields) {
948+
if (field === 'browser') continue // already checked above
937949
if (typeof data[field] === 'string') {
938950
entryPoint = data[field]
939951
break
@@ -951,16 +963,16 @@ export function resolvePackageEntry(
951963
for (let entry of entryPoints) {
952964
// make sure we don't get scripts when looking for sass
953965
if (
954-
options.mainFields?.[0] === 'sass' &&
955-
!options.extensions?.includes(path.extname(entry))
966+
options.mainFields[0] === 'sass' &&
967+
!options.extensions.includes(path.extname(entry))
956968
) {
957969
entry = ''
958970
options.skipPackageJson = true
959971
}
960972

961973
// resolve object browser field in package.json
962974
const { browser: browserField } = data
963-
if (targetWeb && isObject(browserField)) {
975+
if (targetWeb && options.browserField && isObject(browserField)) {
964976
entry = mapWithBrowserField(entry, browserField) || entry
965977
}
966978

@@ -1001,7 +1013,7 @@ function resolveExports(
10011013
if (!options.isRequire) {
10021014
conditions.push('module')
10031015
}
1004-
if (options.conditions) {
1016+
if (options.conditions.length > 0) {
10051017
conditions.push(...options.conditions)
10061018
}
10071019

@@ -1053,7 +1065,7 @@ function resolveDeepImport(
10531065
`${path.join(dir, 'package.json')}.`
10541066
)
10551067
}
1056-
} else if (targetWeb && isObject(browserField)) {
1068+
} else if (targetWeb && options.browserField && isObject(browserField)) {
10571069
// resolve without postfix (see #7098)
10581070
const { file, postfix } = splitFileAndPostfix(relativeId)
10591071
const mapped = mapWithBrowserField(file, browserField)

‎packages/vite/src/node/plugins/ssrRequireHook.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export function ssrRequireHookPlugin(config: ResolvedConfig): Plugin | null {
1313
if (
1414
config.command !== 'build' ||
1515
!config.build.ssr ||
16-
!config.resolve.dedupe?.length ||
16+
!config.resolve.dedupe.length ||
1717
config.ssr?.noExternal === true ||
1818
config.ssr?.format !== 'cjs' ||
1919
isBuildOutputEsm(config)

‎packages/vite/src/node/ssr/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export interface ResolvedSSROptions extends SSROptions {
4141

4242
export function resolveSSROptions(
4343
ssr: SSROptions | undefined,
44-
buildSsrCjsExternalHeuristics?: boolean,
45-
preserveSymlinks?: boolean
44+
preserveSymlinks: boolean,
45+
buildSsrCjsExternalHeuristics?: boolean
4646
): ResolvedSSROptions {
4747
ssr ??= {}
4848
const optimizeDeps = ssr.optimizeDeps ?? {}

‎packages/vite/src/node/ssr/ssrExternal.ts

+8-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'node:fs'
22
import path from 'node:path'
33
import { createRequire } from 'node:module'
4-
import type { InternalResolveOptions } from '../plugins/resolve'
4+
import type { InternalResolveOptions, ResolveOptions } from '../plugins/resolve'
55
import { tryNodeResolve } from '../plugins/resolve'
66
import {
77
bareImportRE,
@@ -53,7 +53,7 @@ export function cjsSsrResolveExternals(
5353

5454
cjsSsrCollectExternals(
5555
config.root,
56-
config.resolve.preserveSymlinks,
56+
config.resolve,
5757
ssrExternals,
5858
seen,
5959
config.logger
@@ -116,8 +116,8 @@ export function createIsConfiguredAsSsrExternal(
116116
createFilter(undefined, noExternal, { resolve: false })
117117

118118
const resolveOptions: InternalResolveOptions = {
119+
...config.resolve,
119120
root,
120-
preserveSymlinks: config.resolve.preserveSymlinks,
121121
isProduction: false,
122122
isBuild: true
123123
}
@@ -211,7 +211,7 @@ function createIsSsrExternal(
211211
// is used reverting to the Vite 2.9 SSR externalization heuristics
212212
function cjsSsrCollectExternals(
213213
root: string,
214-
preserveSymlinks: boolean | undefined,
214+
resolveOptions: Required<ResolveOptions>,
215215
ssrExternals: Set<string>,
216216
seen: Set<string>,
217217
logger: Logger
@@ -227,9 +227,9 @@ function cjsSsrCollectExternals(
227227
...rootPkg.dependencies
228228
}
229229

230-
const resolveOptions: InternalResolveOptions = {
230+
const internalResolveOptions: InternalResolveOptions = {
231+
...resolveOptions,
231232
root,
232-
preserveSymlinks,
233233
isProduction: false,
234234
isBuild: true
235235
}
@@ -247,7 +247,7 @@ function cjsSsrCollectExternals(
247247
esmEntry = tryNodeResolve(
248248
id,
249249
undefined,
250-
resolveOptions,
250+
internalResolveOptions,
251251
true, // we set `targetWeb` to `true` to get the ESM entry
252252
undefined,
253253
true
@@ -314,13 +314,7 @@ function cjsSsrCollectExternals(
314314
}
315315

316316
for (const depRoot of depsToTrace) {
317-
cjsSsrCollectExternals(
318-
depRoot,
319-
preserveSymlinks,
320-
ssrExternals,
321-
seen,
322-
logger
323-
)
317+
cjsSsrCollectExternals(depRoot, resolveOptions, ssrExternals, seen, logger)
324318
}
325319
}
326320

‎packages/vite/src/node/ssr/ssrModuleLoader.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,15 @@ async function instantiateModule(
118118
// CommonJS modules are preferred. We want to avoid ESM->ESM imports
119119
// whenever possible, because `hookNodeResolve` can't intercept them.
120120
const resolveOptions: InternalResolveOptions = {
121-
dedupe,
121+
mainFields: ['main'],
122+
browserField: true,
123+
conditions: [],
122124
extensions: ['.js', '.cjs', '.json'],
125+
dedupe,
126+
preserveSymlinks,
123127
isBuild: true,
124128
isProduction,
125129
isRequire: true,
126-
mainFields: ['main'],
127-
preserveSymlinks,
128130
root
129131
}
130132

0 commit comments

Comments
 (0)
Please sign in to comment.