From 724aa8a5fcb0ccaea283b3bf065d29ebf2cdf5a2 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 5 Jan 2021 15:21:33 -0500 Subject: [PATCH] fix(resolve): handle exports field w/ mapped directory --- .../resolve/__tests__/resolve.spec.ts | 12 +++++++++ .../resolve/conditional-exports/dir/dir.js | 1 + .../resolve/conditional-exports/package.json | 7 +++++- packages/playground/resolve/index.html | 14 +++++++++++ packages/vite/src/node/plugins/resolve.ts | 25 +++++++++++++------ 5 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 packages/playground/resolve/conditional-exports/dir/dir.js diff --git a/packages/playground/resolve/__tests__/resolve.spec.ts b/packages/playground/resolve/__tests__/resolve.spec.ts index f82df05c492656..5a1ca2ed1fa8de 100644 --- a/packages/playground/resolve/__tests__/resolve.spec.ts +++ b/packages/playground/resolve/__tests__/resolve.spec.ts @@ -10,6 +10,18 @@ test('deep import with exports field', async () => { expect(await page.textContent('.exports-deep')).toMatch('[success]') }) +test('deep import with exports field + exposed dir', async () => { + expect(await page.textContent('.exports-deep-exposed-dir')).toMatch( + '[success]' + ) +}) + +test('deep import with exports field + mapped dir', async () => { + expect(await page.textContent('.exports-deep-mapped-dir')).toMatch( + '[success]' + ) +}) + test('omitted index/*', async () => { expect(await page.textContent('.index')).toMatch('[success]') }) diff --git a/packages/playground/resolve/conditional-exports/dir/dir.js b/packages/playground/resolve/conditional-exports/dir/dir.js new file mode 100644 index 00000000000000..2ee34ebc611afb --- /dev/null +++ b/packages/playground/resolve/conditional-exports/dir/dir.js @@ -0,0 +1 @@ +export const msg = '[success] mapped directory from exports' diff --git a/packages/playground/resolve/conditional-exports/package.json b/packages/playground/resolve/conditional-exports/package.json index 60f270c0ddd57b..e98a2c6f8fc72d 100644 --- a/packages/playground/resolve/conditional-exports/package.json +++ b/packages/playground/resolve/conditional-exports/package.json @@ -6,6 +6,11 @@ "import": "./main.js", "require": "./cjs.js" }, - "./deep.js": "./deep.js" + "./deep.js": "./deep.js", + "./dir/": "./dir/", + "./dir-mapped/": { + "import": "./dir/", + "require": "./dir-cjs/" + } } } diff --git a/packages/playground/resolve/index.html b/packages/playground/resolve/index.html index 7e679e071a666c..90d8e52b090221 100644 --- a/packages/playground/resolve/index.html +++ b/packages/playground/resolve/index.html @@ -9,6 +9,12 @@

Entry resolving with exports field

Deep import with exports field

fail

+

Deep import with exports field + exposed directory

+

fail

+ +

Deep import with exports field + mapped directory

+

fail

+

Resolve /index.*

fail

@@ -57,6 +63,14 @@

Inline package

import { msg as deepMsg } from 'resolve-conditional-exports/deep.js' text('.exports-deep', deepMsg) + // deep import w/ exposed dir + import { msg as exposedDirMsg } from 'resolve-conditional-exports/dir/dir' + text('.exports-deep-exposed-dir', exposedDirMsg) + + // deep import w/ mapped dir + import { msg as mappedDirMsg } from 'resolve-conditional-exports/dir-mapped/dir' + text('.exports-deep-mapped-dir', mappedDirMsg) + // implicit index resolving import { foo } from './util' text('.index', foo()) diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 7ce0bb47cceb35..1506935257910e 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -417,13 +417,24 @@ function resolveDeepImport( // map relative based on exports data if (exportsField) { - if ( - isObject(exportsField) && - !Array.isArray(exportsField) && - relativeId in exportsField - ) { - relativeId = resolveConditionalExports(exportsField[relativeId]) - } else { + let isExported = false + if (isObject(exportsField) && !Array.isArray(exportsField)) { + if (relativeId in exportsField) { + relativeId = resolveConditionalExports(exportsField[relativeId]) + isExported = true + } else { + for (const key in exportsField) { + if (key.endsWith('/') && relativeId.startsWith(key)) { + // directory mapping + const replacement = resolveConditionalExports(exportsField[key]) + relativeId = replacement && relativeId.replace(key, replacement) + isExported = true + break + } + } + } + } + if (!isExported || !relativeId) { throw new Error( `Package subpath '${relativeId}' is not defined by "exports" in ` + `${path.join(dir, 'package.json')}.`