77 regexpEscape ,
88 toFileUrl ,
99} from "./deps.ts" ;
10- import { Builder , BuildSnapshot } from "./mod.ts" ;
10+ import { getDependencies , saveSnapshot } from "./kv.ts" ;
11+ import { getFile } from "./kvfs.ts" ;
12+ import { Builder } from "./mod.ts" ;
1113
1214export interface EsbuildBuilderOptions {
1315 /** The build ID. */
@@ -29,12 +31,58 @@ export interface JSXConfig {
2931
3032export class EsbuildBuilder implements Builder {
3133 #options: EsbuildBuilderOptions ;
34+ #files: Map < string , Uint8Array > ;
35+ #dependencies: Map < string , string [ ] > | null ;
36+ #build: Promise < void > | null ;
3237
3338 constructor ( options : EsbuildBuilderOptions ) {
3439 this . #options = options ;
40+ this . #files = new Map < string , Uint8Array > ( ) ;
41+ this . #dependencies = null ;
42+ this . #build = null ;
43+ }
44+
45+ async read ( path : string ) {
46+ const content = this . #files. get ( path ) || await getFile ( path ) ;
47+
48+ if ( content ) return content ;
49+
50+ if ( ! this . #build) {
51+ this . #build = this . build ( ) ;
52+
53+ this . #build
54+ . then ( ( ) => saveSnapshot ( this . #files, this . #dependencies! ) )
55+ . catch ( ( error ) => console . error ( error ) ) ;
56+ }
57+
58+ await this . #build;
59+
60+ return this . #files. get ( path ) || null ;
61+ }
62+
63+ // Lazy load dependencies from KV to avoid blocking first render
64+ dependencies ( path : string ) : string [ ] {
65+ const deps = this . #dependencies?. get ( path ) ;
66+
67+ if ( ! this . #dependencies) {
68+ this . #dependencies = new Map ( ) ;
69+
70+ getDependencies ( ) . then ( ( d ) => {
71+ // A build happened while we were fetching deps.
72+ // It will fill deps for us with a fresh deps array
73+ if ( this . #build instanceof Promise ) {
74+ return ;
75+ } else if ( d ) {
76+ this . #dependencies = d ;
77+ }
78+ } ) . catch ( ( error ) => console . error ( error ) ) ;
79+ }
80+
81+ return deps ?? [ ] ;
3582 }
3683
37- async build ( ) : Promise < EsbuildSnapshot > {
84+ async build ( ) : Promise < void > {
85+ const start = performance . now ( ) ;
3886 const opts = this . #options;
3987 try {
4088 await initEsbuild ( ) ;
@@ -55,7 +103,7 @@ export class EsbuildBuilder implements Builder {
55103 entryPoints : opts . entrypoints ,
56104
57105 platform : "browser" ,
58- target : [ "chrome99" , "firefox99" , "safari15 " ] ,
106+ target : [ "chrome99" , "firefox99" , "safari12 " ] ,
59107
60108 format : "esm" ,
61109 bundle : true ,
@@ -78,14 +126,17 @@ export class EsbuildBuilder implements Builder {
78126 ] ,
79127 } ) ;
80128
81- const files = new Map < string , Uint8Array > ( ) ;
82- const dependencies = new Map < string , string [ ] > ( ) ;
129+ const dur = ( performance . now ( ) - start ) / 1e3 ;
130+ console . info ( ` 📦 Fresh bundle: ${ dur . toFixed ( 2 ) } s` ) ;
131+
132+ this . #files = new Map < string , Uint8Array > ( ) ;
133+ this . #dependencies = new Map < string , string [ ] > ( ) ;
83134
84135 const absWorkingDirLen = toFileUrl ( absWorkingDir ) . href . length + 1 ;
85136
86137 for ( const file of bundle . outputFiles ) {
87138 const path = toFileUrl ( file . path ) . href . slice ( absWorkingDirLen ) ;
88- files . set ( path , file . contents ) ;
139+ this . # files. set ( path , file . contents ) ;
89140 }
90141
91142 const metaOutputs = new Map ( Object . entries ( bundle . metafile . outputs ) ) ;
@@ -94,10 +145,8 @@ export class EsbuildBuilder implements Builder {
94145 const imports = entry . imports
95146 . filter ( ( { kind } ) => kind === "import-statement" )
96147 . map ( ( { path } ) => path ) ;
97- dependencies . set ( path , imports ) ;
148+ this . # dependencies. set ( path , imports ) ;
98149 }
99-
100- return new EsbuildSnapshot ( files , dependencies ) ;
101150 } finally {
102151 stopEsbuild ( ) ;
103152 }
@@ -149,28 +198,3 @@ function buildIdPlugin(buildId: string): esbuildTypes.Plugin {
149198 } ,
150199 } ;
151200}
152-
153- export class EsbuildSnapshot implements BuildSnapshot {
154- #files: Map < string , Uint8Array > ;
155- #dependencies: Map < string , string [ ] > ;
156-
157- constructor (
158- files : Map < string , Uint8Array > ,
159- dependencies : Map < string , string [ ] > ,
160- ) {
161- this . #files = files ;
162- this . #dependencies = dependencies ;
163- }
164-
165- get paths ( ) : string [ ] {
166- return Array . from ( this . #files. keys ( ) ) ;
167- }
168-
169- read ( path : string ) : Uint8Array | null {
170- return this . #files. get ( path ) ?? null ;
171- }
172-
173- dependencies ( path : string ) : string [ ] {
174- return this . #dependencies. get ( path ) ?? [ ] ;
175- }
176- }
0 commit comments