chore: try createPerEnvPlugin

This commit is contained in:
Anthony Fu 2024-05-24 00:33:16 +02:00
parent 5f36aa6ebb
commit 4ea71ade96
No known key found for this signature in database
GPG Key ID: 179936958CD423FF
7 changed files with 127 additions and 56 deletions

View File

@ -500,7 +500,7 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
? [ ? [
...(options.manifest ? [manifestPlugin()] : []), ...(options.manifest ? [manifestPlugin()] : []),
...(options.ssrManifest ? [ssrManifestPlugin(config)] : []), ...(options.ssrManifest ? [ssrManifestPlugin(config)] : []),
buildReporterPlugin(config), buildReporterPlugin(),
] ]
: []), : []),
buildLoadFallbackPlugin(), buildLoadFallbackPlugin(),

View File

@ -1762,6 +1762,20 @@ async function runConfigEnvironmentHook(
} }
} }
export function getDepOptimizationOptions(
config: ResolvedConfig,
ssr: boolean,
): DepOptimizationOptions {
return ssr ? config.ssr.optimizeDeps : config.optimizeDeps
}
export function isDepsOptimizerEnabled(
config: ResolvedConfig,
ssr: boolean,
): boolean {
const optimizeDeps = getDepOptimizationOptions(config, ssr)
return !(optimizeDeps.noDiscovery && !optimizeDeps.include?.length)
}
function optimizeDepsDisabledBackwardCompatibility( function optimizeDepsDisabledBackwardCompatibility(
resolved: ResolvedConfig, resolved: ResolvedConfig,
optimizeDeps: DepOptimizationOptions, optimizeDeps: DepOptimizationOptions,

View File

@ -160,15 +160,6 @@ export interface DepOptimizationOptions {
force?: boolean force?: boolean
} }
export function isDepOptimizationEnabled(
optimizeDeps: DepOptimizationOptions,
): boolean {
return (
!(optimizeDeps.disabled === true || optimizeDeps.disabled === 'dev') &&
!(optimizeDeps.noDiscovery && !optimizeDeps.include?.length)
)
}
// TODO: We first need to define if entries and force should be per-environment // TODO: We first need to define if entries and force should be per-environment
// export type ResolvedDepOptimizationOptions = Required<DepOptimizationOptions> // export type ResolvedDepOptimizationOptions = Required<DepOptimizationOptions>

View File

@ -51,6 +51,7 @@ import {
} from '../utils' } from '../utils'
import { getFsUtils } from '../fsUtils' import { getFsUtils } from '../fsUtils'
import { checkPublicFile } from '../publicDir' import { checkPublicFile } from '../publicDir'
import { getDepOptimizationOptions } from '../config'
import type { ResolvedConfig } from '../config' import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin' import type { Plugin } from '../plugin'
import type { DevEnvironment } from '../server/environment' import type { DevEnvironment } from '../server/environment'
@ -276,20 +277,20 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
let importerFile = importer let importerFile = importer
if ( const optimizeDeps = getDepOptimizationOptions(config, ssr)
depsOptimizer && if (moduleListContains(optimizeDeps?.exclude, url)) {
moduleListContains(depsOptimizer.options.exclude, url) if (depsOptimizer) {
) { await depsOptimizer.scanProcessing
await depsOptimizer.scanProcessing
// if the dependency encountered in the optimized file was excluded from the optimization // if the dependency encountered in the optimized file was excluded from the optimization
// the dependency needs to be resolved starting from the original source location of the optimized file // the dependency needs to be resolved starting from the original source location of the optimized file
// because starting from node_modules/.vite will not find the dependency if it was not hoisted // because starting from node_modules/.vite will not find the dependency if it was not hoisted
// (that is, if it is under node_modules directory in the package source of the optimized file) // (that is, if it is under node_modules directory in the package source of the optimized file)
for (const optimizedModule of depsOptimizer.metadata.depInfoList) { for (const optimizedModule of depsOptimizer.metadata.depInfoList) {
if (!optimizedModule.src) continue // Ignore chunks if (!optimizedModule.src) continue // Ignore chunks
if (optimizedModule.file === importerModule.file) { if (optimizedModule.file === importerModule.file) {
importerFile = optimizedModule.src importerFile = optimizedModule.src
}
} }
} }
} }

View File

@ -1,7 +1,7 @@
import aliasPlugin, { type ResolverFunction } from '@rollup/plugin-alias' import aliasPlugin, { type ResolverFunction } from '@rollup/plugin-alias'
import type { ObjectHook } from 'rollup' import type { ObjectHook } from 'rollup'
import type { PluginHookUtils, ResolvedConfig } from '../config' import type { PluginHookUtils, ResolvedConfig } from '../config'
import { isDepOptimizationEnabled } from '../optimizer' import { isDepsOptimizerEnabled } from '../config'
import type { HookHandler, Plugin, PluginWithRequiredHook } from '../plugin' import type { HookHandler, Plugin, PluginWithRequiredHook } from '../plugin'
import { watchPackageDataPlugin } from '../packages' import { watchPackageDataPlugin } from '../packages'
import { getFsUtils } from '../fsUtils' import { getFsUtils } from '../fsUtils'
@ -38,14 +38,13 @@ export async function resolvePlugins(
? await (await import('../build')).resolveBuildPlugins(config) ? await (await import('../build')).resolveBuildPlugins(config)
: { pre: [], post: [] } : { pre: [], post: [] }
const { modulePreload } = config.build const { modulePreload } = config.build
const depOptimizationEnabled = const depsOptimizerEnabled =
!isBuild && !isBuild &&
Object.values(config.environments).some((environment) => (isDepsOptimizerEnabled(config, false) ||
isDepOptimizationEnabled(environment.dev.optimizeDeps), isDepsOptimizerEnabled(config, true))
)
return [ return [
depOptimizationEnabled ? optimizedDepsPlugin(config) : null, depsOptimizerEnabled ? optimizedDepsPlugin(config) : null,
isBuild ? metadataPlugin() : null, isBuild ? metadataPlugin() : null,
!isWorker ? watchPackageDataPlugin(config.packageCache) : null, !isWorker ? watchPackageDataPlugin(config.packageCache) : null,
preAliasPlugin(config), preAliasPlugin(config),

View File

@ -2,11 +2,11 @@ import path from 'node:path'
import { gzip } from 'node:zlib' import { gzip } from 'node:zlib'
import { promisify } from 'node:util' import { promisify } from 'node:util'
import colors from 'picocolors' import colors from 'picocolors'
import type { Plugin } from 'rollup' import type { Plugin } from '../plugin'
import type { ResolvedConfig } from '../config'
import { isDefined, isInNodeModules, normalizePath } from '../utils' import { isDefined, isInNodeModules, normalizePath } from '../utils'
import { LogLevels } from '../logger' import { LogLevels } from '../logger'
import { withTrailingSlash } from '../../shared/utils' import { withTrailingSlash } from '../../shared/utils'
import type { Environment } from '../environment'
const groups = [ const groups = [
{ name: 'Assets', color: colors.green }, { name: 'Assets', color: colors.green },
@ -23,9 +23,65 @@ type LogEntry = {
const COMPRESSIBLE_ASSETS_RE = /\.(?:html|json|svg|txt|xml|xhtml)$/ const COMPRESSIBLE_ASSETS_RE = /\.(?:html|json|svg|txt|xml|xhtml)$/
export function buildReporterPlugin(config: ResolvedConfig): Plugin { function createPerEnvPlugin(factory: () => Plugin): Plugin {
const defaultPlugin = factory()
let init = false
const pluginMap = new WeakMap<Environment, Plugin>()
function getPlugin(env: Environment) {
// reuse the default plugin for the first environment
if (!init) {
init = true
pluginMap.set(env, defaultPlugin)
}
if (!pluginMap.has(env)) {
pluginMap.set(env, factory())
}
return pluginMap.get(env)!
}
const plugin: any = {}
for (const [key, value] of Object.entries(defaultPlugin)) {
if (typeof value === 'function') {
plugin[key] = function (...args: any[]) {
if (!this.environment) {
throw new Error(
'Hook "' + key + '" is not supported in `createPerEnvPlugin`',
)
}
const plugin = getPlugin(this.environment)
return (plugin as any)[key].apply(this, args)
}
} else if (value && value.handler && typeof value.handler === 'function') {
plugin[key] = {
...value,
handler(...args: any[]) {
if (!this.environment) {
throw new Error(
'Hook "' + key + '" is not supported in `createPerEnvPlugin`',
)
}
const plugin = getPlugin(this.environment)
return (plugin as any)[key].handler.apply(this, args)
},
}
} else {
plugin[key] = value
}
}
return plugin
}
export function buildReporterPlugin(): Plugin {
return createPerEnvPlugin(() => _buildReporterPlugin())
}
function _buildReporterPlugin(): Plugin {
const compress = promisify(gzip) const compress = promisify(gzip)
const chunkLimit = config.build.chunkSizeWarningLimit let chunkLimit = 500
const numberFormatter = new Intl.NumberFormat('en', { const numberFormatter = new Intl.NumberFormat('en', {
maximumFractionDigits: 2, maximumFractionDigits: 2,
@ -36,7 +92,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
} }
const tty = process.stdout.isTTY && !process.env.CI const tty = process.stdout.isTTY && !process.env.CI
const shouldLogInfo = LogLevels[config.logLevel || 'info'] >= LogLevels.info let shouldLogInfo = false
let hasTransformed = false let hasTransformed = false
let hasRenderedChunk = false let hasRenderedChunk = false
let hasCompressChunk = false let hasCompressChunk = false
@ -46,13 +102,14 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
async function getCompressedSize( async function getCompressedSize(
code: string | Uint8Array, code: string | Uint8Array,
env: Environment,
): Promise<number | null> { ): Promise<number | null> {
if (config.build.ssr || !config.build.reportCompressedSize) { if (env.options.build.ssr || !env.options.build.reportCompressedSize) {
return null return null
} }
if (shouldLogInfo && !hasCompressChunk) { if (shouldLogInfo && !hasCompressChunk) {
if (!tty) { if (!tty) {
config.logger.info('computing gzip size...') env.logger.info('computing gzip size...')
} else { } else {
writeLine('computing gzip size (0)...') writeLine('computing gzip size (0)...')
} }
@ -68,10 +125,10 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
return compressed.length return compressed.length
} }
const logTransform = throttle((id: string) => { const logTransform = throttle((id: string, root: string) => {
writeLine( writeLine(
`transforming (${transformedCount}) ${colors.dim( `transforming (${transformedCount}) ${colors.dim(
path.relative(config.root, id), path.relative(root, id),
)}`, )}`,
) )
}) })
@ -79,16 +136,18 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
return { return {
name: 'vite:reporter', name: 'vite:reporter',
sharedDuringBuild: true,
transform(_, id) { transform(_, id) {
transformedCount++ transformedCount++
if (shouldLogInfo) { if (shouldLogInfo) {
if (!tty) { if (!tty) {
if (!hasTransformed) { if (!hasTransformed) {
config.logger.info(`transforming...`) this.environment!.logger.info(`transforming...`)
} }
} else { } else {
if (id.includes(`?`)) return if (id.includes(`?`)) return
logTransform(id) logTransform(id, this.environment!.config.root)
} }
hasTransformed = true hasTransformed = true
} }
@ -96,6 +155,9 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
}, },
buildStart() { buildStart() {
chunkLimit = this.environment!.options.build.chunkSizeWarningLimit
shouldLogInfo =
LogLevels[this.environment!.config.logLevel || 'info'] >= LogLevels.info
transformedCount = 0 transformedCount = 0
}, },
@ -104,7 +166,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
if (tty) { if (tty) {
clearLine() clearLine()
} }
config.logger.info( this.environment!.logger.info(
`${colors.green(``)} ${transformedCount} modules transformed.`, `${colors.green(``)} ${transformedCount} modules transformed.`,
) )
} }
@ -150,7 +212,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
if (shouldLogInfo) { if (shouldLogInfo) {
if (!tty) { if (!tty) {
if (!hasRenderedChunk) { if (!hasRenderedChunk) {
config.logger.info('rendering chunks...') this.environment!.logger.info('rendering chunks...')
} }
} else { } else {
writeLine(`rendering chunks (${chunkCount})...`) writeLine(`rendering chunks (${chunkCount})...`)
@ -165,6 +227,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
}, },
async writeBundle({ dir: outDir }, output) { async writeBundle({ dir: outDir }, output) {
const env = this.environment!
let hasLargeChunks = false let hasLargeChunks = false
if (shouldLogInfo) { if (shouldLogInfo) {
@ -177,7 +240,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
name: chunk.fileName, name: chunk.fileName,
group: 'JS', group: 'JS',
size: chunk.code.length, size: chunk.code.length,
compressedSize: await getCompressedSize(chunk.code), compressedSize: await getCompressedSize(chunk.code, env),
mapSize: chunk.map ? chunk.map.toString().length : null, mapSize: chunk.map ? chunk.map.toString().length : null,
} }
} else { } else {
@ -191,7 +254,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
size: chunk.source.length, size: chunk.source.length,
mapSize: null, // Rollup doesn't support CSS maps? mapSize: null, // Rollup doesn't support CSS maps?
compressedSize: isCompressible compressedSize: isCompressible
? await getCompressedSize(chunk.source) ? await getCompressedSize(chunk.source, env)
: null, : null,
} }
} }
@ -225,11 +288,11 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
const relativeOutDir = normalizePath( const relativeOutDir = normalizePath(
path.relative( path.relative(
config.root, env.config.root,
path.resolve(config.root, outDir ?? config.build.outDir), path.resolve(env.config.root, outDir ?? env.options.build.outDir),
), ),
) )
const assetsDir = path.join(config.build.assetsDir, '/') const assetsDir = path.join(env.options.build.assetsDir, '/')
for (const group of groups) { for (const group of groups) {
const filtered = entries.filter((e) => e.group === group.name) const filtered = entries.filter((e) => e.group === group.name)
@ -241,7 +304,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
const sizeColor = isLarge ? colors.yellow : colors.dim const sizeColor = isLarge ? colors.yellow : colors.dim
let log = colors.dim(withTrailingSlash(relativeOutDir)) let log = colors.dim(withTrailingSlash(relativeOutDir))
log += log +=
!config.build.lib && !env.config.build.lib &&
entry.name.startsWith(withTrailingSlash(assetsDir)) entry.name.startsWith(withTrailingSlash(assetsDir))
? colors.dim(assetsDir) + ? colors.dim(assetsDir) +
group.color( group.color(
@ -265,7 +328,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
` │ map: ${displaySize(entry.mapSize).padStart(mapPad)}`, ` │ map: ${displaySize(entry.mapSize).padStart(mapPad)}`,
) )
} }
config.logger.info(log) env.logger.info(log)
} }
} }
} else { } else {
@ -276,11 +339,11 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
if ( if (
hasLargeChunks && hasLargeChunks &&
config.build.minify && env.options.build.minify &&
!config.build.lib && !env.config.build.lib &&
!config.build.ssr !env.options.build.ssr
) { ) {
config.logger.warn( env.logger.warn(
colors.yellow( colors.yellow(
`\n(!) Some chunks are larger than ${chunkLimit} kB after minification. Consider:\n` + `\n(!) Some chunks are larger than ${chunkLimit} kB after minification. Consider:\n` +
`- Using dynamic import() to code-split the application\n` + `- Using dynamic import() to code-split the application\n` +

View File

@ -12,13 +12,12 @@ import { getDefaultResolvedEnvironmentOptions } from '../config'
import { mergeConfig, promiseWithResolvers } from '../utils' import { mergeConfig, promiseWithResolvers } from '../utils'
import type { FetchModuleOptions } from '../ssr/fetchModule' import type { FetchModuleOptions } from '../ssr/fetchModule'
import { fetchModule } from '../ssr/fetchModule' import { fetchModule } from '../ssr/fetchModule'
import type { DepsOptimizer } from '../optimizer'
import { isDepOptimizationEnabled } from '../optimizer'
import { import {
createDepsOptimizer, createDepsOptimizer,
createExplicitDepsOptimizer, createExplicitDepsOptimizer,
} from '../optimizer/optimizer' } from '../optimizer/optimizer'
import { resolveEnvironmentPlugins } from '../plugin' import { resolveEnvironmentPlugins } from '../plugin'
import type { DepsOptimizer } from '../optimizer'
import { EnvironmentModuleGraph } from './moduleGraph' import { EnvironmentModuleGraph } from './moduleGraph'
import type { HMRChannel } from './hmr' import type { HMRChannel } from './hmr'
import { createNoopHMRChannel, getShortName, updateModules } from './hmr' import { createNoopHMRChannel, getShortName, updateModules } from './hmr'
@ -140,7 +139,11 @@ export class DevEnvironment extends BaseEnvironment {
const { optimizeDeps } = this.options.dev const { optimizeDeps } = this.options.dev
if (setup?.depsOptimizer) { if (setup?.depsOptimizer) {
this.depsOptimizer = setup?.depsOptimizer this.depsOptimizer = setup?.depsOptimizer
} else if (!isDepOptimizationEnabled(optimizeDeps)) { } else if (
optimizeDeps?.disabled === true ||
optimizeDeps?.disabled === 'build' ||
(optimizeDeps?.noDiscovery && optimizeDeps?.include?.length === 0)
) {
this.depsOptimizer = undefined this.depsOptimizer = undefined
} else { } else {
// We only support auto-discovery for the client environment, for all other // We only support auto-discovery for the client environment, for all other