@@ -34,14 +34,17 @@ import { join, resolve } from 'node:path'
34
34
import { performance } from 'node:perf_hooks'
35
35
import { createRequire } from 'node:module'
36
36
import type {
37
+ AsyncPluginHooks ,
37
38
CustomPluginOptions ,
38
39
EmittedFile ,
40
+ FunctionPluginHooks ,
39
41
InputOptions ,
40
42
LoadResult ,
41
43
MinimalPluginContext ,
42
44
ModuleInfo ,
43
45
NormalizedInputOptions ,
44
46
OutputOptions ,
47
+ ParallelPluginHooks ,
45
48
PartialResolvedId ,
46
49
ResolvedId ,
47
50
RollupError ,
@@ -74,6 +77,7 @@ import {
74
77
} from '../utils'
75
78
import { FS_PREFIX } from '../constants'
76
79
import type { ResolvedConfig } from '../config'
80
+ import { createPluginHookUtils } from '../plugins'
77
81
import { buildErrorMessage } from './middlewares/error'
78
82
import type { ModuleGraph } from './moduleGraph'
79
83
@@ -137,11 +141,19 @@ type PluginContext = Omit<
137
141
export let parser = acorn . Parser
138
142
139
143
export async function createPluginContainer (
140
- { plugins , logger , root , build : { rollupOptions } } : ResolvedConfig ,
144
+ config : ResolvedConfig ,
141
145
moduleGraph ?: ModuleGraph ,
142
146
watcher ?: FSWatcher
143
147
) : Promise < PluginContainer > {
144
148
const isDebug = process . env . DEBUG
149
+ const {
150
+ plugins,
151
+ logger,
152
+ root,
153
+ build : { rollupOptions }
154
+ } = config
155
+ const { getSortedPluginHooks, getSortedPlugins } =
156
+ createPluginHookUtils ( plugins )
145
157
146
158
const seenResolves : Record < string , true | undefined > = { }
147
159
const debugResolve = createDebugger ( 'vite:resolve' )
@@ -192,6 +204,28 @@ export async function createPluginContainer(
192
204
)
193
205
}
194
206
207
+ // parallel, ignores returns
208
+ async function hookParallel < H extends AsyncPluginHooks & ParallelPluginHooks > (
209
+ hookName : H ,
210
+ context : ( plugin : Plugin ) => ThisType < FunctionPluginHooks [ H ] > ,
211
+ args : ( plugin : Plugin ) => Parameters < FunctionPluginHooks [ H ] >
212
+ ) : Promise < void > {
213
+ const parallelPromises : Promise < unknown > [ ] = [ ]
214
+ for ( const plugin of getSortedPlugins ( hookName ) ) {
215
+ const hook = plugin [ hookName ]
216
+ if ( ! hook ) continue
217
+ const handler : Function = 'handler' in hook ? hook . handler : hook
218
+ if ( ( hook as { sequential ?: boolean } ) . sequential ) {
219
+ await Promise . all ( parallelPromises )
220
+ parallelPromises . length = 0
221
+ await handler . apply ( context ( plugin ) , args ( plugin ) )
222
+ } else {
223
+ parallelPromises . push ( handler . apply ( context ( plugin ) , args ( plugin ) ) )
224
+ }
225
+ }
226
+ await Promise . all ( parallelPromises )
227
+ }
228
+
195
229
// throw when an unsupported ModuleInfo property is accessed,
196
230
// so that incompatible plugins fail in a non-cryptic way.
197
231
const ModuleInfoProxy : ProxyHandler < ModuleInfo > = {
@@ -500,10 +534,8 @@ export async function createPluginContainer(
500
534
const container : PluginContainer = {
501
535
options : await ( async ( ) => {
502
536
let options = rollupOptions
503
- for ( const plugin of plugins ) {
504
- if ( ! plugin . options ) continue
505
- options =
506
- ( await plugin . options . call ( minimalContext , options ) ) || options
537
+ for ( const optionsHook of getSortedPluginHooks ( 'options' ) ) {
538
+ options = ( await optionsHook . call ( minimalContext , options ) ) || options
507
539
}
508
540
if ( options . acornInjectPlugins ) {
509
541
parser = acorn . Parser . extend (
@@ -520,15 +552,10 @@ export async function createPluginContainer(
520
552
getModuleInfo,
521
553
522
554
async buildStart ( ) {
523
- await Promise . all (
524
- plugins . map ( ( plugin ) => {
525
- if ( plugin . buildStart ) {
526
- return plugin . buildStart . call (
527
- new Context ( plugin ) as any ,
528
- container . options as NormalizedInputOptions
529
- )
530
- }
531
- } )
555
+ await hookParallel (
556
+ 'buildStart' ,
557
+ ( plugin ) => new Context ( plugin ) ,
558
+ ( ) => [ container . options as NormalizedInputOptions ]
532
559
)
533
560
} ,
534
561
@@ -544,24 +571,23 @@ export async function createPluginContainer(
544
571
545
572
let id : string | null = null
546
573
const partial : Partial < PartialResolvedId > = { }
547
- for ( const plugin of plugins ) {
574
+ for ( const plugin of getSortedPlugins ( 'resolveId' ) ) {
548
575
if ( ! plugin . resolveId ) continue
549
576
if ( skip ?. has ( plugin ) ) continue
550
577
551
578
ctx . _activePlugin = plugin
552
579
553
580
const pluginResolveStart = isDebug ? performance . now ( ) : 0
554
- const result = await plugin . resolveId . call (
555
- ctx as any ,
556
- rawId ,
557
- importer ,
558
- {
559
- custom : options ?. custom ,
560
- isEntry : ! ! options ?. isEntry ,
561
- ssr,
562
- scan
563
- }
564
- )
581
+ const handler =
582
+ 'handler' in plugin . resolveId
583
+ ? plugin . resolveId . handler
584
+ : plugin . resolveId
585
+ const result = await handler . call ( ctx as any , rawId , importer , {
586
+ custom : options ?. custom ,
587
+ isEntry : ! ! options ?. isEntry ,
588
+ ssr,
589
+ scan
590
+ } )
565
591
if ( ! result ) continue
566
592
567
593
if ( typeof result === 'string' ) {
@@ -607,10 +633,12 @@ export async function createPluginContainer(
607
633
const ssr = options ?. ssr
608
634
const ctx = new Context ( )
609
635
ctx . ssr = ! ! ssr
610
- for ( const plugin of plugins ) {
636
+ for ( const plugin of getSortedPlugins ( 'load' ) ) {
611
637
if ( ! plugin . load ) continue
612
638
ctx . _activePlugin = plugin
613
- const result = await plugin . load . call ( ctx as any , id , { ssr } )
639
+ const handler =
640
+ 'handler' in plugin . load ? plugin . load . handler : plugin . load
641
+ const result = await handler . call ( ctx as any , id , { ssr } )
614
642
if ( result != null ) {
615
643
if ( isObject ( result ) ) {
616
644
updateModuleInfo ( id , result )
@@ -626,15 +654,19 @@ export async function createPluginContainer(
626
654
const ssr = options ?. ssr
627
655
const ctx = new TransformContext ( id , code , inMap as SourceMap )
628
656
ctx . ssr = ! ! ssr
629
- for ( const plugin of plugins ) {
657
+ for ( const plugin of getSortedPlugins ( 'transform' ) ) {
630
658
if ( ! plugin . transform ) continue
631
659
ctx . _activePlugin = plugin
632
660
ctx . _activeId = id
633
661
ctx . _activeCode = code
634
662
const start = isDebug ? performance . now ( ) : 0
635
663
let result : TransformResult | string | undefined
664
+ const handler =
665
+ 'handler' in plugin . transform
666
+ ? plugin . transform . handler
667
+ : plugin . transform
636
668
try {
637
- result = await plugin . transform . call ( ctx as any , code , id , { ssr } )
669
+ result = await handler . call ( ctx as any , code , id , { ssr } )
638
670
} catch ( e ) {
639
671
ctx . error ( e )
640
672
}
@@ -670,11 +702,15 @@ export async function createPluginContainer(
670
702
async close ( ) {
671
703
if ( closed ) return
672
704
const ctx = new Context ( )
673
- await Promise . all (
674
- plugins . map ( ( p ) => p . buildEnd && p . buildEnd . call ( ctx as any ) )
705
+ await hookParallel (
706
+ 'buildEnd' ,
707
+ ( ) => ctx ,
708
+ ( ) => [ ]
675
709
)
676
- await Promise . all (
677
- plugins . map ( ( p ) => p . closeBundle && p . closeBundle . call ( ctx as any ) )
710
+ await hookParallel (
711
+ 'closeBundle' ,
712
+ ( ) => ctx ,
713
+ ( ) => [ ]
678
714
)
679
715
closed = true
680
716
}
0 commit comments