From d0fda583df94b6045fd34b6f3333b57d5f3bfa5e Mon Sep 17 00:00:00 2001 From: patak-dev Date: Mon, 17 Jan 2022 09:35:14 +0100 Subject: [PATCH 1/9] refactor: avoid splitting vendor chunk by default --- packages/playground/vue/vite.config.ts | 3 +- packages/vite/src/node/build.ts | 59 ------------ packages/vite/src/node/index.ts | 5 + .../vite/src/node/plugins/splitVendorChunk.ts | 95 +++++++++++++++++++ 4 files changed, 102 insertions(+), 60 deletions(-) create mode 100644 packages/vite/src/node/plugins/splitVendorChunk.ts 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() + } + } +} From 641e725ac7e8dbfdca96ec06a0985e0893066e86 Mon Sep 17 00:00:00 2001 From: patak Date: Mon, 17 Jan 2022 15:16:59 +0100 Subject: [PATCH 2/9] chore: fix typo Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- packages/vite/src/node/plugins/splitVendorChunk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/splitVendorChunk.ts b/packages/vite/src/node/plugins/splitVendorChunk.ts index 9e8958f4620372..b4125717737efa 100644 --- a/packages/vite/src/node/plugins/splitVendorChunk.ts +++ b/packages/vite/src/node/plugins/splitVendorChunk.ts @@ -3,7 +3,7 @@ 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 +// We don't recommend 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 From 0a06f137c11a58d83f2371ec14a78dfe87c0408a Mon Sep 17 00:00:00 2001 From: patak-dev Date: Mon, 17 Jan 2022 16:10:38 +0100 Subject: [PATCH 3/9] docs: add section to build guide --- docs/guide/build.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/guide/build.md b/docs/guide/build.md index aac86a237b6819..53faf5189d502c 100644 --- a/docs/guide/build.md +++ b/docs/guide/build.md @@ -43,6 +43,20 @@ module.exports = defineConfig({ For example, you can specify multiple Rollup outputs with plugins that are only applied during build. +## Chunking Strategy + +You can configure how chunks are split using `build.rollupOptions.manualChunks` (see [Rollup docs](https://rollupjs.org/guide/en/#outputmanualchunks)). Until Vite 2.7, the default chunking strategy divided the chunks into `index` and `vendor`. It is a good strategy for some SPAs, but it is hard to provide a general solution for every Vite target use case. From Vite 2.8, `manualChunks` is no longer modified by default. You can continue to use the Split Vendor Chunk strategy by adding the `splitVendorChunkPlugin` in your config file: + +```js +// vite.config.js +import { splitVendorChunkPlugin } from 'vite' +module.exports = defineConfig({ + plugins: [splitVendorChunkPlugin()] +}) +``` + +This strategy is also provided as a `splitVendorChunk({ cache: SplitVendorChunkCache )` factory, in case composition with custom logic is needed. `cache.reset()` needs to be called at `buildStart` for build watch mode to work correctly in this case. + ## Rebuild on files changes You can enable rollup watcher with `vite build --watch`. Or, you can directly adjust the underlying [`WatcherOptions`](https://rollupjs.org/guide/en/#watch-options) via `build.watch`: From 2306dad255bcfc932f9c97b1495a19bf9dc1ae71 Mon Sep 17 00:00:00 2001 From: patak-dev Date: Mon, 17 Jan 2022 21:44:33 +0100 Subject: [PATCH 4/9] fix: account for rollupOptions.output array --- .../vite/src/node/plugins/splitVendorChunk.ts | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/vite/src/node/plugins/splitVendorChunk.ts b/packages/vite/src/node/plugins/splitVendorChunk.ts index b4125717737efa..14c088bb546da2 100644 --- a/packages/vite/src/node/plugins/splitVendorChunk.ts +++ b/packages/vite/src/node/plugins/splitVendorChunk.ts @@ -1,3 +1,4 @@ +import type { UserConfig } from '../../node' import type { Plugin } from '../plugin' import type { OutputOptions, GetManualChunk, GetModuleInfo } from 'rollup' import { isCSSRequest } from './css' @@ -72,24 +73,37 @@ function staticImportedByEntry( } export function splitVendorChunkPlugin(): Plugin { - const cache = new SplitVendorChunkCache() + const caches: SplitVendorChunkCache[] = [] + function createSplitVendorChunk(output: OutputOptions, config: UserConfig) { + const cache = new SplitVendorChunkCache() + caches.push(cache) + const build = config.build ?? {} + const format = output?.format + if (!build.ssr && !build.lib && format !== 'umd' && format !== 'iife') { + return splitVendorChunk({ cache }) + } + } 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') { + let outputs = config?.build?.rollupOptions?.output + if (outputs) { + outputs = Array.isArray(outputs) ? outputs : [outputs] + for (const output of outputs) { + output.manualChunks = createSplitVendorChunk(output, config) + } + } else { return { build: { rollupOptions: { - manualChunks: splitVendorChunk({ cache }) + manualChunks: createSplitVendorChunk({}, config) } } } } }, buildStart() { - cache.reset() + caches.forEach((cache) => cache.reset()) } } } From 41421c4cee6bd70ada50f955ea05da89fc3e4f15 Mon Sep 17 00:00:00 2001 From: patak Date: Fri, 28 Jan 2022 07:34:46 +0100 Subject: [PATCH 5/9] chore: fix type Co-authored-by: ygj6 <7699524+ygj6@users.noreply.github.com> --- docs/guide/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/build.md b/docs/guide/build.md index 53faf5189d502c..1f1f149a07f7c9 100644 --- a/docs/guide/build.md +++ b/docs/guide/build.md @@ -55,7 +55,7 @@ module.exports = defineConfig({ }) ``` -This strategy is also provided as a `splitVendorChunk({ cache: SplitVendorChunkCache )` factory, in case composition with custom logic is needed. `cache.reset()` needs to be called at `buildStart` for build watch mode to work correctly in this case. +This strategy is also provided as a `splitVendorChunk({ cache: SplitVendorChunkCache })` factory, in case composition with custom logic is needed. `cache.reset()` needs to be called at `buildStart` for build watch mode to work correctly in this case. ## Rebuild on files changes From 9e07062947bbf0ff1d27e6c9fe9e2b6fed40031a Mon Sep 17 00:00:00 2001 From: patak Date: Fri, 28 Jan 2022 07:36:16 +0100 Subject: [PATCH 6/9] chore: fix default value --- packages/vite/src/node/plugins/splitVendorChunk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/splitVendorChunk.ts b/packages/vite/src/node/plugins/splitVendorChunk.ts index 14c088bb546da2..7973cb499679ca 100644 --- a/packages/vite/src/node/plugins/splitVendorChunk.ts +++ b/packages/vite/src/node/plugins/splitVendorChunk.ts @@ -24,7 +24,7 @@ export class SplitVendorChunkCache { export function splitVendorChunk({ cache = new SplitVendorChunkCache() -}): GetManualChunk { +} = {}): GetManualChunk { return (id, { getModuleInfo }) => { if ( id.includes('node_modules') && From a4d75bc0ad97cd019a101ff62ea12c808bdecc21 Mon Sep 17 00:00:00 2001 From: patak-dev Date: Fri, 28 Jan 2022 07:44:16 +0100 Subject: [PATCH 7/9] chore: update --- packages/vite/src/node/plugins/splitVendorChunk.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/vite/src/node/plugins/splitVendorChunk.ts b/packages/vite/src/node/plugins/splitVendorChunk.ts index 7973cb499679ca..09246e14e35234 100644 --- a/packages/vite/src/node/plugins/splitVendorChunk.ts +++ b/packages/vite/src/node/plugins/splitVendorChunk.ts @@ -22,9 +22,10 @@ export class SplitVendorChunkCache { } } -export function splitVendorChunk({ - cache = new SplitVendorChunkCache() -} = {}): GetManualChunk { +export function splitVendorChunk( + options: { cache?: SplitVendorChunkCache } = {} +): GetManualChunk { + const cache = options.cache ?? new SplitVendorChunkCache() return (id, { getModuleInfo }) => { if ( id.includes('node_modules') && From 55a17ef1571b5e31b28d0db413f34a55dce0954f Mon Sep 17 00:00:00 2001 From: patak-dev Date: Sat, 29 Jan 2022 18:03:51 +0100 Subject: [PATCH 8/9] refactor: split vendor plugin in separate package --- README.md | 17 +++-- docs/guide/build.md | 8 +- docs/plugins/index.md | 4 + packages/playground/vue/package.json | 1 + packages/playground/vue/vite.config.ts | 5 +- packages/plugin-split-vendor/CHANGELOG.md | 3 + packages/plugin-split-vendor/LICENSE | 21 ++++++ packages/plugin-split-vendor/README.md | 13 ++++ packages/plugin-split-vendor/index.d.ts | 11 +++ .../index.js} | 75 ++++++++++++------- packages/plugin-split-vendor/package.json | 31 ++++++++ packages/vite/src/node/index.ts | 5 -- pnpm-lock.yaml | 8 ++ 13 files changed, 157 insertions(+), 45 deletions(-) create mode 100644 packages/plugin-split-vendor/CHANGELOG.md create mode 100644 packages/plugin-split-vendor/LICENSE create mode 100644 packages/plugin-split-vendor/README.md create mode 100644 packages/plugin-split-vendor/index.d.ts rename packages/{vite/src/node/plugins/splitVendorChunk.ts => plugin-split-vendor/index.js} (55%) create mode 100644 packages/plugin-split-vendor/package.json diff --git a/README.md b/README.md index be96a1bcf73ada..6ae5903b82e544 100644 --- a/README.md +++ b/README.md @@ -39,14 +39,15 @@ Check out the [Migration Guide](https://vitejs.dev/guide/migration.html) if you ## Packages -| Package | Version (click for changelogs) | -| ------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------- | -| [vite](packages/vite) | [![vite version](https://img.shields.io/npm/v/vite.svg?label=%20)](packages/vite/CHANGELOG.md) | -| [@vitejs/plugin-vue](packages/plugin-vue) | [![plugin-vue version](https://img.shields.io/npm/v/@vitejs/plugin-vue.svg?label=%20)](packages/plugin-vue/CHANGELOG.md) | -| [@vitejs/plugin-vue-jsx](packages/plugin-vue-jsx) | [![plugin-vue-jsx version](https://img.shields.io/npm/v/@vitejs/plugin-vue-jsx.svg?label=%20)](packages/plugin-vue-jsx/CHANGELOG.md) | -| [@vitejs/plugin-react](packages/plugin-react) | [![plugin-react version](https://img.shields.io/npm/v/@vitejs/plugin-react.svg?label=%20)](packages/plugin-react/CHANGELOG.md) | -| [@vitejs/plugin-legacy](packages/plugin-legacy) | [![plugin-legacy version](https://img.shields.io/npm/v/@vitejs/plugin-legacy.svg?label=%20)](packages/plugin-legacy/CHANGELOG.md) | -| [create-vite](packages/create-vite) | [![create-vite version](https://img.shields.io/npm/v/create-vite.svg?label=%20)](packages/create-vite/CHANGELOG.md) | +| Package | Version (click for changelogs) | +| ----------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | +| [vite](packages/vite) | [![vite version](https://img.shields.io/npm/v/vite.svg?label=%20)](packages/vite/CHANGELOG.md) | +| [@vitejs/plugin-vue](packages/plugin-vue) | [![plugin-vue version](https://img.shields.io/npm/v/@vitejs/plugin-vue.svg?label=%20)](packages/plugin-vue/CHANGELOG.md) | +| [@vitejs/plugin-vue-jsx](packages/plugin-vue-jsx) | [![plugin-vue-jsx version](https://img.shields.io/npm/v/@vitejs/plugin-vue-jsx.svg?label=%20)](packages/plugin-vue-jsx/CHANGELOG.md) | +| [@vitejs/plugin-react](packages/plugin-react) | [![plugin-react version](https://img.shields.io/npm/v/@vitejs/plugin-react.svg?label=%20)](packages/plugin-react/CHANGELOG.md) | +| [@vitejs/plugin-legacy](packages/plugin-legacy) | [![plugin-legacy version](https://img.shields.io/npm/v/@vitejs/plugin-legacy.svg?label=%20)](packages/plugin-legacy/CHANGELOG.md) | +| [@vitejs/plugin-split-vendor](packages/plugin-split-vendor) | [![plugin-split-vendor version](https://img.shields.io/npm/v/@vitejs/plugin-split-vendor.svg?label=%20)](packages/plugin-vue-jsx/CHANGELOG.md) | +| [create-vite](packages/create-vite) | [![create-vite version](https://img.shields.io/npm/v/create-vite.svg?label=%20)](packages/create-vite/CHANGELOG.md) | ## Contribution diff --git a/docs/guide/build.md b/docs/guide/build.md index 1f1f149a07f7c9..e081c44c94f314 100644 --- a/docs/guide/build.md +++ b/docs/guide/build.md @@ -45,17 +45,17 @@ For example, you can specify multiple Rollup outputs with plugins that are only ## Chunking Strategy -You can configure how chunks are split using `build.rollupOptions.manualChunks` (see [Rollup docs](https://rollupjs.org/guide/en/#outputmanualchunks)). Until Vite 2.7, the default chunking strategy divided the chunks into `index` and `vendor`. It is a good strategy for some SPAs, but it is hard to provide a general solution for every Vite target use case. From Vite 2.8, `manualChunks` is no longer modified by default. You can continue to use the Split Vendor Chunk strategy by adding the `splitVendorChunkPlugin` in your config file: +You can configure how chunks are split using `build.rollupOptions.manualChunks` (see [Rollup docs](https://rollupjs.org/guide/en/#outputmanualchunks)). Until Vite 2.7, the default chunking strategy divided the chunks into `index` and `vendor`. It is a good strategy for some SPAs, but it is hard to provide a general solution for every Vite target use case. From Vite 2.8, `manualChunks` is no longer modified by default. You can continue to use the Split Vendor Chunk strategy by adding the `splitVendorPlugin` from the `@vitejs/plugin-split-vendor` package in your config file: ```js // vite.config.js -import { splitVendorChunkPlugin } from 'vite' +import { splitVendorPlugin } from '@vitejs/plugin-split-vendor' module.exports = defineConfig({ - plugins: [splitVendorChunkPlugin()] + plugins: [splitVendorPlugin()] }) ``` -This strategy is also provided as a `splitVendorChunk({ cache: SplitVendorChunkCache })` factory, in case composition with custom logic is needed. `cache.reset()` needs to be called at `buildStart` for build watch mode to work correctly in this case. +This strategy is also provided as a `splitVendor({ cache: SplitVendorCache })` factory, in case composition with custom logic is needed. `cache.reset()` needs to be called at `buildStart` for build watch mode to work correctly in this case. ## Rebuild on files changes diff --git a/docs/plugins/index.md b/docs/plugins/index.md index 6d81a060cf8883..96be62cdde498d 100644 --- a/docs/plugins/index.md +++ b/docs/plugins/index.md @@ -22,6 +22,10 @@ Vite aims to provide out-of-the-box support for common web development patterns. - Provides legacy browsers support for the production build. +### [@vitejs/plugin-split-vendor](https://github.com/vitejs/vite/tree/main/packages/plugin-split-vendor) + +- Provides `manualChunks` strategy from Vite <=2.7 + ## Community Plugins Check out [awesome-vite](https://github.com/vitejs/awesome-vite#plugins) - you can also submit a PR to list your plugins there. diff --git a/packages/playground/vue/package.json b/packages/playground/vue/package.json index c88fb7ee6343f4..38a1776aadc59b 100644 --- a/packages/playground/vue/package.json +++ b/packages/playground/vue/package.json @@ -14,6 +14,7 @@ }, "devDependencies": { "@vitejs/plugin-vue": "workspace:*", + "@vitejs/plugin-split-vendor": "workspace:*", "js-yaml": "^4.1.0", "less": "^4.1.2", "pug": "^3.0.2", diff --git a/packages/playground/vue/vite.config.ts b/packages/playground/vue/vite.config.ts index a9ca552cbccda2..16222d1f31f794 100644 --- a/packages/playground/vue/vite.config.ts +++ b/packages/playground/vue/vite.config.ts @@ -1,5 +1,6 @@ -import { defineConfig, splitVendorChunkPlugin } from 'vite' +import { defineConfig } from 'vite' import vuePlugin from '@vitejs/plugin-vue' +import { splitVendorPlugin } from '@vitejs/plugin-split-vendor' import { vueI18nPlugin } from './CustomBlockPlugin' export default defineConfig({ @@ -12,7 +13,7 @@ export default defineConfig({ vuePlugin({ reactivityTransform: true }), - splitVendorChunkPlugin(), + splitVendorPlugin(), vueI18nPlugin ], build: { diff --git a/packages/plugin-split-vendor/CHANGELOG.md b/packages/plugin-split-vendor/CHANGELOG.md new file mode 100644 index 00000000000000..b28b04f643122b --- /dev/null +++ b/packages/plugin-split-vendor/CHANGELOG.md @@ -0,0 +1,3 @@ + + + diff --git a/packages/plugin-split-vendor/LICENSE b/packages/plugin-split-vendor/LICENSE new file mode 100644 index 00000000000000..9c1b313d7b1816 --- /dev/null +++ b/packages/plugin-split-vendor/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/plugin-split-vendor/README.md b/packages/plugin-split-vendor/README.md new file mode 100644 index 00000000000000..76b48478ae49f4 --- /dev/null +++ b/packages/plugin-split-vendor/README.md @@ -0,0 +1,13 @@ +# @vitejs/plugin-split-vendor [![npm](https://img.shields.io/npm/v/@vitejs/plugin-split-vendor.svg)](https://npmjs.com/package/@vitejs/plugin-split-vendor) + +You can configure how chunks are split using `build.rollupOptions.manualChunks` (see [Rollup docs](https://rollupjs.org/guide/en/#outputmanualchunks)). Until Vite 2.7, the default chunking strategy divided the chunks into `index` and `vendor`. It is a good strategy for some SPAs, but it is hard to provide a general solution for every Vite target use case. From Vite 2.8, `manualChunks` is no longer modified by default. You can continue to use the Split Vendor Chunk strategy by adding the `splitVendorPlugin` from the `@vitejs/plugin-split-vendor` package in your config file: + +```js +// vite.config.js +import { splitVendorPlugin } from '@vitejs/plugin-split-vendor' +module.exports = defineConfig({ + plugins: [splitVendorPlugin()] +}) +``` + +This strategy is also provided as a `splitVendor({ cache: SplitVendorCache })` factory, in case composition with custom logic is needed. `cache.reset()` needs to be called at `buildStart` for build watch mode to work correctly in this case. diff --git a/packages/plugin-split-vendor/index.d.ts b/packages/plugin-split-vendor/index.d.ts new file mode 100644 index 00000000000000..2583df3c7f7600 --- /dev/null +++ b/packages/plugin-split-vendor/index.d.ts @@ -0,0 +1,11 @@ +import type { Plugin } from 'vite' + +import type { GetManualChunk } from 'rollup' + +export class SplitVendorChunkCache {} + +export function splitVendorChunk(options?: { + cache?: SplitVendorChunkCache +}): GetManualChunk + +export function splitVendorPlugin(): Plugin diff --git a/packages/vite/src/node/plugins/splitVendorChunk.ts b/packages/plugin-split-vendor/index.js similarity index 55% rename from packages/vite/src/node/plugins/splitVendorChunk.ts rename to packages/plugin-split-vendor/index.js index 09246e14e35234..26e5b0da764519 100644 --- a/packages/vite/src/node/plugins/splitVendorChunk.ts +++ b/packages/plugin-split-vendor/index.js @@ -1,7 +1,11 @@ -import type { UserConfig } from '../../node' -import type { Plugin } from '../plugin' -import type { OutputOptions, GetManualChunk, GetModuleInfo } from 'rollup' -import { isCSSRequest } from './css' +// @ts-check +const cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)` +const cssLangRE = new RegExp(cssLangs) +/** + * Internal CSS Check from vite/src/node/plugins/css.ts + * @param {string} request + */ +const isCSSRequest = (request) => cssLangRE.test(request) // Use splitVendorChunkPlugin() to get the same manualChunks strategy as Vite 2.7 // We don't recommend using this strategy as a general solution moving forward @@ -12,20 +16,23 @@ import { isCSSRequest } from './css' // 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 +class SplitVendorCache { + cache constructor() { - this.cache = new Map() + this.cache = new Map() } reset() { - this.cache = new Map() + this.cache = new Map() } } -export function splitVendorChunk( - options: { cache?: SplitVendorChunkCache } = {} -): GetManualChunk { - const cache = options.cache ?? new SplitVendorChunkCache() +/** + * manualChunk strategy splitting in index and vendor chunks + * @param {{ cache?: SplitVendorCache }} options + * @returns {import('rollup').GetManualChunk} + */ +function splitVendor(options = {}) { + const cache = options.cache ?? new SplitVendorCache() return (id, { getModuleInfo }) => { if ( id.includes('node_modules') && @@ -37,14 +44,17 @@ export function splitVendorChunk( } } -function staticImportedByEntry( - id: string, - getModuleInfo: GetModuleInfo, - cache: Map, - importStack: string[] = [] -): boolean { +/** + * Find if a module has been statically imported by an entry + * @param {string} id + * @param {import('rollup').GetModuleInfo} getModuleInfo + * @param {Map} cache + * @param {string[]} importStack + * @returns {boolean} + */ +function staticImportedByEntry(id, getModuleInfo, cache, importStack = []) { if (cache.has(id)) { - return cache.get(id) as boolean + return cache.get(id) } if (importStack.includes(id)) { // circular deps! @@ -73,15 +83,26 @@ function staticImportedByEntry( return someImporterIs } -export function splitVendorChunkPlugin(): Plugin { - const caches: SplitVendorChunkCache[] = [] - function createSplitVendorChunk(output: OutputOptions, config: UserConfig) { - const cache = new SplitVendorChunkCache() +/** + * Implements Vite 2.7 chunking strategy + * @returns {import('vite').Plugin} + */ +function splitVendorPlugin() { + /** + * @type {SplitVendorCache[]} + */ + const caches = [] + /** + * @param {import('rollup').OutputOptions} output + * @param {import('vite').UserConfig} config + */ + function createSplitVendor(output, config) { + const cache = new SplitVendorCache() caches.push(cache) const build = config.build ?? {} const format = output?.format if (!build.ssr && !build.lib && format !== 'umd' && format !== 'iife') { - return splitVendorChunk({ cache }) + return splitVendor({ cache }) } } return { @@ -91,13 +112,13 @@ export function splitVendorChunkPlugin(): Plugin { if (outputs) { outputs = Array.isArray(outputs) ? outputs : [outputs] for (const output of outputs) { - output.manualChunks = createSplitVendorChunk(output, config) + output.manualChunks = createSplitVendor(output, config) } } else { return { build: { rollupOptions: { - manualChunks: createSplitVendorChunk({}, config) + manualChunks: createSplitVendor({}, config) } } } @@ -108,3 +129,5 @@ export function splitVendorChunkPlugin(): Plugin { } } } + +module.exports = { splitVendorPlugin, splitVendor, SplitVendorCache } diff --git a/packages/plugin-split-vendor/package.json b/packages/plugin-split-vendor/package.json new file mode 100644 index 00000000000000..09962201e349fe --- /dev/null +++ b/packages/plugin-split-vendor/package.json @@ -0,0 +1,31 @@ +{ + "name": "@vitejs/plugin-split-vendor", + "version": "0.1.0", + "license": "MIT", + "author": "Evan You", + "files": [ + "index.js", + "index.d.ts" + ], + "main": "index.js", + "types": "index.d.ts", + "scripts": { + "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s --commit-path . --lerna-package plugin-split-vendor", + "release": "ts-node ../../scripts/release.ts --skipBuild" + }, + "engines": { + "node": ">=12.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vitejs/vite.git", + "directory": "packages/plugin-split-vendor" + }, + "bugs": { + "url": "https://github.com/vitejs/vite/issues" + }, + "homepage": "https://github.com/vitejs/vite/tree/main/packages/plugin-split-vendor#readme", + "dependencies": { + "rollup": "^2.59.0" + } +} diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index 147c834d3ba87f..158368872877ac 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -7,10 +7,6 @@ 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' @@ -95,4 +91,3 @@ 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/pnpm-lock.yaml b/pnpm-lock.yaml index d29d20f832517e..391c7a0afd678c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -615,6 +615,7 @@ importers: packages/playground/vue: specifiers: + '@vitejs/plugin-split-vendor': workspace:* '@vitejs/plugin-vue': workspace:* css-with-exports-field: ^1.0.0 js-yaml: ^4.1.0 @@ -628,6 +629,7 @@ importers: lodash-es: 4.17.21 vue: 3.2.26 devDependencies: + '@vitejs/plugin-split-vendor': link:../../plugin-split-vendor '@vitejs/plugin-vue': link:../../plugin-vue css-with-exports-field: 1.0.0 js-yaml: 4.1.0 @@ -690,6 +692,12 @@ importers: react-refresh: 0.11.0 resolve: 1.20.0 + packages/plugin-split-vendor: + specifiers: + rollup: ^2.59.0 + dependencies: + rollup: 2.62.0 + packages/plugin-vue: specifiers: '@rollup/pluginutils': ^4.1.2 From 9a6538a8d0cbf9142e9efdd1f523912a95d068d4 Mon Sep 17 00:00:00 2001 From: patak-dev Date: Sat, 29 Jan 2022 18:18:20 +0100 Subject: [PATCH 9/9] chore: node 12 --- packages/plugin-split-vendor/index.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/plugin-split-vendor/index.js b/packages/plugin-split-vendor/index.js index 26e5b0da764519..b8b4985134c49d 100644 --- a/packages/plugin-split-vendor/index.js +++ b/packages/plugin-split-vendor/index.js @@ -32,7 +32,7 @@ class SplitVendorCache { * @returns {import('rollup').GetManualChunk} */ function splitVendor(options = {}) { - const cache = options.cache ?? new SplitVendorCache() + const cache = options.cache || new SplitVendorCache() return (id, { getModuleInfo }) => { if ( id.includes('node_modules') && @@ -99,8 +99,8 @@ function splitVendorPlugin() { function createSplitVendor(output, config) { const cache = new SplitVendorCache() caches.push(cache) - const build = config.build ?? {} - const format = output?.format + const build = config.build || {} + const format = output.format if (!build.ssr && !build.lib && format !== 'umd' && format !== 'iife') { return splitVendor({ cache }) } @@ -108,7 +108,10 @@ function splitVendorPlugin() { return { name: 'vite:split-vendor-chunk', config(config) { - let outputs = config?.build?.rollupOptions?.output + let outputs = + config.build && + config.build.rollupOptions && + config.build.rollupOptions.output if (outputs) { outputs = Array.isArray(outputs) ? outputs : [outputs] for (const output of outputs) {