From cba13e8b924fc2c318b4af5324e7c883014e5a8a Mon Sep 17 00:00:00 2001 From: smeng9 <38666763+smeng9@users.noreply.github.com> Date: Wed, 5 Oct 2022 02:45:32 -0500 Subject: [PATCH] fix(optimizer): browser field bare import (fix #7599) (#10314) Co-authored-by: sapphi-red --- packages/vite/src/node/plugins/resolve.ts | 40 ++++++++++++++++++- .../__tests__/optimize-deps.spec.ts | 4 ++ .../dep-cjs-browser-field-bare/events-shim.js | 3 ++ .../dep-cjs-browser-field-bare/index.js | 5 +++ .../dep-cjs-browser-field-bare/internal.js | 6 +++ .../dep-cjs-browser-field-bare/package.json | 9 +++++ playground/optimize-deps/index.html | 6 +++ playground/optimize-deps/package.json | 1 + pnpm-lock.yaml | 11 +++++ 9 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 playground/optimize-deps/dep-cjs-browser-field-bare/events-shim.js create mode 100644 playground/optimize-deps/dep-cjs-browser-field-bare/index.js create mode 100644 playground/optimize-deps/dep-cjs-browser-field-bare/internal.js create mode 100644 playground/optimize-deps/dep-cjs-browser-field-bare/package.json diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index b9476e501ff447..d3672e81c71fe4 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -1106,7 +1106,8 @@ function tryResolveBrowserMapping( externalize?: boolean ) { let res: string | undefined - const pkg = importer && idToPkgMap.get(importer) + const pkg = + importer && (idToPkgMap.get(importer) || resolvePkg(importer, options)) if (pkg && isObject(pkg.data.browser)) { const mapId = isFilePath ? './' + slash(path.relative(pkg.dir, id)) : id const browserMappedPath = mapWithBrowserField(mapId, pkg.data.browser) @@ -1165,3 +1166,40 @@ function getRealPath(resolved: string, preserveSymlinks?: boolean): string { } return normalizePath(resolved) } + +/** + * if importer was not resolved by vite's resolver previously + * (when esbuild resolved it) + * resolve importer's pkg and add to idToPkgMap + */ +function resolvePkg(importer: string, options: InternalResolveOptions) { + const { root, preserveSymlinks, packageCache } = options + + if (importer.includes('\x00')) { + return null + } + + const possiblePkgIds: string[] = [] + for (let prevSlashIndex = -1; ; ) { + const slashIndex = importer.indexOf(isWindows ? '\\' : '/', prevSlashIndex) + if (slashIndex < 0) { + break + } + + prevSlashIndex = slashIndex + 1 + + const possiblePkgId = importer.slice(0, slashIndex) + possiblePkgIds.push(possiblePkgId) + } + + let pkg: PackageData | undefined + possiblePkgIds.reverse().find((pkgId) => { + pkg = resolvePackageData(pkgId, root, preserveSymlinks, packageCache)! + return pkg + })! + + if (pkg) { + idToPkgMap.set(importer, pkg) + } + return pkg +} diff --git a/playground/optimize-deps/__tests__/optimize-deps.spec.ts b/playground/optimize-deps/__tests__/optimize-deps.spec.ts index 997d3bb9da1a26..8d109205855555 100644 --- a/playground/optimize-deps/__tests__/optimize-deps.spec.ts +++ b/playground/optimize-deps/__tests__/optimize-deps.spec.ts @@ -58,6 +58,10 @@ test('cjs browser field (axios)', async () => { expect(await page.textContent('.cjs-browser-field')).toBe('pong') }) +test('cjs browser field bare', async () => { + expect(await page.textContent('.cjs-browser-field-bare')).toBe('pong') +}) + test('dep from linked dep (lodash-es)', async () => { expect(await page.textContent('.deps-linked')).toBe('fooBarBaz') }) diff --git a/playground/optimize-deps/dep-cjs-browser-field-bare/events-shim.js b/playground/optimize-deps/dep-cjs-browser-field-bare/events-shim.js new file mode 100644 index 00000000000000..fb5ce844858a55 --- /dev/null +++ b/playground/optimize-deps/dep-cjs-browser-field-bare/events-shim.js @@ -0,0 +1,3 @@ +module.exports = { + foo: 'foo' +} diff --git a/playground/optimize-deps/dep-cjs-browser-field-bare/index.js b/playground/optimize-deps/dep-cjs-browser-field-bare/index.js new file mode 100644 index 00000000000000..5ea984fdc8a39c --- /dev/null +++ b/playground/optimize-deps/dep-cjs-browser-field-bare/index.js @@ -0,0 +1,5 @@ +'use strict' + +const internal = require('./internal') + +module.exports = internal diff --git a/playground/optimize-deps/dep-cjs-browser-field-bare/internal.js b/playground/optimize-deps/dep-cjs-browser-field-bare/internal.js new file mode 100644 index 00000000000000..6ab4782816a21a --- /dev/null +++ b/playground/optimize-deps/dep-cjs-browser-field-bare/internal.js @@ -0,0 +1,6 @@ +'use strict' + +// eslint-disable-next-line import/no-nodejs-modules +const events = require('events') + +module.exports = 'foo' in events ? 'pong' : '' diff --git a/playground/optimize-deps/dep-cjs-browser-field-bare/package.json b/playground/optimize-deps/dep-cjs-browser-field-bare/package.json new file mode 100644 index 00000000000000..87a42018c9b419 --- /dev/null +++ b/playground/optimize-deps/dep-cjs-browser-field-bare/package.json @@ -0,0 +1,9 @@ +{ + "name": "dep-cjs-browser-field-bare", + "private": true, + "version": "0.0.0", + "main": "index.js", + "browser": { + "events": "./events-shim.js" + } +} diff --git a/playground/optimize-deps/index.html b/playground/optimize-deps/index.html index f3e94ca6624dc1..3ca86a5359781a 100644 --- a/playground/optimize-deps/index.html +++ b/playground/optimize-deps/index.html @@ -29,6 +29,9 @@

Dedupe (dep in linked & optimized package)

CommonJS w/ browser field mapping (axios)

This should show pong:
+

CommonJS w/ bare id browser field mapping

+
This should show pong:
+

Detecting linked src package and optimizing its deps (lodash-es)

This should show fooBarBaz:
@@ -100,6 +103,9 @@

Non Optimized Module isn't duplicated

// test dep detection in globbed files const globbed = import.meta.glob('./glob/*.js', { eager: true }) + import cjsBrowerFieldBare from 'dep-cjs-browser-field-bare' + text('.cjs-browser-field-bare', cjsBrowerFieldBare) + import { camelCase } from 'dep-linked' text('.deps-linked', camelCase('foo-bar-baz')) diff --git a/playground/optimize-deps/package.json b/playground/optimize-deps/package.json index 01bf8259094afe..0441c709cd71a8 100644 --- a/playground/optimize-deps/package.json +++ b/playground/optimize-deps/package.json @@ -11,6 +11,7 @@ "dependencies": { "axios": "^0.27.2", "clipboard": "^2.0.11", + "dep-cjs-browser-field-bare": "file:./dep-cjs-browser-field-bare", "dep-cjs-compiled-from-cjs": "file:./dep-cjs-compiled-from-cjs", "dep-cjs-compiled-from-esm": "file:./dep-cjs-compiled-from-esm", "dep-cjs-with-assets": "file:./dep-cjs-with-assets", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c9eec08453f43..405e698cc5d7a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -645,6 +645,7 @@ importers: added-in-entries: file:./added-in-entries axios: ^0.27.2 clipboard: ^2.0.11 + dep-cjs-browser-field-bare: file:./dep-cjs-browser-field-bare dep-cjs-compiled-from-cjs: file:./dep-cjs-compiled-from-cjs dep-cjs-compiled-from-esm: file:./dep-cjs-compiled-from-esm dep-cjs-with-assets: file:./dep-cjs-with-assets @@ -674,6 +675,7 @@ importers: added-in-entries: file:playground/optimize-deps/added-in-entries axios: 0.27.2 clipboard: 2.0.11 + dep-cjs-browser-field-bare: file:playground/optimize-deps/dep-cjs-browser-field-bare dep-cjs-compiled-from-cjs: file:playground/optimize-deps/dep-cjs-compiled-from-cjs dep-cjs-compiled-from-esm: file:playground/optimize-deps/dep-cjs-compiled-from-esm dep-cjs-with-assets: file:playground/optimize-deps/dep-cjs-with-assets @@ -705,6 +707,9 @@ importers: playground/optimize-deps/added-in-entries: specifiers: {} + playground/optimize-deps/dep-cjs-browser-field-bare: + specifiers: {} + playground/optimize-deps/dep-cjs-compiled-from-cjs: specifiers: {} @@ -9063,6 +9068,12 @@ packages: version: 1.0.0 dev: false + file:playground/optimize-deps/dep-cjs-browser-field-bare: + resolution: {directory: playground/optimize-deps/dep-cjs-browser-field-bare, type: directory} + name: dep-cjs-browser-field-bare + version: 0.0.0 + dev: false + file:playground/optimize-deps/dep-cjs-compiled-from-cjs: resolution: {directory: playground/optimize-deps/dep-cjs-compiled-from-cjs, type: directory} name: dep-cjs-compiled-from-cjs