Skip to content

Commit 3766004

Browse files
authored
feat: support log related functions in dev (#18922)
1 parent dc8946b commit 3766004

File tree

3 files changed

+189
-41
lines changed

3 files changed

+189
-41
lines changed

packages/vite/rollup.dts.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const identifierReplacements: Record<string, Record<string, string>> = {
4949
rollup: {
5050
Plugin$1: 'rollup.Plugin',
5151
PluginContext$1: 'rollup.PluginContext',
52+
MinimalPluginContext$1: 'rollup.MinimalPluginContext',
5253
TransformPluginContext$1: 'rollup.TransformPluginContext',
5354
TransformResult$2: 'rollup.TransformResult',
5455
},

packages/vite/src/node/server/__tests__/pluginContainer.spec.ts

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { describe, expect, it } from 'vitest'
1+
import { stripVTControlCharacters } from 'node:util'
2+
import { describe, expect, it, vi } from 'vitest'
23
import type { UserConfig } from '../../config'
34
import { resolveConfig } from '../../config'
45
import type { Plugin } from '../../plugin'
56
import { DevEnvironment } from '../environment'
7+
import { createLogger } from '../../logger'
68

79
describe('plugin container', () => {
810
describe('getModuleInfo', () => {
@@ -142,6 +144,55 @@ describe('plugin container', () => {
142144
})
143145
})
144146

147+
describe('options', () => {
148+
it('should not throw errors when this.debug is called', async () => {
149+
const plugin: Plugin = {
150+
name: 'p1',
151+
options() {
152+
this.debug('test')
153+
},
154+
}
155+
await getDevEnvironment({
156+
plugins: [plugin],
157+
})
158+
})
159+
160+
const logFunctions = ['info', 'warn'] as const
161+
for (const logFunction of logFunctions) {
162+
it(`should support this.${logFunction}`, async () => {
163+
const logger = createLogger()
164+
const mockedFn = vi
165+
.spyOn(logger, logFunction)
166+
.mockImplementation(() => {})
167+
const plugin: Plugin = {
168+
name: 'p1',
169+
options() {
170+
this[logFunction]('test')
171+
},
172+
}
173+
await getDevEnvironment({
174+
plugins: [plugin],
175+
customLogger: logger,
176+
})
177+
expect(mockedFn).toHaveBeenCalledOnce()
178+
})
179+
}
180+
181+
it('should support this.error', async () => {
182+
const plugin: Plugin = {
183+
name: 'p1',
184+
options() {
185+
this.error('test')
186+
},
187+
}
188+
await expect(() =>
189+
getDevEnvironment({
190+
plugins: [plugin],
191+
}),
192+
).rejects.toThrowError('test')
193+
})
194+
})
195+
145196
describe('load', () => {
146197
it('can resolve a secondary module', async () => {
147198
const entryUrl = '/x.js'
@@ -212,6 +263,65 @@ describe('plugin container', () => {
212263
)
213264
expect(result.code).equals('3')
214265
})
266+
267+
it('should not throw errors when this.debug is called', async () => {
268+
const plugin: Plugin = {
269+
name: 'p1',
270+
load() {
271+
this.debug({ message: 'test', pos: 12 })
272+
},
273+
}
274+
const environment = await getDevEnvironment({
275+
plugins: [plugin],
276+
})
277+
await environment.pluginContainer.load('foo')
278+
})
279+
280+
const logFunctions = ['info', 'warn'] as const
281+
for (const logFunction of logFunctions) {
282+
it(`should support this.${logFunction}`, async () => {
283+
const logger = createLogger()
284+
const mockedFn = vi
285+
.spyOn(logger, logFunction)
286+
.mockImplementation(() => {})
287+
const plugin: Plugin = {
288+
name: 'p1',
289+
load() {
290+
this[logFunction]({ message: 'test', pos: 12 })
291+
},
292+
}
293+
const environment = await getDevEnvironment({
294+
plugins: [plugin],
295+
customLogger: logger,
296+
})
297+
await environment.pluginContainer.load('foo')
298+
expect(mockedFn).toHaveBeenCalledOnce()
299+
expect(stripVTControlCharacters(mockedFn.mock.calls[0][0])).toBe(
300+
`${logFunction === 'warn' ? 'warning' : logFunction}: test\n` +
301+
' Plugin: p1',
302+
)
303+
})
304+
}
305+
306+
it('should support this.error', async () => {
307+
const plugin: Plugin = {
308+
name: 'p1',
309+
load() {
310+
this.error({ message: 'test', pos: 12 })
311+
},
312+
}
313+
const environment = await getDevEnvironment({
314+
plugins: [plugin],
315+
})
316+
await expect(() => environment.pluginContainer.load('foo')).rejects
317+
.toThrowErrorMatchingInlineSnapshot(`
318+
{
319+
"message": "test",
320+
"plugin": "p1",
321+
"pos": 12,
322+
}
323+
`)
324+
})
215325
})
216326

217327
describe('resolveId', () => {

packages/vite/src/node/server/pluginContainer.ts

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,18 @@ import type {
4040
FunctionPluginHooks,
4141
InputOptions,
4242
LoadResult,
43-
MinimalPluginContext,
4443
ModuleInfo,
4544
ModuleOptions,
4645
NormalizedInputOptions,
4746
OutputOptions,
4847
ParallelPluginHooks,
4948
PartialNull,
5049
PartialResolvedId,
50+
PluginContextMeta,
5151
ResolvedId,
5252
RollupError,
5353
RollupLog,
54+
MinimalPluginContext as RollupMinimalPluginContext,
5455
PluginContext as RollupPluginContext,
5556
TransformPluginContext as RollupTransformPluginContext,
5657
SourceDescription,
@@ -88,8 +89,6 @@ import type {
8889
EnvironmentModuleNode,
8990
} from './moduleGraph'
9091

91-
const noop = () => {}
92-
9392
// same default value of "moduleInfo.meta" as in Rollup
9493
const EMPTY_OBJECT = Object.freeze({})
9594

@@ -105,6 +104,9 @@ const debugPluginResolve = createDebugger('vite:plugin-resolve', {
105104
const debugPluginTransform = createDebugger('vite:plugin-transform', {
106105
onlyWhenFocused: 'vite:plugin',
107106
})
107+
const debugPluginContainerContext = createDebugger(
108+
'vite:plugin-container-context',
109+
)
108110

109111
export const ERR_CLOSED_SERVER = 'ERR_CLOSED_SERVER'
110112

@@ -182,18 +184,10 @@ class EnvironmentPluginContainer {
182184
public plugins: Plugin[],
183185
public watcher?: FSWatcher,
184186
) {
185-
this.minimalContext = {
186-
meta: {
187-
rollupVersion,
188-
watchMode: true,
189-
},
190-
debug: noop,
191-
info: noop,
192-
warn: noop,
193-
// @ts-expect-error noop
194-
error: noop,
187+
this.minimalContext = new MinimalPluginContext(
188+
{ rollupVersion, watchMode: true },
195189
environment,
196-
}
190+
)
197191
const utils = createPluginHookUtils(plugins)
198192
this.getSortedPlugins = utils.getSortedPlugins
199193
this.getSortedPluginHooks = utils.getSortedPluginHooks
@@ -545,22 +539,63 @@ class EnvironmentPluginContainer {
545539
}
546540
}
547541

548-
class PluginContext implements Omit<RollupPluginContext, 'cache'> {
542+
class MinimalPluginContext implements RollupMinimalPluginContext {
543+
constructor(
544+
public meta: PluginContextMeta,
545+
public environment: Environment,
546+
) {}
547+
548+
debug(rawLog: string | RollupLog | (() => string | RollupLog)): void {
549+
const log = this._normalizeRawLog(rawLog)
550+
const msg = buildErrorMessage(log, [`debug: ${log.message}`], false)
551+
debugPluginContainerContext?.(msg)
552+
}
553+
554+
info(rawLog: string | RollupLog | (() => string | RollupLog)): void {
555+
const log = this._normalizeRawLog(rawLog)
556+
const msg = buildErrorMessage(log, [`info: ${log.message}`], false)
557+
this.environment.logger.info(msg, { clear: true, timestamp: true })
558+
}
559+
560+
warn(rawLog: string | RollupLog | (() => string | RollupLog)): void {
561+
const log = this._normalizeRawLog(rawLog)
562+
const msg = buildErrorMessage(
563+
log,
564+
[colors.yellow(`warning: ${log.message}`)],
565+
false,
566+
)
567+
this.environment.logger.warn(msg, { clear: true, timestamp: true })
568+
}
569+
570+
error(e: string | RollupError): never {
571+
const err = (typeof e === 'string' ? new Error(e) : e) as RollupError
572+
throw err
573+
}
574+
575+
private _normalizeRawLog(
576+
rawLog: string | RollupLog | (() => string | RollupLog),
577+
): RollupLog {
578+
const logValue = typeof rawLog === 'function' ? rawLog() : rawLog
579+
return typeof logValue === 'string' ? new Error(logValue) : logValue
580+
}
581+
}
582+
583+
class PluginContext
584+
extends MinimalPluginContext
585+
implements Omit<RollupPluginContext, 'cache'>
586+
{
549587
ssr = false
550588
_scan = false
551589
_activeId: string | null = null
552590
_activeCode: string | null = null
553591
_resolveSkips?: Set<Plugin>
554592
_resolveSkipCalls?: readonly SkipInformation[]
555-
meta: RollupPluginContext['meta']
556-
environment: Environment
557593

558594
constructor(
559595
public _plugin: Plugin,
560596
public _container: EnvironmentPluginContainer,
561597
) {
562-
this.environment = this._container.environment
563-
this.meta = this._container.minimalContext.meta
598+
super(_container.minimalContext.meta, _container.environment)
564599
}
565600

566601
parse(code: string, opts: any) {
@@ -684,39 +719,41 @@ class PluginContext implements Omit<RollupPluginContext, 'cache'> {
684719
return ''
685720
}
686721

687-
warn(
688-
e: string | RollupLog | (() => string | RollupLog),
722+
override debug(log: string | RollupLog | (() => string | RollupLog)): void {
723+
const err = this._formatLog(typeof log === 'function' ? log() : log)
724+
super.debug(err)
725+
}
726+
727+
override info(log: string | RollupLog | (() => string | RollupLog)): void {
728+
const err = this._formatLog(typeof log === 'function' ? log() : log)
729+
super.info(err)
730+
}
731+
732+
override warn(
733+
log: string | RollupLog | (() => string | RollupLog),
689734
position?: number | { column: number; line: number },
690735
): void {
691-
const err = this._formatError(typeof e === 'function' ? e() : e, position)
692-
const msg = buildErrorMessage(
693-
err,
694-
[colors.yellow(`warning: ${err.message}`)],
695-
false,
736+
const err = this._formatLog(
737+
typeof log === 'function' ? log() : log,
738+
position,
696739
)
697-
this.environment.logger.warn(msg, {
698-
clear: true,
699-
timestamp: true,
700-
})
740+
super.warn(err)
701741
}
702742

703-
error(
743+
override error(
704744
e: string | RollupError,
705745
position?: number | { column: number; line: number },
706746
): never {
707747
// error thrown here is caught by the transform middleware and passed on
708748
// the the error middleware.
709-
throw this._formatError(e, position)
749+
throw this._formatLog(e, position)
710750
}
711751

712-
debug = noop
713-
info = noop
714-
715-
private _formatError(
716-
e: string | RollupError,
717-
position: number | { column: number; line: number } | undefined,
718-
): RollupError {
719-
const err = (typeof e === 'string' ? new Error(e) : e) as RollupError
752+
private _formatLog<E extends RollupLog>(
753+
e: string | E,
754+
position?: number | { column: number; line: number } | undefined,
755+
): E {
756+
const err = (typeof e === 'string' ? new Error(e) : e) as E
720757
if (err.pluginCode) {
721758
return err // The plugin likely called `this.error`
722759
}

0 commit comments

Comments
 (0)