@@ -6,8 +6,10 @@ import colors from 'picocolors'
6
6
import type { BuildOptions as EsbuildBuildOptions } from 'esbuild'
7
7
import { build } from 'esbuild'
8
8
import { init , parse } from 'es-module-lexer'
9
+ import { createFilter } from '@rollup/pluginutils'
9
10
import type { ResolvedConfig } from '../config'
10
11
import {
12
+ arraify ,
11
13
createDebugger ,
12
14
emptyDir ,
13
15
flattenId ,
@@ -43,10 +45,13 @@ export type ExportsData = {
43
45
}
44
46
45
47
export interface DepsOptimizer {
46
- metadata : DepOptimizationMetadata
48
+ metadata : ( options : { ssr : boolean } ) => DepOptimizationMetadata
47
49
scanProcessing ?: Promise < void >
48
-
49
- registerMissingImport : ( id : string , resolved : string ) => OptimizedDepInfo
50
+ registerMissingImport : (
51
+ id : string ,
52
+ resolved : string ,
53
+ ssr ?: boolean
54
+ ) => OptimizedDepInfo
50
55
run : ( ) => void
51
56
52
57
isOptimizedDepFile : ( id : string ) => boolean
@@ -232,6 +237,53 @@ export async function optimizeDeps(
232
237
return result . metadata
233
238
}
234
239
240
+ export async function optimizeServerSsrDeps (
241
+ config : ResolvedConfig
242
+ ) : Promise < DepOptimizationMetadata > {
243
+ const cachedMetadata = loadCachedDepOptimizationMetadata (
244
+ config ,
245
+ config . optimizeDeps . force ,
246
+ false ,
247
+ true // ssr
248
+ )
249
+ if ( cachedMetadata ) {
250
+ return cachedMetadata
251
+ }
252
+
253
+ let alsoInclude : string [ ] | undefined
254
+ let noExternalFilter : ( ( id : unknown ) => boolean ) | undefined
255
+
256
+ const noExternal = config . ssr ?. noExternal
257
+ if ( noExternal ) {
258
+ alsoInclude = arraify ( noExternal ) . filter (
259
+ ( ne ) => typeof ne === 'string'
260
+ ) as string [ ]
261
+ noExternalFilter =
262
+ noExternal === true
263
+ ? ( dep : unknown ) => false
264
+ : createFilter ( noExternal , config . optimizeDeps ?. exclude , {
265
+ resolve : false
266
+ } )
267
+ }
268
+
269
+ const deps : Record < string , string > = { }
270
+
271
+ await addManuallyIncludedOptimizeDeps (
272
+ deps ,
273
+ config ,
274
+ alsoInclude ,
275
+ noExternalFilter
276
+ )
277
+
278
+ const depsInfo = toDiscoveredDependencies ( config , deps , true )
279
+
280
+ const result = await runOptimizeDeps ( config , depsInfo , true )
281
+
282
+ await result . commit ( )
283
+
284
+ return result . metadata
285
+ }
286
+
235
287
export function initDepsOptimizerMetadata (
236
288
config : ResolvedConfig ,
237
289
timestamp ?: string
@@ -264,7 +316,8 @@ export function addOptimizedDepInfo(
264
316
export function loadCachedDepOptimizationMetadata (
265
317
config : ResolvedConfig ,
266
318
force = config . optimizeDeps . force ,
267
- asCommand = false
319
+ asCommand = false ,
320
+ ssr = ! ! config . build . ssr
268
321
) : DepOptimizationMetadata | undefined {
269
322
const log = asCommand ? config . logger . info : debug
270
323
@@ -274,7 +327,7 @@ export function loadCachedDepOptimizationMetadata(
274
327
emptyDir ( config . cacheDir )
275
328
}
276
329
277
- const depsCacheDir = getDepsCacheDir ( config )
330
+ const depsCacheDir = getDepsCacheDir ( config , ssr )
278
331
279
332
if ( ! force ) {
280
333
let cachedMetadata : DepOptimizationMetadata | undefined
@@ -341,6 +394,15 @@ export async function initialProjectDependencies(
341
394
342
395
await addManuallyIncludedOptimizeDeps ( deps , config )
343
396
397
+ return toDiscoveredDependencies ( config , deps , ! ! config . build . ssr , timestamp )
398
+ }
399
+
400
+ export function toDiscoveredDependencies (
401
+ config : ResolvedConfig ,
402
+ deps : Record < string , string > ,
403
+ ssr : boolean ,
404
+ timestamp ?: string
405
+ ) : Record < string , OptimizedDepInfo > {
344
406
const browserHash = getOptimizedBrowserHash (
345
407
getDepHash ( config ) ,
346
408
deps ,
@@ -351,7 +413,7 @@ export async function initialProjectDependencies(
351
413
const src = deps [ id ]
352
414
discovered [ id ] = {
353
415
id,
354
- file : getOptimizedDepPath ( id , config ) ,
416
+ file : getOptimizedDepPath ( id , config , ssr ) ,
355
417
src,
356
418
browserHash : browserHash ,
357
419
exportsData : extractExportsData ( src , config )
@@ -381,16 +443,17 @@ export function depsLogString(qualifiedIds: string[]): string {
381
443
*/
382
444
export async function runOptimizeDeps (
383
445
resolvedConfig : ResolvedConfig ,
384
- depsInfo : Record < string , OptimizedDepInfo >
446
+ depsInfo : Record < string , OptimizedDepInfo > ,
447
+ ssr : boolean = ! ! resolvedConfig . build . ssr
385
448
) : Promise < DepOptimizationResult > {
386
449
const isBuild = resolvedConfig . command === 'build'
387
450
const config : ResolvedConfig = {
388
451
...resolvedConfig ,
389
452
command : 'build'
390
453
}
391
454
392
- const depsCacheDir = getDepsCacheDir ( resolvedConfig )
393
- const processingCacheDir = getProcessingDepsCacheDir ( resolvedConfig )
455
+ const depsCacheDir = getDepsCacheDir ( resolvedConfig , ssr )
456
+ const processingCacheDir = getProcessingDepsCacheDir ( resolvedConfig , ssr )
394
457
395
458
// Create a temporal directory so we don't need to delete optimized deps
396
459
// until they have been processed. This also avoids leaving the deps cache
@@ -526,7 +589,7 @@ export async function runOptimizeDeps(
526
589
const id = path
527
590
. relative ( processingCacheDirOutputPath , o )
528
591
. replace ( jsExtensionRE , '' )
529
- const file = getOptimizedDepPath ( id , resolvedConfig )
592
+ const file = getOptimizedDepPath ( id , resolvedConfig , ssr )
530
593
if (
531
594
! findOptimizedDepInfoInRecord (
532
595
metadata . optimized ,
@@ -561,16 +624,18 @@ export async function findKnownImports(
561
624
562
625
async function addManuallyIncludedOptimizeDeps (
563
626
deps : Record < string , string > ,
564
- config : ResolvedConfig
627
+ config : ResolvedConfig ,
628
+ extra ?: string [ ] ,
629
+ filter ?: ( id : string ) => boolean
565
630
) : Promise < void > {
566
- const include = config . optimizeDeps ?. include
631
+ const include = [ ... ( config . optimizeDeps ?. include ?? [ ] ) , ... ( extra ?? [ ] ) ]
567
632
if ( include ) {
568
633
const resolve = config . createResolver ( { asSrc : false , scan : true } )
569
634
for ( const id of include ) {
570
635
// normalize 'foo >bar` as 'foo > bar' to prevent same id being added
571
636
// and for pretty printing
572
637
const normalizedId = normalizeId ( id )
573
- if ( ! deps [ normalizedId ] ) {
638
+ if ( ! deps [ normalizedId ] && filter ?. ( normalizedId ) !== false ) {
574
639
const entry = await resolve ( id )
575
640
if ( entry ) {
576
641
deps [ normalizedId ] = entry
@@ -603,49 +668,55 @@ export function depsFromOptimizedDepInfo(
603
668
604
669
export function getOptimizedDepPath (
605
670
id : string ,
606
- config : ResolvedConfig
671
+ config : ResolvedConfig ,
672
+ ssr : boolean = ! ! config . build . ssr
607
673
) : string {
608
674
return normalizePath (
609
- path . resolve ( getDepsCacheDir ( config ) , flattenId ( id ) + '.js' )
675
+ path . resolve ( getDepsCacheDir ( config , ssr ) , flattenId ( id ) + '.js' )
610
676
)
611
677
}
612
678
613
- function getDepsCacheSuffix ( config : ResolvedConfig ) : string {
679
+ function getDepsCacheSuffix ( config : ResolvedConfig , ssr : boolean ) : string {
614
680
let suffix = ''
615
681
if ( config . command === 'build' ) {
616
682
// Differentiate build caches depending on outDir to allow parallel builds
617
683
const { outDir } = config . build
618
684
const buildId =
619
685
outDir . length > 8 || outDir . includes ( '/' ) ? getHash ( outDir ) : outDir
620
686
suffix += `_build-${ buildId } `
621
- if ( config . build . ssr ) {
622
- suffix += '_ssr'
623
- }
687
+ }
688
+ if ( ssr ) {
689
+ suffix += '_ssr'
624
690
}
625
691
return suffix
626
692
}
627
- export function getDepsCacheDir ( config : ResolvedConfig ) : string {
628
- const dirName = 'deps' + getDepsCacheSuffix ( config )
629
- return normalizePath ( path . resolve ( config . cacheDir , dirName ) )
693
+
694
+ export function getDepsCacheDir ( config : ResolvedConfig , ssr : boolean ) : string {
695
+ return getDepsCacheDirPrefix ( config ) + getDepsCacheSuffix ( config , ssr )
696
+ }
697
+
698
+ function getProcessingDepsCacheDir ( config : ResolvedConfig , ssr : boolean ) {
699
+ return (
700
+ getDepsCacheDirPrefix ( config ) + getDepsCacheSuffix ( config , ssr ) + '_temp'
701
+ )
630
702
}
631
703
632
- function getProcessingDepsCacheDir ( config : ResolvedConfig ) {
633
- const dirName = 'deps' + getDepsCacheSuffix ( config ) + '_temp'
634
- return normalizePath ( path . resolve ( config . cacheDir , dirName ) )
704
+ export function getDepsCacheDirPrefix ( config : ResolvedConfig ) : string {
705
+ return normalizePath ( path . resolve ( config . cacheDir , 'deps' ) )
635
706
}
636
707
637
708
export function isOptimizedDepFile (
638
709
id : string ,
639
710
config : ResolvedConfig
640
711
) : boolean {
641
- return id . startsWith ( getDepsCacheDir ( config ) )
712
+ return id . startsWith ( getDepsCacheDirPrefix ( config ) )
642
713
}
643
714
644
715
export function createIsOptimizedDepUrl (
645
716
config : ResolvedConfig
646
717
) : ( url : string ) => boolean {
647
718
const { root } = config
648
- const depsCacheDir = getDepsCacheDir ( config )
719
+ const depsCacheDir = getDepsCacheDirPrefix ( config )
649
720
650
721
// determine the url prefix of files inside cache directory
651
722
const depsCacheDirRelative = normalizePath ( path . relative ( root , depsCacheDir ) )
0 commit comments