@@ -9,7 +9,7 @@ import type {
9
9
import { transform } from 'esbuild'
10
10
import type { RawSourceMap } from '@ampproject/remapping'
11
11
import type { InternalModuleFormat , SourceMap } from 'rollup'
12
- import type { TSConfckParseOptions , TSConfckParseResult } from 'tsconfck'
12
+ import type { TSConfckParseOptions } from 'tsconfck'
13
13
import { TSConfckParseError , findAll , parse } from 'tsconfck'
14
14
import {
15
15
cleanUrl ,
@@ -18,11 +18,13 @@ import {
18
18
createFilter ,
19
19
ensureWatchedFile ,
20
20
generateCodeFrame ,
21
+ timeFrom ,
21
22
} from '../utils'
22
23
import type { ResolvedConfig , ViteDevServer } from '..'
23
24
import type { Plugin } from '../plugin'
24
25
import { searchForWorkspaceRoot } from '..'
25
26
27
+ const isDebug = process . env . DEBUG
26
28
const debug = createDebugger ( 'vite:esbuild' )
27
29
28
30
const INJECT_HELPERS_IIFE_RE =
@@ -204,7 +206,8 @@ export async function transformWithEsbuild(
204
206
}
205
207
}
206
208
207
- export function esbuildPlugin ( options : ESBuildOptions ) : Plugin {
209
+ export function esbuildPlugin ( config : ResolvedConfig ) : Plugin {
210
+ const options = config . esbuild as ESBuildOptions
208
211
const { jsxInject, include, exclude, ...esbuildTransformOptions } = options
209
212
210
213
const filter = createFilter ( include || / \. ( m ? t s | [ j t ] s x ) $ / , exclude || / \. j s $ / )
@@ -226,6 +229,8 @@ export function esbuildPlugin(options: ESBuildOptions): Plugin {
226
229
keepNames : false ,
227
230
}
228
231
232
+ initTSConfck ( config . root )
233
+
229
234
return {
230
235
name : 'vite:esbuild' ,
231
236
configureServer ( _server ) {
@@ -235,9 +240,6 @@ export function esbuildPlugin(options: ESBuildOptions): Plugin {
235
240
. on ( 'change' , reloadOnTsconfigChange )
236
241
. on ( 'unlink' , reloadOnTsconfigChange )
237
242
} ,
238
- async configResolved ( config ) {
239
- await initTSConfck ( config )
240
- } ,
241
243
buildEnd ( ) {
242
244
// recycle serve to avoid preventing Node self-exit (#6815)
243
245
server = null as any
@@ -281,11 +283,10 @@ const rollupToEsbuildFormatMap: Record<
281
283
}
282
284
283
285
export const buildEsbuildPlugin = ( config : ResolvedConfig ) : Plugin => {
286
+ initTSConfck ( config . root )
287
+
284
288
return {
285
289
name : 'vite:esbuild-transpile' ,
286
- async configResolved ( config ) {
287
- await initTSConfck ( config )
288
- } ,
289
290
async renderChunk ( code , chunk , opts ) {
290
291
// @ts -expect-error injected by @vitejs/plugin-legacy
291
292
if ( opts . __vite_skip_esbuild__ ) {
@@ -432,32 +433,51 @@ function prettifyMessage(m: Message, code: string): string {
432
433
return res + `\n`
433
434
}
434
435
435
- const tsconfckParseOptions : TSConfckParseOptions = {
436
- cache : new Map < string , TSConfckParseResult > ( ) ,
437
- tsConfigPaths : undefined ,
438
- root : undefined ,
439
- resolveWithEmptyIfConfigNotFound : true ,
436
+ let tsconfckRoot : string | undefined
437
+ let tsconfckParseOptions : TSConfckParseOptions | Promise < TSConfckParseOptions > =
438
+ { resolveWithEmptyIfConfigNotFound : true }
439
+
440
+ function initTSConfck ( root : string , force = false ) {
441
+ // bail if already cached
442
+ if ( ! force && root === tsconfckRoot ) return
443
+
444
+ const workspaceRoot = searchForWorkspaceRoot ( root )
445
+
446
+ tsconfckRoot = root
447
+ tsconfckParseOptions = initTSConfckParseOptions ( workspaceRoot )
448
+
449
+ // cached as the options value itself when promise is resolved
450
+ tsconfckParseOptions . then ( ( options ) => {
451
+ if ( root === tsconfckRoot ) {
452
+ tsconfckParseOptions = options
453
+ }
454
+ } )
440
455
}
441
456
442
- async function initTSConfck ( config : ResolvedConfig ) {
443
- const workspaceRoot = searchForWorkspaceRoot ( config . root )
444
- debug ( `init tsconfck (root: ${ colors . cyan ( workspaceRoot ) } )` )
445
-
446
- tsconfckParseOptions . cache ! . clear ( )
447
- tsconfckParseOptions . root = workspaceRoot
448
- tsconfckParseOptions . tsConfigPaths = new Set ( [
449
- ...( await findAll ( workspaceRoot , {
450
- skip : ( dir ) => dir === 'node_modules' || dir === '.git' ,
451
- } ) ) ,
452
- ] )
453
- debug ( `init tsconfck end` )
457
+ async function initTSConfckParseOptions ( workspaceRoot : string ) {
458
+ const start = isDebug ? performance . now ( ) : 0
459
+
460
+ const options : TSConfckParseOptions = {
461
+ cache : new Map ( ) ,
462
+ root : workspaceRoot ,
463
+ tsConfigPaths : new Set (
464
+ await findAll ( workspaceRoot , {
465
+ skip : ( dir ) => dir === 'node_modules' || dir === '.git' ,
466
+ } ) ,
467
+ ) ,
468
+ resolveWithEmptyIfConfigNotFound : true ,
469
+ }
470
+
471
+ isDebug && debug ( timeFrom ( start ) , 'tsconfck init' , colors . dim ( workspaceRoot ) )
472
+
473
+ return options
454
474
}
455
475
456
476
async function loadTsconfigJsonForFile (
457
477
filename : string ,
458
478
) : Promise < TSConfigJSON > {
459
479
try {
460
- const result = await parse ( filename , tsconfckParseOptions )
480
+ const result = await parse ( filename , await tsconfckParseOptions )
461
481
// tsconfig could be out of root, make sure it is watched on dev
462
482
if ( server && result . tsconfigFile !== 'no_tsconfig_file_found' ) {
463
483
ensureWatchedFile ( server . watcher , result . tsconfigFile , server . config . root )
@@ -474,15 +494,15 @@ async function loadTsconfigJsonForFile(
474
494
}
475
495
}
476
496
477
- function reloadOnTsconfigChange ( changedFile : string ) {
497
+ async function reloadOnTsconfigChange ( changedFile : string ) {
478
498
// server could be closed externally after a file change is detected
479
499
if ( ! server ) return
480
500
// any tsconfig.json that's added in the workspace could be closer to a code file than a previously cached one
481
501
// any json file in the tsconfig cache could have been used to compile ts
482
502
if (
483
503
path . basename ( changedFile ) === 'tsconfig.json' ||
484
504
( changedFile . endsWith ( '.json' ) &&
485
- tsconfckParseOptions ?. cache ?. has ( changedFile ) )
505
+ ( await tsconfckParseOptions ) ?. cache ?. has ( changedFile ) )
486
506
) {
487
507
server . config . logger . info (
488
508
`changed tsconfig file detected: ${ changedFile } - Clearing cache and forcing full-reload to ensure TypeScript is compiled with updated config values.` ,
@@ -493,15 +513,15 @@ function reloadOnTsconfigChange(changedFile: string) {
493
513
server . moduleGraph . invalidateAll ( )
494
514
495
515
// reset tsconfck so that recompile works with up2date configs
496
- initTSConfck ( server . config ) . finally ( ( ) => {
497
- // server may not be available if vite config is updated at the same time
498
- if ( server ) {
499
- // force full reload
500
- server . ws . send ( {
501
- type : 'full-reload' ,
502
- path : '* ' ,
503
- } )
504
- }
505
- } )
516
+ initTSConfck ( server . config . root , true )
517
+
518
+ // server may not be available if vite config is updated at the same time
519
+ if ( server ) {
520
+ // force full reload
521
+ server . ws . send ( {
522
+ type : 'full-reload ' ,
523
+ path : '*' ,
524
+ } )
525
+ }
506
526
}
507
527
}
0 commit comments