From 6f182df671f6ab6f7d7b90a1889c8d5bef49e799 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 14 Mar 2023 17:07:55 +0800 Subject: [PATCH 1/3] feat(optimizer): support glob includes --- packages/vite/src/node/optimizer/index.ts | 45 ++--- packages/vite/src/node/optimizer/resolve.ts | 158 ++++++++++++++++++ packages/vite/src/node/plugins/define.ts | 8 +- packages/vite/src/node/ssr/ssrExternal.ts | 11 +- packages/vite/src/node/utils.ts | 14 ++ .../__tests__/optimize-deps.spec.ts | 22 ++- .../glob/bar.js | 0 .../glob/foo.js | 0 .../glob/nested/baz.js | 0 .../dep-optimize-exports-with-glob/index.js | 0 .../dep-optimize-exports-with-glob/named.js | 0 .../package.json | 11 ++ .../dep-optimize-with-glob/glob/bar.js | 0 .../dep-optimize-with-glob/glob/foo.js | 0 .../dep-optimize-with-glob/glob/nested/baz.js | 0 .../dep-optimize-with-glob/index.js | 0 .../dep-optimize-with-glob/named.js | 0 .../dep-optimize-with-glob/package.json | 6 + playground/optimize-deps/package.json | 2 + playground/optimize-deps/vite.config.js | 2 + playground/test-utils.ts | 11 +- pnpm-lock.yaml | 22 +++ 22 files changed, 263 insertions(+), 49 deletions(-) create mode 100644 packages/vite/src/node/optimizer/resolve.ts create mode 100644 playground/optimize-deps/dep-optimize-exports-with-glob/glob/bar.js create mode 100644 playground/optimize-deps/dep-optimize-exports-with-glob/glob/foo.js create mode 100644 playground/optimize-deps/dep-optimize-exports-with-glob/glob/nested/baz.js create mode 100644 playground/optimize-deps/dep-optimize-exports-with-glob/index.js create mode 100644 playground/optimize-deps/dep-optimize-exports-with-glob/named.js create mode 100644 playground/optimize-deps/dep-optimize-exports-with-glob/package.json create mode 100644 playground/optimize-deps/dep-optimize-with-glob/glob/bar.js create mode 100644 playground/optimize-deps/dep-optimize-with-glob/glob/foo.js create mode 100644 playground/optimize-deps/dep-optimize-with-glob/glob/nested/baz.js create mode 100644 playground/optimize-deps/dep-optimize-with-glob/index.js create mode 100644 playground/optimize-deps/dep-optimize-with-glob/named.js create mode 100644 playground/optimize-deps/dep-optimize-with-glob/package.json diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 93989cae446a2f..ffcb6784be946d 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -7,6 +7,7 @@ import colors from 'picocolors' import type { BuildContext, BuildOptions as EsbuildBuildOptions } from 'esbuild' import esbuild, { build } from 'esbuild' import { init, parse } from 'es-module-lexer' +import glob from 'fast-glob' import { createFilter } from '@rollup/pluginutils' import { getDepOptimizationConfig } from '../config' import type { ResolvedConfig } from '../config' @@ -18,7 +19,6 @@ import { getHash, isOptimizable, lookupFile, - nestedResolveFrom, normalizeId, normalizePath, removeDir, @@ -29,6 +29,7 @@ import { transformWithEsbuild } from '../plugins/esbuild' import { ESBUILD_MODULES_TARGET } from '../constants' import { esbuildCjsExternalPlugin, esbuildDepPlugin } from './esbuildDepPlugin' import { scanImports } from './scan' +import { createOptimizeDepsIncludeResolver, expandGlobIds } from './resolve' export { initDepsOptimizer, initDevSsrDepsOptimizer, @@ -813,8 +814,19 @@ export async function addManuallyIncludedOptimizeDeps( ) } } + + const includes = [...optimizeDepsInclude, ...extra] + for (let i = 0; i < includes.length; i++) { + const id = includes[i] + if (glob.isDynamicPattern(id)) { + const globIds = expandGlobIds(id, config) + includes.splice(i, 1, ...globIds) + i += globIds.length - 1 + } + } + const resolve = createOptimizeDepsIncludeResolver(config, ssr) - for (const id of [...optimizeDepsInclude, ...extra]) { + for (const id of includes) { // normalize 'foo >bar` as 'foo > bar' to prevent same id being added // and for pretty printing const normalizedId = normalizeId(id) @@ -836,35 +848,6 @@ export async function addManuallyIncludedOptimizeDeps( } } -function createOptimizeDepsIncludeResolver( - config: ResolvedConfig, - ssr: boolean, -) { - const resolve = config.createResolver({ - asSrc: false, - scan: true, - ssrOptimizeCheck: ssr, - ssrConfig: config.ssr, - }) - return async (id: string) => { - const lastArrowIndex = id.lastIndexOf('>') - if (lastArrowIndex === -1) { - return await resolve(id, undefined, undefined, ssr) - } - // split nested selected id by last '>', for example: - // 'foo > bar > baz' => 'foo > bar' & 'baz' - const nestedRoot = id.substring(0, lastArrowIndex).trim() - const nestedPath = id.substring(lastArrowIndex + 1).trim() - const basedir = nestedResolveFrom( - nestedRoot, - config.root, - config.resolve.preserveSymlinks, - ssr, - ) - return await resolve(nestedPath, basedir, undefined, ssr) - } -} - export function newDepOptimizationProcessing(): DepOptimizationProcessing { let resolve: () => void const promise = new Promise((_resolve) => { diff --git a/packages/vite/src/node/optimizer/resolve.ts b/packages/vite/src/node/optimizer/resolve.ts new file mode 100644 index 00000000000000..0594afda307c8c --- /dev/null +++ b/packages/vite/src/node/optimizer/resolve.ts @@ -0,0 +1,158 @@ +import path from 'node:path' +import glob from 'fast-glob' +import micromatch from 'micromatch' +import type { ResolvedConfig } from '../config' +import { + escapeRegex, + getNpmPackageName, + nestedResolveFrom, + slash, +} from '../utils' +import { resolvePackageData } from '../packages' + +export function createOptimizeDepsIncludeResolver( + config: ResolvedConfig, + ssr: boolean, +): (id: string) => Promise { + const resolve = config.createResolver({ + asSrc: false, + scan: true, + ssrOptimizeCheck: ssr, + ssrConfig: config.ssr, + }) + return async (id: string) => { + const lastArrowIndex = id.lastIndexOf('>') + if (lastArrowIndex === -1) { + return await resolve(id, undefined, undefined, ssr) + } + // split nested selected id by last '>', for example: + // 'foo > bar > baz' => 'foo > bar' & 'baz' + const nestedRoot = id.substring(0, lastArrowIndex).trim() + const nestedPath = id.substring(lastArrowIndex + 1).trim() + const basedir = nestedResolveFrom( + nestedRoot, + config.root, + config.resolve.preserveSymlinks, + ssr, + ) + return await resolve(nestedPath, basedir, undefined, ssr) + } +} + +/** + * Expand the glob syntax in `optimizeDeps.include` to proper import paths + */ +export function expandGlobIds(id: string, config: ResolvedConfig): string[] { + const pkgName = getNpmPackageName(id) + if (!pkgName) return [] + + const pkgData = resolvePackageData( + pkgName, + config.root, + config.resolve.preserveSymlinks, + config.packageCache, + ) + if (!pkgData) return [] + + const pattern = '.' + id.slice(pkgName.length) + const exports = pkgData.data.exports + + // if package has exports field, get all possible export paths and apply + // glob on them with micromatch + if (exports) { + if (typeof exports === 'string' || Array.isArray(exports)) { + return [pkgName] + } + + const possibleExportPaths: string[] = [] + for (const key in exports) { + if (key.startsWith('.')) { + if (key.includes('*')) { + // "./glob/*": { + // "browser": "./dist/glob/*-browser/*.js", <-- get this one + // "default": "./dist/glob/*/*.js" + // } + // NOTE: theoretically the "default" condition could map to a different + // set of files, but that complicates the resolve logic, so we assume + // all conditions map to the same set of files, and get the first one. + const exportsValue = getFirstExportStringValue(exports[key]) + if (!exportsValue) continue + + // "./dist/glob/*-browser/*.js" => "./dist/glob/**/*-browser/**/*.js" + // NOTE: in some cases, this could expand to consecutive /**/*/**/* etc + // but it's fine since fast-glob handles it the same. + const exportValuePattern = exportsValue.replace(/\*/g, '**/*') + // "./dist/glob/*-browser/*.js" => /dist\/glob\/(.*)-browser\/(.*)\.js/ + const exportsValueGlobRe = new RegExp( + exportsValue.split('*').map(escapeRegex).join('(.*)'), + ) + + possibleExportPaths.push( + ...glob + .sync(exportValuePattern, { + cwd: pkgData.dir, + ignore: ['node_modules'], + }) + .map((filePath) => { + // "./glob/*": "./dist/glob/*-browser/*.js" + // `filePath`: "./dist/glob/foo-browser/foo.js" + // we need to revert the file path back to the export key by + // matching value regex and replacing the capture groups to the key + const matched = slash(filePath).match(exportsValueGlobRe) + // `matched`: [..., 'foo', 'foo'] + if (matched) { + let allGlobSame = matched.length === 2 + // exports key can only have one *, so for >=2 matched groups, + // make sure they have the same value + if (!allGlobSame) { + // assume true, if one group is different, set false and break + allGlobSame = true + for (let i = 2; i < matched.length; i++) { + if (matched[i] !== matched[i - 1]) { + allGlobSame = false + break + } + } + } + if (allGlobSame) { + return key.replace('*', matched[1]).slice(2) + } + } + return '' + }) + .filter(Boolean), + ) + } else { + possibleExportPaths.push(key.slice(2)) + } + } + } + + const matched = micromatch(possibleExportPaths, pattern).map((match) => + path.posix.join(pkgName, match), + ) + matched.unshift(pkgName) + return matched + } else { + // for packages without exports, we can do a simple glob + const matched = glob + .sync(pattern, { cwd: pkgData.dir, ignore: ['node_modules'] }) + .map((match) => path.posix.join(pkgName, slash(match))) + matched.unshift(pkgName) + return matched + } +} + +function getFirstExportStringValue( + obj: string | string[] | Record, +): string | undefined { + if (typeof obj === 'string') { + return obj + } else if (Array.isArray(obj)) { + return obj[0] + } else { + for (const key in obj) { + return getFirstExportStringValue(obj[key]) + } + } +} diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index f47a3ff97fed64..c0c37183b81aaf 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -1,7 +1,7 @@ import MagicString from 'magic-string' import type { ResolvedConfig } from '../config' import type { Plugin } from '../plugin' -import { transformStableResult } from '../utils' +import { escapeRegex, transformStableResult } from '../utils' import { isCSSRequest } from './css' import { isHTMLRequest } from './html' @@ -113,11 +113,7 @@ export function definePlugin(config: ResolvedConfig): Plugin { // Mustn't be preceded by a char that can be part of an identifier // or a '.' that isn't part of a spread operator '(? { - return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&') - }) - .join('|') + + replacementsKeys.map(escapeRegex).join('|') + // Mustn't be followed by a char that can be part of an identifier // or an assignment (but allow equality operators) ')(?:(?<=\\.)|(?![\\p{L}\\p{N}_$]|\\s*?=[^=]))', diff --git a/packages/vite/src/node/ssr/ssrExternal.ts b/packages/vite/src/node/ssr/ssrExternal.ts index ce08b020d17fbf..8289ec4edb43e5 100644 --- a/packages/vite/src/node/ssr/ssrExternal.ts +++ b/packages/vite/src/node/ssr/ssrExternal.ts @@ -7,6 +7,7 @@ import { bareImportRE, createDebugger, createFilter, + getNpmPackageName, isBuiltin, isDefined, lookupFile, @@ -337,13 +338,3 @@ export function cjsShouldExternalizeForSSR( }) return should } - -function getNpmPackageName(importPath: string): string | null { - const parts = importPath.split('/') - if (parts[0].startsWith('@')) { - if (!parts[1]) return null - return `${parts[0]}/${parts[1]}` - } else { - return parts[0] - } -} diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 4cb6931e7317de..5580c20f892f72 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -1273,3 +1273,17 @@ export function evalValue(rawValue: string): T { `) return fn() } + +export function getNpmPackageName(importPath: string): string | null { + const parts = importPath.split('/') + if (parts[0].startsWith('@')) { + if (!parts[1]) return null + return `${parts[0]}/${parts[1]}` + } else { + return parts[0] + } +} + +export function escapeRegex(str: string): string { + return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&') +} diff --git a/playground/optimize-deps/__tests__/optimize-deps.spec.ts b/playground/optimize-deps/__tests__/optimize-deps.spec.ts index bb0841e5b72f65..abcb77c96045e7 100644 --- a/playground/optimize-deps/__tests__/optimize-deps.spec.ts +++ b/playground/optimize-deps/__tests__/optimize-deps.spec.ts @@ -1,4 +1,4 @@ -import { expect, test } from 'vitest' +import { describe, expect, test } from 'vitest' import { browserErrors, browserLogs, @@ -6,6 +6,7 @@ import { isBuild, isServe, page, + readDepOptimizationMetadata, } from '~utils' test('default + named imports from cjs dep (react)', async () => { @@ -200,3 +201,22 @@ test.runIf(isServe)('error on builtin modules usage', () => { ]), ) }) + +describe.runIf(isServe)('optimizeDeps config', () => { + test('supports include glob syntax', () => { + const metadata = readDepOptimizationMetadata() + expect(Object.keys(metadata.optimized)).to.include.members([ + '@vitejs/test-dep-optimize-exports-with-glob', + '@vitejs/test-dep-optimize-exports-with-glob/named', + '@vitejs/test-dep-optimize-exports-with-glob/glob-dir/foo', + '@vitejs/test-dep-optimize-exports-with-glob/glob-dir/bar', + '@vitejs/test-dep-optimize-exports-with-glob/glob-dir/nested/baz', + '@vitejs/test-dep-optimize-with-glob', + '@vitejs/test-dep-optimize-with-glob/index.js', + '@vitejs/test-dep-optimize-with-glob/named.js', + '@vitejs/test-dep-optimize-with-glob/glob/foo.js', + '@vitejs/test-dep-optimize-with-glob/glob/bar.js', + '@vitejs/test-dep-optimize-with-glob/glob/nested/baz.js', + ]) + }) +}) diff --git a/playground/optimize-deps/dep-optimize-exports-with-glob/glob/bar.js b/playground/optimize-deps/dep-optimize-exports-with-glob/glob/bar.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-exports-with-glob/glob/foo.js b/playground/optimize-deps/dep-optimize-exports-with-glob/glob/foo.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-exports-with-glob/glob/nested/baz.js b/playground/optimize-deps/dep-optimize-exports-with-glob/glob/nested/baz.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-exports-with-glob/index.js b/playground/optimize-deps/dep-optimize-exports-with-glob/index.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-exports-with-glob/named.js b/playground/optimize-deps/dep-optimize-exports-with-glob/named.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-exports-with-glob/package.json b/playground/optimize-deps/dep-optimize-exports-with-glob/package.json new file mode 100644 index 00000000000000..3a5936bc882613 --- /dev/null +++ b/playground/optimize-deps/dep-optimize-exports-with-glob/package.json @@ -0,0 +1,11 @@ +{ + "name": "@vitejs/test-dep-optimize-exports-with-glob", + "private": true, + "version": "1.0.0", + "type": "module", + "exports": { + ".": "./index.js", + "./named": "./named.js", + "./glob-dir/*": "./glob/*.js" + } +} diff --git a/playground/optimize-deps/dep-optimize-with-glob/glob/bar.js b/playground/optimize-deps/dep-optimize-with-glob/glob/bar.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-with-glob/glob/foo.js b/playground/optimize-deps/dep-optimize-with-glob/glob/foo.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-with-glob/glob/nested/baz.js b/playground/optimize-deps/dep-optimize-with-glob/glob/nested/baz.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-with-glob/index.js b/playground/optimize-deps/dep-optimize-with-glob/index.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-with-glob/named.js b/playground/optimize-deps/dep-optimize-with-glob/named.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/optimize-deps/dep-optimize-with-glob/package.json b/playground/optimize-deps/dep-optimize-with-glob/package.json new file mode 100644 index 00000000000000..b640f9453e3a9f --- /dev/null +++ b/playground/optimize-deps/dep-optimize-with-glob/package.json @@ -0,0 +1,6 @@ +{ + "name": "@vitejs/test-dep-optimize-with-glob", + "private": true, + "version": "1.0.0", + "type": "module" +} diff --git a/playground/optimize-deps/package.json b/playground/optimize-deps/package.json index da52abead01850..de1439ee21fb3d 100644 --- a/playground/optimize-deps/package.json +++ b/playground/optimize-deps/package.json @@ -21,6 +21,8 @@ "@vitejs/test-dep-linked-include": "link:./dep-linked-include", "@vitejs/test-dep-node-env": "file:./dep-node-env", "@vitejs/test-dep-not-js": "file:./dep-not-js", + "@vitejs/test-dep-optimize-exports-with-glob": "file:./dep-optimize-exports-with-glob", + "@vitejs/test-dep-optimize-with-glob": "file:./dep-optimize-with-glob", "@vitejs/test-dep-relative-to-main": "file:./dep-relative-to-main", "@vitejs/test-dep-with-builtin-module-cjs": "file:./dep-with-builtin-module-cjs", "@vitejs/test-dep-with-builtin-module-esm": "file:./dep-with-builtin-module-esm", diff --git a/playground/optimize-deps/vite.config.js b/playground/optimize-deps/vite.config.js index 7eb4c5b10c3101..a3048f8bf864f6 100644 --- a/playground/optimize-deps/vite.config.js +++ b/playground/optimize-deps/vite.config.js @@ -21,6 +21,8 @@ export default defineConfig({ '@vitejs/test-nested-exclude > @vitejs/test-nested-include', // will throw if optimized (should log warning instead) '@vitejs/test-non-optimizable-include', + '@vitejs/test-dep-optimize-exports-with-glob/**/*', + '@vitejs/test-dep-optimize-with-glob/**/*.js', ], exclude: ['@vitejs/test-nested-exclude', '@vitejs/test-dep-non-optimized'], esbuildOptions: { diff --git a/playground/test-utils.ts b/playground/test-utils.ts index d2aafaff4b2aca..07ddcaa625a7fc 100644 --- a/playground/test-utils.ts +++ b/playground/test-utils.ts @@ -5,7 +5,7 @@ import fs from 'node:fs' import path from 'node:path' import colors from 'css-color-names' import type { ConsoleMessage, ElementHandle } from 'playwright-chromium' -import type { Manifest } from 'vite' +import type { DepOptimizationMetadata, Manifest } from 'vite' import { normalizePath } from 'vite' import { fromComment } from 'convert-source-map' import { expect } from 'vitest' @@ -145,6 +145,15 @@ export function readManifest(base = ''): Manifest { ) } +export function readDepOptimizationMetadata(): DepOptimizationMetadata { + return JSON.parse( + fs.readFileSync( + path.join(testDir, 'node_modules/.vite/deps/_metadata.json'), + 'utf-8', + ), + ) +} + /** * Poll a getter until the value it returns includes the expected value. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16a012761797ae..3f511565592fd7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -630,6 +630,8 @@ importers: '@vitejs/test-dep-node-env': file:./dep-node-env '@vitejs/test-dep-non-optimized': file:./dep-non-optimized '@vitejs/test-dep-not-js': file:./dep-not-js + '@vitejs/test-dep-optimize-exports-with-glob': file:./dep-optimize-exports-with-glob + '@vitejs/test-dep-optimize-with-glob': file:./dep-optimize-with-glob '@vitejs/test-dep-relative-to-main': file:./dep-relative-to-main '@vitejs/test-dep-with-builtin-module-cjs': file:./dep-with-builtin-module-cjs '@vitejs/test-dep-with-builtin-module-esm': file:./dep-with-builtin-module-esm @@ -661,6 +663,8 @@ importers: '@vitejs/test-dep-node-env': file:playground/optimize-deps/dep-node-env '@vitejs/test-dep-non-optimized': file:playground/optimize-deps/dep-non-optimized '@vitejs/test-dep-not-js': file:playground/optimize-deps/dep-not-js + '@vitejs/test-dep-optimize-exports-with-glob': file:playground/optimize-deps/dep-optimize-exports-with-glob + '@vitejs/test-dep-optimize-with-glob': file:playground/optimize-deps/dep-optimize-with-glob '@vitejs/test-dep-relative-to-main': file:playground/optimize-deps/dep-relative-to-main '@vitejs/test-dep-with-builtin-module-cjs': file:playground/optimize-deps/dep-with-builtin-module-cjs '@vitejs/test-dep-with-builtin-module-esm': file:playground/optimize-deps/dep-with-builtin-module-esm @@ -725,6 +729,12 @@ importers: playground/optimize-deps/dep-not-js: specifiers: {} + playground/optimize-deps/dep-optimize-exports-with-glob: + specifiers: {} + + playground/optimize-deps/dep-optimize-with-glob: + specifiers: {} + playground/optimize-deps/dep-relative-to-main: specifiers: {} @@ -10081,6 +10091,18 @@ packages: version: 1.0.0 dev: false + file:playground/optimize-deps/dep-optimize-exports-with-glob: + resolution: {directory: playground/optimize-deps/dep-optimize-exports-with-glob, type: directory} + name: '@vitejs/test-dep-optimize-exports-with-glob' + version: 1.0.0 + dev: false + + file:playground/optimize-deps/dep-optimize-with-glob: + resolution: {directory: playground/optimize-deps/dep-optimize-with-glob, type: directory} + name: '@vitejs/test-dep-optimize-with-glob' + version: 1.0.0 + dev: false + file:playground/optimize-deps/dep-relative-to-main: resolution: {directory: playground/optimize-deps/dep-relative-to-main, type: directory} name: '@vitejs/test-dep-relative-to-main' From 806b72560996ad6db1a8f9e123bfc53aa23f8545 Mon Sep 17 00:00:00 2001 From: bluwy Date: Sun, 9 Apr 2023 00:16:15 +0800 Subject: [PATCH 2/3] chore: fix merge --- packages/vite/src/node/optimizer/index.ts | 1 - packages/vite/src/node/optimizer/resolve.ts | 26 ++++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 8a33803cc068b5..fea26116c18778 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -27,7 +27,6 @@ import { } from '../utils' import { transformWithEsbuild } from '../plugins/esbuild' import { ESBUILD_MODULES_TARGET } from '../constants' -import { resolvePackageData } from '../packages' import type { ViteDevServer } from '../server' import { esbuildCjsExternalPlugin, esbuildDepPlugin } from './esbuildDepPlugin' import { scanImports } from './scan' diff --git a/packages/vite/src/node/optimizer/resolve.ts b/packages/vite/src/node/optimizer/resolve.ts index 0594afda307c8c..27edd088c2d250 100644 --- a/packages/vite/src/node/optimizer/resolve.ts +++ b/packages/vite/src/node/optimizer/resolve.ts @@ -2,12 +2,7 @@ import path from 'node:path' import glob from 'fast-glob' import micromatch from 'micromatch' import type { ResolvedConfig } from '../config' -import { - escapeRegex, - getNpmPackageName, - nestedResolveFrom, - slash, -} from '../utils' +import { escapeRegex, getNpmPackageName, slash } from '../utils' import { resolvePackageData } from '../packages' export function createOptimizeDepsIncludeResolver( @@ -19,6 +14,7 @@ export function createOptimizeDepsIncludeResolver( scan: true, ssrOptimizeCheck: ssr, ssrConfig: config.ssr, + packageCache: new Map(), }) return async (id: string) => { const lastArrowIndex = id.lastIndexOf('>') @@ -29,11 +25,10 @@ export function createOptimizeDepsIncludeResolver( // 'foo > bar > baz' => 'foo > bar' & 'baz' const nestedRoot = id.substring(0, lastArrowIndex).trim() const nestedPath = id.substring(lastArrowIndex + 1).trim() - const basedir = nestedResolveFrom( + const basedir = nestedResolveBasedir( nestedRoot, config.root, config.resolve.preserveSymlinks, - ssr, ) return await resolve(nestedPath, basedir, undefined, ssr) } @@ -156,3 +151,18 @@ function getFirstExportStringValue( } } } + +/** + * Continuously resolve the basedir of packages separated by '>' + */ +function nestedResolveBasedir( + id: string, + basedir: string, + preserveSymlinks = false, +) { + const pkgs = id.split('>').map((pkg) => pkg.trim()) + for (const pkg of pkgs) { + basedir = resolvePackageData(pkg, basedir, preserveSymlinks)?.dir || basedir + } + return basedir +} From 7bc5832a32b347e5cb0a1abd6c61245d58edb8d0 Mon Sep 17 00:00:00 2001 From: bluwy Date: Sun, 9 Apr 2023 00:23:28 +0800 Subject: [PATCH 3/3] docs: add docs --- docs/config/dep-optimization-options.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/config/dep-optimization-options.md b/docs/config/dep-optimization-options.md index 6c7f372a02109c..09f4c5b495f729 100644 --- a/docs/config/dep-optimization-options.md +++ b/docs/config/dep-optimization-options.md @@ -35,6 +35,16 @@ export default defineConfig({ By default, linked packages not inside `node_modules` are not pre-bundled. Use this option to force a linked package to be pre-bundled. +**Experimental:** If you're using a library with many deep imports, you can also specify a trailing glob pattern to pre-bundle all deep imports at once. This will avoid constantly pre-bundling whenever a new deep import is used. For example: + +```js +export default defineConfig({ + optimizeDeps: { + include: ['my-lib/components/**/*.vue'], + }, +}) +``` + ## optimizeDeps.esbuildOptions - **Type:** [`EsbuildBuildOptions`](https://esbuild.github.io/api/#simple-options)