From 4dd7ae0a3e302d598e699ce501b0b82df9a4e8cf Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 26 Feb 2022 21:25:47 +0900 Subject: [PATCH 1/7] fix: import with query with exports field --- .../playground/resolve/__tests__/resolve.spec.ts | 4 +++- packages/vite/src/node/plugins/resolve.ts | 15 +++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/playground/resolve/__tests__/resolve.spec.ts b/packages/playground/resolve/__tests__/resolve.spec.ts index b64da138033fc0..07ebff5e2466e7 100644 --- a/packages/playground/resolve/__tests__/resolve.spec.ts +++ b/packages/playground/resolve/__tests__/resolve.spec.ts @@ -17,7 +17,9 @@ test('deep import with exports field', async () => { }) test('deep import with query with exports field', async () => { - expect(await page.textContent('.exports-deep-query')).not.toMatch('fail') + expect(await page.textContent('.exports-deep-query')).toMatch( + isBuild ? /base64/ : '/exports-path/deep.json' + ) }) test('deep import with exports field + exposed dir', async () => { diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 03a9026242f428..3a723f31c331ab 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -772,10 +772,13 @@ function packageEntryFailure(id: string, details?: string) { function resolveExports( pkg: PackageData['data'], - key: string, + keyWithQuery: string, options: InternalResolveOptions, targetWeb: boolean ) { + const key = cleanUrl(keyWithQuery) + const query = keyWithQuery.slice(key.length) + const conditions = [options.isProduction ? 'production' : 'development'] if (!options.isRequire) { conditions.push('module') @@ -783,11 +786,12 @@ function resolveExports( if (options.conditions) { conditions.push(...options.conditions) } - return _resolveExports(pkg, key, { + const resolved = _resolveExports(pkg, key, { browser: targetWeb, require: options.isRequire, conditions }) + return resolved + query } function resolveDeepImport( @@ -813,12 +817,7 @@ function resolveDeepImport( // map relative based on exports data if (exportsField) { if (isObject(exportsField) && !Array.isArray(exportsField)) { - relativeId = resolveExports( - data, - cleanUrl(relativeId), - options, - targetWeb - ) + relativeId = resolveExports(data, relativeId, options, targetWeb) } else { // not exposed relativeId = undefined From 4485a2c4bb9f0d746cde24599cd4f7b18760fad8 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Fri, 4 Mar 2022 18:03:19 +0900 Subject: [PATCH 2/7] chore: add comment about import with ?url --- packages/playground/resolve/__tests__/resolve.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/playground/resolve/__tests__/resolve.spec.ts b/packages/playground/resolve/__tests__/resolve.spec.ts index 07ebff5e2466e7..958f156102ae5d 100644 --- a/packages/playground/resolve/__tests__/resolve.spec.ts +++ b/packages/playground/resolve/__tests__/resolve.spec.ts @@ -17,6 +17,7 @@ test('deep import with exports field', async () => { }) test('deep import with query with exports field', async () => { + // since it is imported with `?url` it should return a url expect(await page.textContent('.exports-deep-query')).toMatch( isBuild ? /base64/ : '/exports-path/deep.json' ) From 5169c277a5d4b072fc53ad2b6f7900c3539f7a2d Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Fri, 4 Mar 2022 18:21:49 +0900 Subject: [PATCH 3/7] fix: prefer exports field including postfix --- .../resolve/__tests__/resolve.spec.ts | 6 ++ .../playground/resolve/exports-path/deep2.js | 1 + .../resolve/exports-path/package.json | 1 + packages/playground/resolve/index.html | 7 +++ packages/vite/src/node/plugins/resolve.ts | 60 ++++++++++++------- 5 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 packages/playground/resolve/exports-path/deep2.js diff --git a/packages/playground/resolve/__tests__/resolve.spec.ts b/packages/playground/resolve/__tests__/resolve.spec.ts index 958f156102ae5d..b502a9c93d2505 100644 --- a/packages/playground/resolve/__tests__/resolve.spec.ts +++ b/packages/playground/resolve/__tests__/resolve.spec.ts @@ -23,6 +23,12 @@ test('deep import with query with exports field', async () => { ) }) +test('deep import with exports field including "?"', async () => { + expect(await page.textContent('.exports-deep-question-mark')).toMatch( + '[success]' + ) +}) + test('deep import with exports field + exposed dir', async () => { expect(await page.textContent('.exports-deep-exposed-dir')).toMatch( '[success]' diff --git a/packages/playground/resolve/exports-path/deep2.js b/packages/playground/resolve/exports-path/deep2.js new file mode 100644 index 00000000000000..4593a43f1a3d66 --- /dev/null +++ b/packages/playground/resolve/exports-path/deep2.js @@ -0,0 +1 @@ +export const msg = '[success] deep resolve from exports including postfix' diff --git a/packages/playground/resolve/exports-path/package.json b/packages/playground/resolve/exports-path/package.json index 7355da2f63f616..c2d17a2ffd0190 100644 --- a/packages/playground/resolve/exports-path/package.json +++ b/packages/playground/resolve/exports-path/package.json @@ -9,6 +9,7 @@ }, "./deep.js": "./deep.js", "./deep.json": "./deep.json", + "./deep.js?url": "./deep2.js", "./dir/": "./dir/", "./dir-mapped/*": { "import": "./dir/*", diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html index 71699035abdd53..c100dce1213fcb 100644 --- a/packages/playground/resolve/index.html +++ b/packages/playground/resolve/index.html @@ -15,6 +15,9 @@

Deep import with exports field

Deep import with query with exports field

fail

+

Deep import with exports field including "?"

+

fail

+

Deep import with exports field + exposed directory

fail

@@ -107,6 +110,10 @@

resolve package that contains # in path

import deepPath from 'resolve-exports-path/deep.json?url' text('.exports-deep-query', deepPath) + // deep import w/ exports including "?" + import { msg as deepMsg2 } from 'resolve-exports-path/deep.js?url' + text('.exports-deep-question-mark', deepMsg2) + // deep import w/ exposed dir import { msg as exposedDirMsg } from 'resolve-exports-path/dir/dir' text('.exports-deep-exposed-dir', exposedDirMsg) diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 3a723f31c331ab..9bf517f4b54d86 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -289,23 +289,28 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { } } -function tryFsResolve( - fsPath: string, - options: InternalResolveOptions, - tryIndex = true, - targetWeb = true -): string | undefined { - let file = fsPath +function splitFileAndPostfix(path: string) { + let file = path let postfix = '' - let postfixIndex = fsPath.indexOf('?') + let postfixIndex = path.indexOf('?') if (postfixIndex < 0) { - postfixIndex = fsPath.indexOf('#') + postfixIndex = path.indexOf('#') } if (postfixIndex > 0) { - file = fsPath.slice(0, postfixIndex) - postfix = fsPath.slice(postfixIndex) + file = path.slice(0, postfixIndex) + postfix = path.slice(postfixIndex) } + return { file, postfix } +} + +function tryFsResolve( + fsPath: string, + options: InternalResolveOptions, + tryIndex = true, + targetWeb = true +): string | undefined { + const { file, postfix } = splitFileAndPostfix(fsPath) let res: string | undefined @@ -776,9 +781,6 @@ function resolveExports( options: InternalResolveOptions, targetWeb: boolean ) { - const key = cleanUrl(keyWithQuery) - const query = keyWithQuery.slice(key.length) - const conditions = [options.isProduction ? 'production' : 'development'] if (!options.isRequire) { conditions.push('module') @@ -786,12 +788,30 @@ function resolveExports( if (options.conditions) { conditions.push(...options.conditions) } - const resolved = _resolveExports(pkg, key, { - browser: targetWeb, - require: options.isRequire, - conditions - }) - return resolved + query + + try { + const resolved = _resolveExports(pkg, keyWithQuery, { + browser: targetWeb, + require: options.isRequire, + conditions + }) + return resolved + } catch (err) { + // not found + + // try without postfix for `import 'something/path.js?query'` (see #7098) + const { file, postfix } = splitFileAndPostfix(keyWithQuery) + if (!postfix) { + throw err + } + + const resolvedWithoutPostfix = _resolveExports(pkg, file, { + browser: targetWeb, + require: options.isRequire, + conditions + }) + return resolvedWithoutPostfix + postfix + } } function resolveDeepImport( From fe040cdc8c675fbb6870d0ced9eb16b7f33bd704 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Fri, 4 Mar 2022 19:01:18 +0900 Subject: [PATCH 4/7] fix: fallback to browser field without postfix --- .../resolve/browser-field/package.json | 3 +- packages/playground/resolve/index.html | 4 ++- packages/vite/src/node/plugins/resolve.ts | 31 +++++++++++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/playground/resolve/browser-field/package.json b/packages/playground/resolve/browser-field/package.json index 006f9b4b5f4fc6..910a4ff4b705c0 100644 --- a/packages/playground/resolve/browser-field/package.json +++ b/packages/playground/resolve/browser-field/package.json @@ -12,6 +12,7 @@ "./no-ext-index": "./out/esm.browser.js", "./not-browser.js": false, "./multiple.dot.path.js": false, - "jsdom": false + "jsdom": false, + "./question.js?query": "./out/esm.browser.js" } } diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html index c100dce1213fcb..5de5ade2c3a2dc 100644 --- a/packages/playground/resolve/index.html +++ b/packages/playground/resolve/index.html @@ -158,10 +158,12 @@

resolve package that contains # in path

import e from 'resolve-browser-field/ext-index/index.js' import f from 'resolve-browser-field/ext-index' import g from 'resolve-browser-field/no-ext-index/index.js' // no substitution + import h from 'resolve-browser-field/question.js?query' + import i from 'resolve-browser-field/no-ext?query' import { ra, rb, rc, rd, re, rf, rg } from 'resolve-browser-field/relative' - const success = [main, a, c, d, e, f, ra, rc, rd, re, rf] + const success = [main, a, c, d, e, f, h, i, ra, rc, rd, re, rf] const noSuccess = [b, g, rb, rg] if ( diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 9bf517f4b54d86..b9753cb40736a1 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -917,12 +917,37 @@ function mapWithBrowserField( ): string | false | undefined { const normalizedPath = path.posix.normalize(relativePathInPkgDir) + const result = _mapWithBrowserField(normalizedPath, map) + if (result !== undefined) { + return result + } + + // try without postfix for `import 'something/path.js?query'` (see #7098) + const { file: normalizedPathWithoutPostfix, postfix } = + splitFileAndPostfix(normalizedPath) + if (!postfix) { + return undefined + } + const resultWithoutPostfix = _mapWithBrowserField( + normalizedPathWithoutPostfix, + map + ) + if (typeof resultWithoutPostfix === 'string') { + return resultWithoutPostfix + postfix + } + return resultWithoutPostfix +} + +function _mapWithBrowserField( + normalizedRelativePath: string, + map: Record +): string | false | undefined { for (const key in map) { const normalizedKey = path.posix.normalize(key) if ( - normalizedPath === normalizedKey || - equalWithoutSuffix(normalizedPath, normalizedKey, '.js') || - equalWithoutSuffix(normalizedPath, normalizedKey, '/index.js') + normalizedRelativePath === normalizedKey || + equalWithoutSuffix(normalizedRelativePath, normalizedKey, '.js') || + equalWithoutSuffix(normalizedRelativePath, normalizedKey, '/index.js') ) { return map[key] } From 5fc902d8d0913132d6169106b6522bd83562c2dc Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Wed, 9 Mar 2022 17:12:32 +0900 Subject: [PATCH 5/7] fix: dont resolve exports field with postfix --- .../resolve/__tests__/resolve.spec.ts | 6 --- .../playground/resolve/exports-path/deep2.js | 1 - .../resolve/exports-path/package.json | 1 - packages/playground/resolve/index.html | 7 ---- packages/vite/src/node/plugins/resolve.ts | 39 +++++++------------ 5 files changed, 14 insertions(+), 40 deletions(-) delete mode 100644 packages/playground/resolve/exports-path/deep2.js diff --git a/packages/playground/resolve/__tests__/resolve.spec.ts b/packages/playground/resolve/__tests__/resolve.spec.ts index b502a9c93d2505..958f156102ae5d 100644 --- a/packages/playground/resolve/__tests__/resolve.spec.ts +++ b/packages/playground/resolve/__tests__/resolve.spec.ts @@ -23,12 +23,6 @@ test('deep import with query with exports field', async () => { ) }) -test('deep import with exports field including "?"', async () => { - expect(await page.textContent('.exports-deep-question-mark')).toMatch( - '[success]' - ) -}) - test('deep import with exports field + exposed dir', async () => { expect(await page.textContent('.exports-deep-exposed-dir')).toMatch( '[success]' diff --git a/packages/playground/resolve/exports-path/deep2.js b/packages/playground/resolve/exports-path/deep2.js deleted file mode 100644 index 4593a43f1a3d66..00000000000000 --- a/packages/playground/resolve/exports-path/deep2.js +++ /dev/null @@ -1 +0,0 @@ -export const msg = '[success] deep resolve from exports including postfix' diff --git a/packages/playground/resolve/exports-path/package.json b/packages/playground/resolve/exports-path/package.json index c2d17a2ffd0190..7355da2f63f616 100644 --- a/packages/playground/resolve/exports-path/package.json +++ b/packages/playground/resolve/exports-path/package.json @@ -9,7 +9,6 @@ }, "./deep.js": "./deep.js", "./deep.json": "./deep.json", - "./deep.js?url": "./deep2.js", "./dir/": "./dir/", "./dir-mapped/*": { "import": "./dir/*", diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html index 5de5ade2c3a2dc..dcd6117cea2121 100644 --- a/packages/playground/resolve/index.html +++ b/packages/playground/resolve/index.html @@ -15,9 +15,6 @@

Deep import with exports field

Deep import with query with exports field

fail

-

Deep import with exports field including "?"

-

fail

-

Deep import with exports field + exposed directory

fail

@@ -110,10 +107,6 @@

resolve package that contains # in path

import deepPath from 'resolve-exports-path/deep.json?url' text('.exports-deep-query', deepPath) - // deep import w/ exports including "?" - import { msg as deepMsg2 } from 'resolve-exports-path/deep.js?url' - text('.exports-deep-question-mark', deepMsg2) - // deep import w/ exposed dir import { msg as exposedDirMsg } from 'resolve-exports-path/dir/dir' text('.exports-deep-exposed-dir', exposedDirMsg) diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index b9753cb40736a1..e45c2aecb7567e 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -777,7 +777,7 @@ function packageEntryFailure(id: string, details?: string) { function resolveExports( pkg: PackageData['data'], - keyWithQuery: string, + key: string, options: InternalResolveOptions, targetWeb: boolean ) { @@ -789,29 +789,11 @@ function resolveExports( conditions.push(...options.conditions) } - try { - const resolved = _resolveExports(pkg, keyWithQuery, { - browser: targetWeb, - require: options.isRequire, - conditions - }) - return resolved - } catch (err) { - // not found - - // try without postfix for `import 'something/path.js?query'` (see #7098) - const { file, postfix } = splitFileAndPostfix(keyWithQuery) - if (!postfix) { - throw err - } - - const resolvedWithoutPostfix = _resolveExports(pkg, file, { - browser: targetWeb, - require: options.isRequire, - conditions - }) - return resolvedWithoutPostfix + postfix - } + return _resolveExports(pkg, key, { + browser: targetWeb, + require: options.isRequire, + conditions + }) } function resolveDeepImport( @@ -837,7 +819,14 @@ function resolveDeepImport( // map relative based on exports data if (exportsField) { if (isObject(exportsField) && !Array.isArray(exportsField)) { - relativeId = resolveExports(data, relativeId, options, targetWeb) + // resolve without postfix (see #7098) + const { file, postfix } = splitFileAndPostfix(relativeId) + const exportsId = resolveExports(data, file, options, targetWeb) + if (exportsId !== undefined) { + relativeId = exportsId + postfix + } else { + relativeId = undefined + } } else { // not exposed relativeId = undefined From 639d608529e55013c9ff68bab541100d2b3311ee Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Wed, 9 Mar 2022 17:14:12 +0900 Subject: [PATCH 6/7] Revert "fix: fallback to browser field without postfix" This reverts commit fe040cdc8c675fbb6870d0ced9eb16b7f33bd704. --- .../resolve/browser-field/package.json | 3 +- packages/playground/resolve/index.html | 4 +-- packages/vite/src/node/plugins/resolve.ts | 31 ++----------------- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/packages/playground/resolve/browser-field/package.json b/packages/playground/resolve/browser-field/package.json index 910a4ff4b705c0..006f9b4b5f4fc6 100644 --- a/packages/playground/resolve/browser-field/package.json +++ b/packages/playground/resolve/browser-field/package.json @@ -12,7 +12,6 @@ "./no-ext-index": "./out/esm.browser.js", "./not-browser.js": false, "./multiple.dot.path.js": false, - "jsdom": false, - "./question.js?query": "./out/esm.browser.js" + "jsdom": false } } diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html index dcd6117cea2121..71699035abdd53 100644 --- a/packages/playground/resolve/index.html +++ b/packages/playground/resolve/index.html @@ -151,12 +151,10 @@

resolve package that contains # in path

import e from 'resolve-browser-field/ext-index/index.js' import f from 'resolve-browser-field/ext-index' import g from 'resolve-browser-field/no-ext-index/index.js' // no substitution - import h from 'resolve-browser-field/question.js?query' - import i from 'resolve-browser-field/no-ext?query' import { ra, rb, rc, rd, re, rf, rg } from 'resolve-browser-field/relative' - const success = [main, a, c, d, e, f, h, i, ra, rc, rd, re, rf] + const success = [main, a, c, d, e, f, ra, rc, rd, re, rf] const noSuccess = [b, g, rb, rg] if ( diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index e45c2aecb7567e..ac5a4df74a5847 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -906,37 +906,12 @@ function mapWithBrowserField( ): string | false | undefined { const normalizedPath = path.posix.normalize(relativePathInPkgDir) - const result = _mapWithBrowserField(normalizedPath, map) - if (result !== undefined) { - return result - } - - // try without postfix for `import 'something/path.js?query'` (see #7098) - const { file: normalizedPathWithoutPostfix, postfix } = - splitFileAndPostfix(normalizedPath) - if (!postfix) { - return undefined - } - const resultWithoutPostfix = _mapWithBrowserField( - normalizedPathWithoutPostfix, - map - ) - if (typeof resultWithoutPostfix === 'string') { - return resultWithoutPostfix + postfix - } - return resultWithoutPostfix -} - -function _mapWithBrowserField( - normalizedRelativePath: string, - map: Record -): string | false | undefined { for (const key in map) { const normalizedKey = path.posix.normalize(key) if ( - normalizedRelativePath === normalizedKey || - equalWithoutSuffix(normalizedRelativePath, normalizedKey, '.js') || - equalWithoutSuffix(normalizedRelativePath, normalizedKey, '/index.js') + normalizedPath === normalizedKey || + equalWithoutSuffix(normalizedPath, normalizedKey, '.js') || + equalWithoutSuffix(normalizedPath, normalizedKey, '/index.js') ) { return map[key] } From de16341de9b0ab6a7dfe735fd996c9c14688bddd Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Wed, 9 Mar 2022 17:25:11 +0900 Subject: [PATCH 7/7] fix: resolve browser field without postfix --- packages/playground/resolve/index.html | 3 ++- packages/vite/src/node/plugins/resolve.ts | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html index 71699035abdd53..520b22db0304e9 100644 --- a/packages/playground/resolve/index.html +++ b/packages/playground/resolve/index.html @@ -151,10 +151,11 @@

resolve package that contains # in path

import e from 'resolve-browser-field/ext-index/index.js' import f from 'resolve-browser-field/ext-index' import g from 'resolve-browser-field/no-ext-index/index.js' // no substitution + import h from 'resolve-browser-field/no-ext?query' import { ra, rb, rc, rd, re, rf, rg } from 'resolve-browser-field/relative' - const success = [main, a, c, d, e, f, ra, rc, rd, re, rf] + const success = [main, a, c, d, e, f, h, ra, rc, rd, re, rf] const noSuccess = [b, g, rb, rg] if ( diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index ac5a4df74a5847..251d1a8e68d4c1 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -838,9 +838,11 @@ function resolveDeepImport( ) } } else if (targetWeb && isObject(browserField)) { - const mapped = mapWithBrowserField(relativeId, browserField) + // resolve without postfix (see #7098) + const { file, postfix } = splitFileAndPostfix(relativeId) + const mapped = mapWithBrowserField(file, browserField) if (mapped) { - relativeId = mapped + relativeId = mapped + postfix } else if (mapped === false) { return (webResolvedImports[id] = browserExternalId) }