perf(isolateEntries): transform log

This commit is contained in:
alex8088 2025-10-29 23:25:28 +08:00
parent cfd9812a91
commit 4edffe3b9a

View File

@ -1,10 +1,19 @@
import { type InlineConfig, type Plugin, type Logger, build as viteBuild, mergeConfig } from 'vite' /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type */
import path from 'node:path'
import { type InlineConfig, type Plugin, type Logger, type LogLevel, build as viteBuild, mergeConfig } from 'vite'
import type { InputOptions, RollupOutput } from 'rollup' import type { InputOptions, RollupOutput } from 'rollup'
import colors from 'picocolors' import colors from 'picocolors'
import buildReporterPlugin from './buildReporter' import buildReporterPlugin from './buildReporter'
const VIRTUAL_ENTRY_ID = '\0virtual:isolate-entries' const VIRTUAL_ENTRY_ID = '\0virtual:isolate-entries'
const LogLevels: Record<LogLevel, number> = {
silent: 0,
error: 1,
warn: 2,
info: 3
}
export default function isolateEntriesPlugin(userConfig: InlineConfig): Plugin { export default function isolateEntriesPlugin(userConfig: InlineConfig): Plugin {
let logger: Logger let logger: Logger
@ -16,9 +25,11 @@ export default function isolateEntriesPlugin(userConfig: InlineConfig): Plugin {
return { return {
name: 'vite:isolate-entries', name: 'vite:isolate-entries',
apply: 'build', apply: 'build',
configResolved(config): void { configResolved(config): void {
logger = config.logger logger = config.logger
}, },
options(opts): InputOptions | void { options(opts): InputOptions | void {
const { input } = opts const { input } = opts
if (input && typeof input === 'object') { if (input && typeof input === 'object') {
@ -29,24 +40,32 @@ export default function isolateEntriesPlugin(userConfig: InlineConfig): Plugin {
} }
} }
}, },
buildStart(): void { buildStart(): void {
transformedCount = 0 transformedCount = 0
assetCache.clear() assetCache.clear()
}, },
resolveId(id): string | null { resolveId(id): string | null {
if (id === VIRTUAL_ENTRY_ID) { if (id === VIRTUAL_ENTRY_ID) {
return id return id
} }
return null return null
}, },
async load(id): Promise<string | void> { async load(id): Promise<string | void> {
if (id === VIRTUAL_ENTRY_ID) { if (id === VIRTUAL_ENTRY_ID) {
const _entries = Array.isArray(entries) const _entries = Array.isArray(entries)
? entries ? entries
: Object.entries(entries).map(([key, value]) => ({ [key]: value })) : Object.entries(entries).map(([key, value]) => ({ [key]: value }))
const watchFiles = new Set<string>() const watchFiles = new Set<string>()
const shouldLog = LogLevels[userConfig.logLevel || 'info'] >= LogLevels.info
const shouldWatch = this.meta.watchMode
for (const entry of _entries) { for (const entry of _entries) {
const re = await bundleEntryFile(entry, userConfig, this.meta.watchMode) const re = await bundleEntryFile(entry, userConfig, shouldWatch, shouldLog, transformedCount)
const outputChunks = re.bundles.output const outputChunks = re.bundles.output
for (const chunk of outputChunks) { for (const chunk of outputChunks) {
if (assetCache.has(chunk.fileName)) { if (assetCache.has(chunk.fileName)) {
@ -59,23 +78,29 @@ export default function isolateEntriesPlugin(userConfig: InlineConfig): Plugin {
}) })
assetCache.add(chunk.fileName) assetCache.add(chunk.fileName)
} }
for (const id of re.watchFiles) { for (const id of re.watchFiles) {
watchFiles.add(id) watchFiles.add(id)
} }
transformedCount += re.transformedCount transformedCount += re.transformedCount
} }
for (const id of watchFiles) { for (const id of watchFiles) {
this.addWatchFile(id) this.addWatchFile(id)
} }
return ` return `
// This is the virtual entry file // This is the virtual entry file
console.log(1)` console.log(1)`
} }
}, },
renderStart(): void { renderStart(): void {
clearLine() clearLine(-1)
logger.info(`${colors.green(``)} ${transformedCount} modules transformed.`) logger.info(`${colors.green(``)} ${transformedCount} modules transformed.`)
}, },
generateBundle(_, bundle): void { generateBundle(_, bundle): void {
for (const chunkName in bundle) { for (const chunkName in bundle) {
if (chunkName.includes('virtual_isolate-entries')) { if (chunkName.includes('virtual_isolate-entries')) {
@ -89,25 +114,18 @@ export default function isolateEntriesPlugin(userConfig: InlineConfig): Plugin {
async function bundleEntryFile( async function bundleEntryFile(
input: string | Record<string, string>, input: string | Record<string, string>,
config: InlineConfig, config: InlineConfig,
watch: boolean watch: boolean,
shouldLog: boolean,
preTransformedCount: number
): Promise<{ bundles: RollupOutput; watchFiles: string[]; transformedCount: number }> { ): Promise<{ bundles: RollupOutput; watchFiles: string[]; transformedCount: number }> {
let transformedCount = 0 const transformReporter = transformReporterPlugin(preTransformedCount, shouldLog)
const buildReporter = watch ? buildReporterPlugin() : undefined
const reporter = watch ? buildReporterPlugin() : undefined
const viteConfig = mergeConfig(config, { const viteConfig = mergeConfig(config, {
build: { build: {
write: false, write: false,
watch: false watch: false
}, },
plugins: [ plugins: [transformReporter, buildReporter],
{
name: 'vite:transform-counter',
transform(): void {
transformedCount++
}
} as Plugin,
reporter
],
logLevel: 'warn', logLevel: 'warn',
configFile: false configFile: false
}) as InlineConfig }) as InlineConfig
@ -119,13 +137,63 @@ async function bundleEntryFile(
return { return {
bundles: bundles as RollupOutput, bundles: bundles as RollupOutput,
watchFiles: reporter?.api?.getWatchFiles() || [], watchFiles: buildReporter?.api?.getWatchFiles() || [],
transformedCount transformedCount: transformReporter?.api?.getTransformedCount() || 0
} }
} }
function clearLine(): void { function transformReporterPlugin(
process.stdout.moveCursor(0, -1) preTransformedCount = 0,
shouldLog = true
): Plugin<{ getTransformedCount: () => number }> {
let transformedCount = 0
let root
const log = throttle(id => {
writeLine(`transforming (${preTransformedCount + transformedCount}) ${colors.dim(path.relative(root, id))}`)
})
return {
name: 'vite:transform-reporter',
configResolved(config) {
root = config.root
},
transform(_, id) {
transformedCount++
if (!shouldLog) return
if (id.includes('?')) return
log(id)
},
api: {
getTransformedCount() {
return transformedCount
}
}
}
}
function writeLine(output: string): void {
clearLine()
if (output.length < process.stdout.columns) {
process.stdout.write(output)
} else {
process.stdout.write(output.substring(0, process.stdout.columns - 1))
}
}
function clearLine(move: number = 0): void {
if (move < 0) {
process.stdout.moveCursor(0, move)
}
process.stdout.clearLine(0) process.stdout.clearLine(0)
process.stdout.cursorTo(0) process.stdout.cursorTo(0)
} }
function throttle(fn: Function) {
let timerHandle: NodeJS.Timeout | null = null
return (...args: any[]) => {
if (timerHandle) return
fn(...args)
timerHandle = setTimeout(() => {
timerHandle = null
}, 100)
}
}