Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove build time pre-bundling #15184

Merged
merged 15 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions docs/config/dep-optimization-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,6 @@ Certain options are omitted since changing them would not be compatible with Vit

Set to `true` to force dependency pre-bundling, ignoring previously cached optimized dependencies.

## optimizeDeps.disabled

- **Experimental:** [Give Feedback](https://github.com/vitejs/vite/discussions/13839)
- **Type:** `boolean | 'build' | 'dev'`
- **Default:** `'build'`

Disables dependencies optimizations, `true` disables the optimizer during build and dev. Pass `'build'` or `'dev'` to only disable the optimizer in one of the modes. Dependency optimization is enabled by default in dev only.

:::warning
Optimizing dependencies in build mode is **experimental**. If enabled, it removes one of the most significant differences between dev and prod. [`@rollup/plugin-commonjs`](https://github.com/rollup/plugins/tree/master/packages/commonjs) is no longer needed in this case since esbuild converts CJS-only dependencies to ESM.

If you want to try this build strategy, you can use `optimizeDeps.disabled: false`. `@rollup/plugin-commonjs` can be removed by passing `build.commonjsOptions: { include: [] }`.
:::

## optimizeDeps.needsInterop

- **Experimental**
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"test": "run-s test-unit test-serve test-build",
"test-serve": "vitest run -c vitest.config.e2e.ts",
"test-build": "VITE_TEST_BUILD=1 vitest run -c vitest.config.e2e.ts",
"test-build-without-plugin-commonjs": "VITE_TEST_WITHOUT_PLUGIN_COMMONJS=1 pnpm test-build",
"test-unit": "vitest run",
"test-docs": "pnpm run docs-build",
"debug-serve": "VITE_DEBUG_SERVE=1 vitest run -c vitest.config.e2e.ts",
Expand Down
24 changes: 2 additions & 22 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,20 +466,6 @@ export async function resolveConfig(
const userPlugins = [...prePlugins, ...normalPlugins, ...postPlugins]
config = await runConfigHook(config, userPlugins, configEnv)

// If there are custom commonjsOptions, don't force optimized deps for this test
// even if the env var is set as it would interfere with the playground specs.
if (
!config.build?.commonjsOptions &&
process.env.VITE_TEST_WITHOUT_PLUGIN_COMMONJS
) {
config = mergeConfig(config, {
optimizeDeps: { disabled: false },
ssr: { optimizeDeps: { disabled: false } },
})
config.build ??= {}
config.build.commonjsOptions = { include: [] }
}

// Define logger
const logger = createLogger(config.logLevel, {
allowClearScreen: config.clearScreen,
Expand Down Expand Up @@ -774,7 +760,6 @@ export async function resolveConfig(
packageCache,
createResolver,
optimizeDeps: {
disabled: 'build',
...optimizeDeps,
esbuildOptions: {
preserveSymlinks: resolveOptions.preserveSymlinks,
Expand Down Expand Up @@ -1232,11 +1217,6 @@ export function isDepsOptimizerEnabled(
config: ResolvedConfig,
ssr: boolean,
): boolean {
const { command } = config
const { disabled } = getDepOptimizationConfig(config, ssr)
return !(
disabled === true ||
(command === 'build' && disabled === 'build') ||
(command === 'serve' && disabled === 'dev')
)
const optimizeDeps = getDepOptimizationConfig(config, ssr)
return !(optimizeDeps.noDiscovery && !optimizeDeps.include?.length)
}
112 changes: 16 additions & 96 deletions packages/vite/src/node/optimizer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ 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'
import {
arraify,
createDebugger,
flattenId,
getHash,
Expand Down Expand Up @@ -58,9 +56,6 @@ export interface DepsOptimizer {
isOptimizedDepUrl: (url: string) => boolean
getOptimizedDepId: (depInfo: OptimizedDepInfo) => string
delayDepsOptimizerUntil: (id: string, done: () => Promise<any>) => void
registerWorkersSource: (id: string) => void
resetRegisteredIds: () => void
ensureFirstRun: () => void

close: () => Promise<void>

Expand Down Expand Up @@ -118,14 +113,6 @@ export interface DepOptimizationConfig {
* @experimental
*/
extensions?: string[]
/**
* Disables dependencies optimizations, true disables the optimizer during
* build and dev. Pass 'build' or 'dev' to only disable the optimizer in
* one of the modes. Deps optimization is enabled by default in dev only.
* @default 'build'
* @experimental
*/
disabled?: boolean | 'build' | 'dev'
/**
* Automatic dependency discovery. When `noDiscovery` is true, only dependencies
* listed in `include` will be optimized. The scanner isn't run for cold start
Expand Down Expand Up @@ -230,8 +217,7 @@ export async function optimizeDeps(
asCommand = false,
): Promise<DepOptimizationMetadata> {
const log = asCommand ? config.logger.info : debug

const ssr = config.command === 'build' && !!config.build.ssr
const ssr = false

const cachedMetadata = await loadCachedDepOptimizationMetadata(
config,
Expand All @@ -252,7 +238,7 @@ export async function optimizeDeps(

const depsInfo = toDiscoveredDependencies(config, deps, ssr)

const result = await runOptimizeDeps(config, depsInfo).result
const result = await runOptimizeDeps(config, depsInfo, ssr).result

await result.commit()

Expand All @@ -273,37 +259,13 @@ export async function optimizeServerSsrDeps(
return cachedMetadata
}

let alsoInclude: string[] | undefined
let noExternalFilter: ((id: unknown) => boolean) | undefined

const { exclude } = getDepOptimizationConfig(config, ssr)

const noExternal = config.ssr?.noExternal
if (noExternal) {
alsoInclude = arraify(noExternal).filter(
(ne) => typeof ne === 'string',
) as string[]
noExternalFilter =
noExternal === true
? (dep: unknown) => true
: createFilter(undefined, exclude, {
resolve: false,
})
}

const deps: Record<string, string> = {}

await addManuallyIncludedOptimizeDeps(
deps,
config,
ssr,
alsoInclude,
noExternalFilter,
)
await addManuallyIncludedOptimizeDeps(deps, config, ssr)

const depsInfo = toDiscoveredDependencies(config, deps, true)
const depsInfo = toDiscoveredDependencies(config, deps, ssr)

const result = await runOptimizeDeps(config, depsInfo, true).result
const result = await runOptimizeDeps(config, depsInfo, ssr).result

await result.commit()

Expand Down Expand Up @@ -451,8 +413,7 @@ export function depsLogString(qualifiedIds: string[]): string {
export function runOptimizeDeps(
resolvedConfig: ResolvedConfig,
depsInfo: Record<string, OptimizedDepInfo>,
ssr: boolean = resolvedConfig.command === 'build' &&
!!resolvedConfig.build.ssr,
ssr: boolean,
): {
cancel: () => Promise<void>
result: Promise<DepOptimizationResult>
Expand Down Expand Up @@ -713,7 +674,6 @@ async function prepareEsbuildOptimizerRun(
context?: BuildContext
idToExports: Record<string, ExportsData>
}> {
const isBuild = resolvedConfig.command === 'build'
const config: ResolvedConfig = {
...resolvedConfig,
command: 'build',
Expand Down Expand Up @@ -754,40 +714,15 @@ async function prepareEsbuildOptimizerRun(

if (optimizerContext.cancelled) return { context: undefined, idToExports }

// esbuild automatically replaces process.env.NODE_ENV for platform 'browser'
// But in lib mode, we need to keep process.env.NODE_ENV untouched
const define = {
'process.env.NODE_ENV':
isBuild && config.build.lib
? 'process.env.NODE_ENV'
: JSON.stringify(process.env.NODE_ENV || config.mode),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || config.mode),
}

const platform =
ssr && config.ssr?.target !== 'webworker' ? 'node' : 'browser'

const external = [...(optimizeDeps?.exclude ?? [])]

if (isBuild) {
let rollupOptionsExternal = config?.build?.rollupOptions?.external
if (rollupOptionsExternal) {
if (typeof rollupOptionsExternal === 'string') {
rollupOptionsExternal = [rollupOptionsExternal]
}
// TODO: decide whether to support RegExp and function options
// They're not supported yet because `optimizeDeps.exclude` currently only accepts strings
if (
!Array.isArray(rollupOptionsExternal) ||
rollupOptionsExternal.some((ext) => typeof ext !== 'string')
) {
throw new Error(
`[vite] 'build.rollupOptions.external' can only be an array of strings or a string when using esbuild optimization at build time.`,
)
}
external.push(...(rollupOptionsExternal as string[]))
}
}

const plugins = [...pluginsFromConfig]
if (external.length) {
plugins.push(esbuildCjsExternalPlugin(external, platform))
Expand All @@ -811,13 +746,13 @@ async function prepareEsbuildOptimizerRun(
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`,
}
: undefined,
target: isBuild ? config.build.target || undefined : ESBUILD_MODULES_TARGET,
target: ESBUILD_MODULES_TARGET,
external,
logLevel: 'error',
splitting: true,
sourcemap: true,
outdir: processingCacheDir,
ignoreAnnotations: !isBuild,
ignoreAnnotations: true,
metafile: true,
plugins,
charset: 'utf8',
Expand All @@ -835,13 +770,12 @@ export async function addManuallyIncludedOptimizeDeps(
deps: Record<string, string>,
config: ResolvedConfig,
ssr: boolean,
extra: string[] = [],
filter?: (id: string) => boolean,
patak-dev marked this conversation as resolved.
Show resolved Hide resolved
): Promise<void> {
const { logger } = config
const optimizeDeps = getDepOptimizationConfig(config, ssr)
const optimizeDepsInclude = optimizeDeps?.include ?? []
if (optimizeDepsInclude.length || extra.length) {
if (optimizeDepsInclude.length) {
const unableToOptimize = (id: string, msg: string) => {
if (optimizeDepsInclude.includes(id)) {
logger.warn(
Expand All @@ -852,7 +786,7 @@ export async function addManuallyIncludedOptimizeDeps(
}
}

const includes = [...optimizeDepsInclude, ...extra]
const includes = [...optimizeDepsInclude]
for (let i = 0; i < includes.length; i++) {
const id = includes[i]
if (glob.isDynamicPattern(id)) {
Expand All @@ -867,7 +801,7 @@ export async function addManuallyIncludedOptimizeDeps(
// normalize 'foo >bar` as 'foo > bar' to prevent same id being added
// and for pretty printing
const normalizedId = normalizeId(id)
if (!deps[normalizedId] && filter?.(normalizedId) !== false) {
if (!deps[normalizedId]) {
const entry = await resolve(id)
if (entry) {
if (isOptimizable(entry, optimizeDeps)) {
Expand Down Expand Up @@ -914,30 +848,17 @@ export function getOptimizedDepPath(
)
}

function getDepsCacheSuffix(config: ResolvedConfig, ssr: boolean): string {
let suffix = ''
if (config.command === 'build') {
// Differentiate build caches depending on outDir to allow parallel builds
const { outDir } = config.build
const buildId =
outDir.length > 8 || outDir.includes('/') ? getHash(outDir) : outDir
suffix += `_build-${buildId}`
}
if (ssr) {
suffix += '_ssr'
}
return suffix
function getDepsCacheSuffix(ssr: boolean): string {
return ssr ? '_ssr' : ''
}

export function getDepsCacheDir(config: ResolvedConfig, ssr: boolean): string {
return getDepsCacheDirPrefix(config) + getDepsCacheSuffix(config, ssr)
return getDepsCacheDirPrefix(config) + getDepsCacheSuffix(ssr)
}

function getProcessingDepsCacheDir(config: ResolvedConfig, ssr: boolean) {
return (
getDepsCacheDirPrefix(config) +
getDepsCacheSuffix(config, ssr) +
getTempSuffix()
getDepsCacheDirPrefix(config) + getDepsCacheSuffix(ssr) + getTempSuffix()
)
}

Expand Down Expand Up @@ -1225,7 +1146,6 @@ export function getDepHash(config: ResolvedConfig, ssr: boolean): string {
mode: process.env.NODE_ENV || config.mode,
root: config.root,
resolve: config.resolve,
buildTarget: config.build.target,
assetsInclude: config.assetsInclude,
plugins: config.plugins.map((p) => p.name),
optimizeDeps: {
Expand Down
Loading