@@ -11,7 +11,10 @@ import { TupleToUnion } from 'type-fest'
1111import * as R from 'remeda'
1212import { PluginHookNames } from '../constants/plugin'
1313import { AssertNever } from './type-assert'
14- import { PrivatePluginContextResolveOptions } from '../plugin/plugin-context'
14+ import {
15+ PluginContext ,
16+ PrivatePluginContextResolveOptions ,
17+ } from '../plugin/plugin-context'
1518import { SYMBOL_FOR_RESOLVE_CALLER_THAT_SKIP_SELF } from '../constants/plugin-context'
1619import { isPluginHookName } from './plugin'
1720
@@ -43,7 +46,7 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
4346
4447 const names : string [ ] = [ ]
4548 const batchedHooks : {
46- [ K in SupportedHookNames ] ?: NonNullable < Plugin [ K ] > [ ]
49+ [ K in SupportedHookNames ] ?: [ NonNullable < Plugin [ K ] > , Plugin ] [ ]
4750 } = { }
4851
4952 plugins . forEach ( ( plugin , index ) => {
@@ -66,47 +69,47 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
6669 const handlers = batchedHooks . buildStart ?? [ ]
6770 batchedHooks . buildStart = handlers
6871 if ( plugin . buildStart ) {
69- handlers . push ( plugin . buildStart )
72+ handlers . push ( [ plugin . buildStart , plugin ] )
7073 }
7174 break
7275 }
7376 case 'load' : {
7477 const handlers = batchedHooks . load ?? [ ]
7578 batchedHooks . load = handlers
7679 if ( plugin . load ) {
77- handlers . push ( plugin . load )
80+ handlers . push ( [ plugin . load , plugin ] )
7881 }
7982 break
8083 }
8184 case 'transform' : {
8285 const handlers = batchedHooks . transform ?? [ ]
8386 batchedHooks . transform = handlers
8487 if ( plugin . transform ) {
85- handlers . push ( plugin . transform )
88+ handlers . push ( [ plugin . transform , plugin ] )
8689 }
8790 break
8891 }
8992 case 'resolveId' : {
9093 const handlers = batchedHooks . resolveId ?? [ ]
9194 batchedHooks . resolveId = handlers
9295 if ( plugin . resolveId ) {
93- handlers . push ( plugin . resolveId )
96+ handlers . push ( [ plugin . resolveId , plugin ] )
9497 }
9598 break
9699 }
97100 case 'buildEnd' : {
98101 const handlers = batchedHooks . buildEnd ?? [ ]
99102 batchedHooks . buildEnd = handlers
100103 if ( plugin . buildEnd ) {
101- handlers . push ( plugin . buildEnd )
104+ handlers . push ( [ plugin . buildEnd , plugin ] )
102105 }
103106 break
104107 }
105108 case 'renderChunk' : {
106109 const handlers = batchedHooks . renderChunk ?? [ ]
107110 batchedHooks . renderChunk = handlers
108111 if ( plugin . renderChunk ) {
109- handlers . push ( plugin . renderChunk )
112+ handlers . push ( [ plugin . renderChunk , plugin ] )
110113 }
111114 break
112115 }
@@ -116,7 +119,7 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
116119 case 'outro' : {
117120 const hook = plugin [ pluginProp ]
118121 if ( hook ) {
119- ; ( batchedHooks [ pluginProp ] ??= [ ] ) . push ( hook )
122+ ; ( batchedHooks [ pluginProp ] ??= [ ] ) . push ( [ hook , plugin ] )
120123 }
121124 break
122125 }
@@ -133,16 +136,109 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
133136 name : `Composed(${ names . join ( ', ' ) } )` ,
134137 }
135138
139+ const createFixedPluginResolveFnMap = new Map <
140+ Plugin ,
141+ ( ctx : PluginContext ) => PluginContext [ 'resolve' ]
142+ > ( )
143+
144+ function applyFixedPluginResolveFn ( ctx : PluginContext , plugin : Plugin ) {
145+ const createFixedPluginResolveFn = createFixedPluginResolveFnMap . get ( plugin )
146+
147+ if ( createFixedPluginResolveFn ) {
148+ return {
149+ ...ctx ,
150+ resolve : createFixedPluginResolveFn ( ctx ) ,
151+ }
152+ }
153+
154+ return ctx
155+ }
156+
157+ if ( batchedHooks . resolveId ) {
158+ const batchedHandlers = batchedHooks . resolveId
159+ const handlerSymbols = batchedHandlers . map ( ( [ _handler , plugin ] ) =>
160+ Symbol ( plugin . name ?? `Anonymous` ) ,
161+ )
162+ for (
163+ let handlerIdx = 0 ;
164+ handlerIdx < batchedHandlers . length ;
165+ handlerIdx ++
166+ ) {
167+ const [ _handler , plugin ] = batchedHandlers [ handlerIdx ]
168+ const handlerSymbol = handlerSymbols [ handlerIdx ]
169+ const createFixedPluginResolveFn = (
170+ ctx : PluginContext ,
171+ ) : PluginContext [ 'resolve' ] => {
172+ return ( source , importer , rawContextResolveOptions ) => {
173+ const contextResolveOptions : PrivatePluginContextResolveOptions =
174+ rawContextResolveOptions ?? { }
175+
176+ if ( contextResolveOptions . skipSelf ) {
177+ contextResolveOptions [ SYMBOL_FOR_RESOLVE_CALLER_THAT_SKIP_SELF ] =
178+ handlerSymbol
179+ contextResolveOptions . skipSelf = false
180+ }
181+
182+ return ctx . resolve ( source , importer , contextResolveOptions )
183+ }
184+ }
185+ createFixedPluginResolveFnMap . set ( plugin , createFixedPluginResolveFn )
186+ }
187+
188+ composed . resolveId = async function (
189+ source ,
190+ importer ,
191+ rawHookResolveIdOptions ,
192+ ) {
193+ const hookResolveIdOptions : PrivateResolveIdExtraOptions =
194+ rawHookResolveIdOptions
195+
196+ const symbolForCallerThatSkipSelf =
197+ hookResolveIdOptions ?. [ SYMBOL_FOR_RESOLVE_CALLER_THAT_SKIP_SELF ]
198+
199+ for (
200+ let handlerIdx = 0 ;
201+ handlerIdx < batchedHandlers . length ;
202+ handlerIdx ++
203+ ) {
204+ const [ handler , plugin ] = batchedHandlers [ handlerIdx ]
205+ const handlerSymbol = handlerSymbols [ handlerIdx ]
206+
207+ if ( symbolForCallerThatSkipSelf === handlerSymbol ) {
208+ continue
209+ }
210+
211+ const { handler : handlerFn } = normalizeHook ( handler )
212+ const result = await handlerFn . call (
213+ applyFixedPluginResolveFn ( this , plugin ) ,
214+ source ,
215+ importer ,
216+ rawHookResolveIdOptions ,
217+ )
218+ if ( ! isNullish ( result ) ) {
219+ return result
220+ }
221+ }
222+ }
223+ }
224+
136225 R . keys ( batchedHooks ) . forEach ( ( hookName ) => {
137226 switch ( hookName ) {
227+ case 'resolveId' : {
228+ // It's handled above
229+ break
230+ }
138231 case 'buildStart' : {
139232 if ( batchedHooks . buildStart ) {
140233 const batchedHandlers = batchedHooks . buildStart
141234 composed . buildStart = async function ( options ) {
142235 await Promise . all (
143- batchedHandlers . map ( ( handler ) => {
236+ batchedHandlers . map ( ( [ handler , plugin ] ) => {
144237 const { handler : handlerFn } = normalizeHook ( handler )
145- return handlerFn . call ( this , options )
238+ return handlerFn . call (
239+ applyFixedPluginResolveFn ( this , plugin ) ,
240+ options ,
241+ )
146242 } ) ,
147243 )
148244 }
@@ -153,9 +249,12 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
153249 if ( batchedHooks . load ) {
154250 const batchedHandlers = batchedHooks . load
155251 composed . load = async function ( id ) {
156- for ( const handler of batchedHandlers ) {
252+ for ( const [ handler , plugin ] of batchedHandlers ) {
157253 const { handler : handlerFn } = normalizeHook ( handler )
158- const result = await handlerFn . call ( this , id )
254+ const result = await handlerFn . call (
255+ applyFixedPluginResolveFn ( this , plugin ) ,
256+ id ,
257+ )
159258 if ( ! isNullish ( result ) ) {
160259 return result
161260 }
@@ -178,9 +277,14 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
178277 code = newCode
179278 moduleSideEffects = newModuleSideEffects ?? undefined
180279 }
181- for ( const handler of batchedHandlers ) {
280+ for ( const [ handler , plugin ] of batchedHandlers ) {
182281 const { handler : handlerFn } = normalizeHook ( handler )
183- const result = await handlerFn . call ( this , code , id , moduleType )
282+ const result = await handlerFn . call (
283+ applyFixedPluginResolveFn ( this , plugin ) ,
284+ code ,
285+ id ,
286+ moduleType ,
287+ )
184288 if ( ! isNullish ( result ) ) {
185289 if ( typeof result === 'string' ) {
186290 updateOutput ( result )
@@ -199,73 +303,17 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
199303 }
200304 break
201305 }
202- case 'resolveId' : {
203- if ( batchedHooks . resolveId ) {
204- const batchedHandlers = batchedHooks . resolveId
205- const handlerSymbols = batchedHandlers . map ( ( _handler , idx ) =>
206- Symbol ( idx ) ,
207- )
208- composed . resolveId = async function (
209- source ,
210- importer ,
211- rawHookResolveIdOptions ,
212- ) {
213- const hookResolveIdOptions : PrivateResolveIdExtraOptions =
214- rawHookResolveIdOptions
215-
216- const symbolForCallerThatSkipSelf =
217- hookResolveIdOptions ?. [ SYMBOL_FOR_RESOLVE_CALLER_THAT_SKIP_SELF ]
218-
219- for (
220- let handlerIdx = 0 ;
221- handlerIdx < batchedHandlers . length ;
222- handlerIdx ++
223- ) {
224- const handler = batchedHandlers [ handlerIdx ]
225- const handlerSymbol = handlerSymbols [ handlerIdx ]
226-
227- if ( symbolForCallerThatSkipSelf === handlerSymbol ) {
228- continue
229- }
230-
231- const { handler : handlerFn } = normalizeHook ( handler )
232- const result = await handlerFn . call (
233- {
234- ...this ,
235- resolve : ( source , importer , rawContextResolveOptions ) => {
236- const contextResolveOptions : PrivatePluginContextResolveOptions =
237- rawContextResolveOptions ?? { }
238-
239- if ( contextResolveOptions . skipSelf ) {
240- contextResolveOptions [
241- SYMBOL_FOR_RESOLVE_CALLER_THAT_SKIP_SELF
242- ] = handlerSymbol
243- contextResolveOptions . skipSelf = false
244- }
245-
246- return this . resolve ( source , importer , contextResolveOptions )
247- } ,
248- } ,
249- source ,
250- importer ,
251- rawHookResolveIdOptions ,
252- )
253- if ( ! isNullish ( result ) ) {
254- return result
255- }
256- }
257- }
258- }
259- break
260- }
261306 case 'buildEnd' : {
262307 if ( batchedHooks . buildEnd ) {
263308 const batchedHandlers = batchedHooks . buildEnd
264309 composed . buildEnd = async function ( err ) {
265310 await Promise . all (
266- batchedHandlers . map ( ( handler ) => {
311+ batchedHandlers . map ( ( [ handler , plugin ] ) => {
267312 const { handler : handlerFn } = normalizeHook ( handler )
268- return handlerFn . call ( this , err )
313+ return handlerFn . call (
314+ applyFixedPluginResolveFn ( this , plugin ) ,
315+ err ,
316+ )
269317 } ) ,
270318 )
271319 }
@@ -276,9 +324,14 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
276324 if ( batchedHooks . renderChunk ) {
277325 const batchedHandlers = batchedHooks . renderChunk
278326 composed . renderChunk = async function ( code , chunk , options ) {
279- for ( const handler of batchedHandlers ) {
327+ for ( const [ handler , plugin ] of batchedHandlers ) {
280328 const { handler : handlerFn } = normalizeHook ( handler )
281- const result = await handlerFn . call ( this , code , chunk , options )
329+ const result = await handlerFn . call (
330+ applyFixedPluginResolveFn ( this , plugin ) ,
331+ code ,
332+ chunk ,
333+ options ,
334+ )
282335 if ( ! isNullish ( result ) ) {
283336 return result
284337 }
@@ -295,13 +348,16 @@ function createComposedPlugin(plugins: Plugin[]): Plugin {
295348 if ( hooks ?. length ) {
296349 composed [ hookName ] = async function ( chunk ) {
297350 const ret : string [ ] = [ ]
298- for ( const hook of hooks ) {
351+ for ( const [ hook , plugin ] of hooks ) {
299352 {
300353 const { handler } = normalizeHook ( hook )
301354 ret . push (
302355 typeof handler === 'string'
303356 ? handler
304- : await handler . call ( this , chunk ) ,
357+ : await handler . call (
358+ applyFixedPluginResolveFn ( this , plugin ) ,
359+ chunk ,
360+ ) ,
305361 )
306362 }
307363 }
0 commit comments