diff --git a/packages/playground/vue/vite.config.ts b/packages/playground/vue/vite.config.ts index 82efdac5e9f876..a9ca552cbccda2 100644 --- a/packages/playground/vue/vite.config.ts +++ b/packages/playground/vue/vite.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vite' +import { defineConfig, splitVendorChunkPlugin } from 'vite' import vuePlugin from '@vitejs/plugin-vue' import { vueI18nPlugin } from './CustomBlockPlugin' @@ -12,6 +12,7 @@ export default defineConfig({ vuePlugin({ reactivityTransform: true }), + splitVendorChunkPlugin(), vueI18nPlugin ], build: { diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 84ffb93b432f15..bb724f80415113 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -12,8 +12,6 @@ import type { OutputOptions, RollupOutput, ExternalOption, - GetManualChunk, - GetModuleInfo, WatcherOptions, RollupWatcher, RollupError, @@ -37,7 +35,6 @@ import { dataURIPlugin } from './plugins/dataUri' import { buildImportAnalysisPlugin } from './plugins/importAnalysisBuild' import { resolveSSRExternal, shouldExternalizeForSSR } from './ssr/ssrExternal' import { ssrManifestPlugin } from './ssr/ssrManifestPlugin' -import { isCSSRequest } from './plugins/css' import type { DepOptimizationMetadata } from './optimizer' import { scanImports } from './optimizer/scan' import { assetImportMetaUrlPlugin } from './plugins/assetImportMetaUrl' @@ -509,13 +506,6 @@ async function doBuild( // #1048 add `Symbol.toStringTag` for module default export namespaceToStringTag: true, inlineDynamicImports: ssr && typeof input === 'string', - manualChunks: - !ssr && - !libOptions && - output?.format !== 'umd' && - output?.format !== 'iife' - ? createMoveToVendorChunkFn(config) - : undefined, ...output } } @@ -642,55 +632,6 @@ function getPkgName(root: string) { return name?.startsWith('@') ? name.split('/')[1] : name } -function createMoveToVendorChunkFn(config: ResolvedConfig): GetManualChunk { - const cache = new Map() - return (id, { getModuleInfo }) => { - if ( - id.includes('node_modules') && - !isCSSRequest(id) && - staticImportedByEntry(id, getModuleInfo, cache) - ) { - return 'vendor' - } - } -} - -function staticImportedByEntry( - id: string, - getModuleInfo: GetModuleInfo, - cache: Map, - importStack: string[] = [] -): boolean { - if (cache.has(id)) { - return cache.get(id) as boolean - } - if (importStack.includes(id)) { - // circular deps! - cache.set(id, false) - return false - } - const mod = getModuleInfo(id) - if (!mod) { - cache.set(id, false) - return false - } - - if (mod.isEntry) { - cache.set(id, true) - return true - } - const someImporterIs = mod.importers.some((importer) => - staticImportedByEntry( - importer, - getModuleInfo, - cache, - importStack.concat(id) - ) - ) - cache.set(id, someImporterIs) - return someImporterIs -} - export function resolveLibFilename( libOptions: LibraryOptions, format: ModuleFormat, diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index 158368872877ac..147c834d3ba87f 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -7,6 +7,10 @@ export { send } from './server/send' export { createLogger, printHttpServerUrls } from './logger' export { transformWithEsbuild } from './plugins/esbuild' export { resolvePackageEntry } from './plugins/resolve' +export { + splitVendorChunkPlugin, + splitVendorChunk +} from './plugins/splitVendorChunk' export { resolvePackageData } from './packages' export { normalizePath } from './utils' @@ -91,3 +95,4 @@ export type { Terser } from 'types/terser' export type { RollupCommonJSOptions } from 'types/commonjs' export type { RollupDynamicImportVarsOptions } from 'types/dynamicImportVars' export type { Matcher, AnymatchPattern, AnymatchFn } from 'types/anymatch' +export type { SplitVendorChunkCache } from './plugins/splitVendorChunk' diff --git a/packages/vite/src/node/plugins/splitVendorChunk.ts b/packages/vite/src/node/plugins/splitVendorChunk.ts new file mode 100644 index 00000000000000..9e8958f4620372 --- /dev/null +++ b/packages/vite/src/node/plugins/splitVendorChunk.ts @@ -0,0 +1,95 @@ +import type { Plugin } from '../plugin' +import type { OutputOptions, GetManualChunk, GetModuleInfo } from 'rollup' +import { isCSSRequest } from './css' + +// Use splitVendorChunkPlugin() to get the same manualChunks strategy as Vite 2.7 +// We don't recomment using this strategy as a general solution moving forward + +// splitVendorChunk is a simple index/vendor strategy that was used in Vite +// until v2.8. It is exposed to let people continue to use it in case it was +// working well for their setups. +// The cache needs to be reset on buildStart for watch mode to work correctly +// Don't use this manualChunks strategy for ssr, lib mode, and 'umd' or 'iife' + +export class SplitVendorChunkCache { + cache: Map + constructor() { + this.cache = new Map() + } + reset() { + this.cache = new Map() + } +} + +export function splitVendorChunk({ + cache = new SplitVendorChunkCache() +}): GetManualChunk { + return (id, { getModuleInfo }) => { + if ( + id.includes('node_modules') && + !isCSSRequest(id) && + staticImportedByEntry(id, getModuleInfo, cache.cache) + ) { + return 'vendor' + } + } +} + +function staticImportedByEntry( + id: string, + getModuleInfo: GetModuleInfo, + cache: Map, + importStack: string[] = [] +): boolean { + if (cache.has(id)) { + return cache.get(id) as boolean + } + if (importStack.includes(id)) { + // circular deps! + cache.set(id, false) + return false + } + const mod = getModuleInfo(id) + if (!mod) { + cache.set(id, false) + return false + } + + if (mod.isEntry) { + cache.set(id, true) + return true + } + const someImporterIs = mod.importers.some((importer) => + staticImportedByEntry( + importer, + getModuleInfo, + cache, + importStack.concat(id) + ) + ) + cache.set(id, someImporterIs) + return someImporterIs +} + +export function splitVendorChunkPlugin(): Plugin { + const cache = new SplitVendorChunkCache() + return { + name: 'vite:split-vendor-chunk', + config(config) { + const build = config.build ?? {} + const format = (build.rollupOptions?.output as OutputOptions)?.format + if (!build.ssr && !build.lib && format !== 'umd' && format !== 'iife') { + return { + build: { + rollupOptions: { + manualChunks: splitVendorChunk({ cache }) + } + } + } + } + }, + buildStart() { + cache.reset() + } + } +}