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.ssrManifest ? [ssrManifestPlugin(config)] : []),
buildReporterPlugin(config),
buildReporterPlugin(),
]
: []),
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(
resolved: ResolvedConfig,
optimizeDeps: DepOptimizationOptions,

View File

@ -160,15 +160,6 @@ export interface DepOptimizationOptions {
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
// export type ResolvedDepOptimizationOptions = Required<DepOptimizationOptions>

View File

@ -51,6 +51,7 @@ import {
} from '../utils'
import { getFsUtils } from '../fsUtils'
import { checkPublicFile } from '../publicDir'
import { getDepOptimizationOptions } from '../config'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import type { DevEnvironment } from '../server/environment'
@ -276,20 +277,20 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
let importerFile = importer
if (
depsOptimizer &&
moduleListContains(depsOptimizer.options.exclude, url)
) {
await depsOptimizer.scanProcessing
const optimizeDeps = getDepOptimizationOptions(config, ssr)
if (moduleListContains(optimizeDeps?.exclude, url)) {
if (depsOptimizer) {
await depsOptimizer.scanProcessing
// 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
// 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)
for (const optimizedModule of depsOptimizer.metadata.depInfoList) {
if (!optimizedModule.src) continue // Ignore chunks
if (optimizedModule.file === importerModule.file) {
importerFile = optimizedModule.src
// 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
// 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)
for (const optimizedModule of depsOptimizer.metadata.depInfoList) {
if (!optimizedModule.src) continue // Ignore chunks
if (optimizedModule.file === importerModule.file) {
importerFile = optimizedModule.src
}
}
}
}

View File

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

View File

@ -2,11 +2,11 @@ import path from 'node:path'
import { gzip } from 'node:zlib'
import { promisify } from 'node:util'
import colors from 'picocolors'
import type { Plugin } from 'rollup'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { isDefined, isInNodeModules, normalizePath } from '../utils'
import { LogLevels } from '../logger'
import { withTrailingSlash } from '../../shared/utils'
import type { Environment } from '../environment'
const groups = [
{ name: 'Assets', color: colors.green },
@ -23,9 +23,65 @@ type LogEntry = {
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 chunkLimit = config.build.chunkSizeWarningLimit
let chunkLimit = 500
const numberFormatter = new Intl.NumberFormat('en', {
maximumFractionDigits: 2,
@ -36,7 +92,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
}
const tty = process.stdout.isTTY && !process.env.CI
const shouldLogInfo = LogLevels[config.logLevel || 'info'] >= LogLevels.info
let shouldLogInfo = false
let hasTransformed = false
let hasRenderedChunk = false
let hasCompressChunk = false
@ -46,13 +102,14 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
async function getCompressedSize(
code: string | Uint8Array,
env: Environment,
): Promise<number | null> {
if (config.build.ssr || !config.build.reportCompressedSize) {
if (env.options.build.ssr || !env.options.build.reportCompressedSize) {
return null
}
if (shouldLogInfo && !hasCompressChunk) {
if (!tty) {
config.logger.info('computing gzip size...')
env.logger.info('computing gzip size...')
} else {
writeLine('computing gzip size (0)...')
}
@ -68,10 +125,10 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
return compressed.length
}
const logTransform = throttle((id: string) => {
const logTransform = throttle((id: string, root: string) => {
writeLine(
`transforming (${transformedCount}) ${colors.dim(
path.relative(config.root, id),
path.relative(root, id),
)}`,
)
})
@ -79,16 +136,18 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
return {
name: 'vite:reporter',
sharedDuringBuild: true,
transform(_, id) {
transformedCount++
if (shouldLogInfo) {
if (!tty) {
if (!hasTransformed) {
config.logger.info(`transforming...`)
this.environment!.logger.info(`transforming...`)
}
} else {
if (id.includes(`?`)) return
logTransform(id)
logTransform(id, this.environment!.config.root)
}
hasTransformed = true
}
@ -96,6 +155,9 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
},
buildStart() {
chunkLimit = this.environment!.options.build.chunkSizeWarningLimit
shouldLogInfo =
LogLevels[this.environment!.config.logLevel || 'info'] >= LogLevels.info
transformedCount = 0
},
@ -104,7 +166,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
if (tty) {
clearLine()
}
config.logger.info(
this.environment!.logger.info(
`${colors.green(``)} ${transformedCount} modules transformed.`,
)
}
@ -150,7 +212,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
if (shouldLogInfo) {
if (!tty) {
if (!hasRenderedChunk) {
config.logger.info('rendering chunks...')
this.environment!.logger.info('rendering chunks...')
}
} else {
writeLine(`rendering chunks (${chunkCount})...`)
@ -165,6 +227,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
},
async writeBundle({ dir: outDir }, output) {
const env = this.environment!
let hasLargeChunks = false
if (shouldLogInfo) {
@ -177,7 +240,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
name: chunk.fileName,
group: 'JS',
size: chunk.code.length,
compressedSize: await getCompressedSize(chunk.code),
compressedSize: await getCompressedSize(chunk.code, env),
mapSize: chunk.map ? chunk.map.toString().length : null,
}
} else {
@ -191,7 +254,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
size: chunk.source.length,
mapSize: null, // Rollup doesn't support CSS maps?
compressedSize: isCompressible
? await getCompressedSize(chunk.source)
? await getCompressedSize(chunk.source, env)
: null,
}
}
@ -225,11 +288,11 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
const relativeOutDir = normalizePath(
path.relative(
config.root,
path.resolve(config.root, outDir ?? config.build.outDir),
env.config.root,
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) {
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
let log = colors.dim(withTrailingSlash(relativeOutDir))
log +=
!config.build.lib &&
!env.config.build.lib &&
entry.name.startsWith(withTrailingSlash(assetsDir))
? colors.dim(assetsDir) +
group.color(
@ -265,7 +328,7 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
` │ map: ${displaySize(entry.mapSize).padStart(mapPad)}`,
)
}
config.logger.info(log)
env.logger.info(log)
}
}
} else {
@ -276,11 +339,11 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
if (
hasLargeChunks &&
config.build.minify &&
!config.build.lib &&
!config.build.ssr
env.options.build.minify &&
!env.config.build.lib &&
!env.options.build.ssr
) {
config.logger.warn(
env.logger.warn(
colors.yellow(
`\n(!) Some chunks are larger than ${chunkLimit} kB after minification. Consider:\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 type { FetchModuleOptions } from '../ssr/fetchModule'
import { fetchModule } from '../ssr/fetchModule'
import type { DepsOptimizer } from '../optimizer'
import { isDepOptimizationEnabled } from '../optimizer'
import {
createDepsOptimizer,
createExplicitDepsOptimizer,
} from '../optimizer/optimizer'
import { resolveEnvironmentPlugins } from '../plugin'
import type { DepsOptimizer } from '../optimizer'
import { EnvironmentModuleGraph } from './moduleGraph'
import type { HMRChannel } from './hmr'
import { createNoopHMRChannel, getShortName, updateModules } from './hmr'
@ -140,7 +139,11 @@ export class DevEnvironment extends BaseEnvironment {
const { optimizeDeps } = this.options.dev
if (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
} else {
// We only support auto-discovery for the client environment, for all other