@@ -20,6 +20,7 @@ interface Options {
2020 tolerance : number ;
2121 width : number ;
2222 viewHeight : number ;
23+ concurrency : number ;
2324 summaryFile : string ;
2425}
2526
@@ -31,6 +32,7 @@ function parseArgs(): Options {
3132 tolerance : 0 ,
3233 width : 1280 ,
3334 viewHeight : 1024 ,
35+ concurrency : 4 ,
3436 summaryFile : "visual_diffs/results.json" ,
3537 } ;
3638 for ( let i = 0 ; i < args . length ; i ++ ) {
@@ -56,6 +58,10 @@ function parseArgs(): Options {
5658 case "--view-height" :
5759 opts . viewHeight = Number ( args [ ++ i ] ) ;
5860 break ;
61+ case "-c" :
62+ case "--concurrency" :
63+ opts . concurrency = Number ( args [ ++ i ] ) ;
64+ break ;
5965 case "-s" :
6066 case "--summary-file" :
6167 opts . summaryFile = args [ ++ i ] ;
@@ -125,36 +131,57 @@ function compareImages(
125131 return true ;
126132}
127133
134+ async function promisePool < T > (
135+ items : T [ ] ,
136+ concurrency : number ,
137+ iteratorFn : ( item : T ) => Promise < void >
138+ ) {
139+ const executing : Promise < void > [ ] = [ ] ;
140+
141+ for ( const item of items ) {
142+ const p = iteratorFn ( item ) . then ( ( ) => {
143+ executing . splice ( executing . indexOf ( p ) , 1 ) ;
144+ } ) ;
145+ executing . push ( p ) ;
146+ if ( executing . length >= concurrency ) {
147+ await Promise . race ( executing ) ;
148+ }
149+ }
150+ await Promise . all ( executing ) ;
151+ }
152+
128153async function run ( ) {
129154 const opts = parseArgs ( ) ;
130155 if ( ! opts . previewUrl ) {
131156 throw new Error ( "Missing preview URL" ) ;
132157 }
133158 if ( ! opts . previewUrl . endsWith ( "/" ) ) opts . previewUrl += "/" ;
134159
135- const sitemapXml = await fetchSitemap ( "https://docusaurus-openapi.tryingpan.dev/sitemap.xml" ) ;
160+ const sitemapXml = await fetchSitemap (
161+ "https://docusaurus-openapi.tryingpan.dev/sitemap.xml"
162+ ) ;
163+
136164 const paths = parseUrlsFromSitemap ( await sitemapXml ) ;
137165 console . log ( `Found ${ paths . length } paths.` ) ;
138166
139167 const browser = await chromium . launch ( ) ;
140168 const context = await browser . newContext ( {
141169 viewport : { width : opts . width , height : opts . viewHeight } ,
142170 } ) ;
143- const page = await context . newPage ( ) ;
144-
145171 let total = 0 ;
146172 let matches = 0 ;
147173 let mismatches = 0 ;
148174 let skipped = 0 ;
149175 const pages : { path : string ; status : string } [ ] = [ ] ;
150176
151- for ( const url of paths ) {
177+ async function processPath ( url : string ) {
152178 total += 1 ;
153179 const cleanPath =
154180 new URL ( url ) . pathname . replace ( / ^ \/ / , "" ) . replace ( / \/ $ / , "" ) || "root" ;
155181 const prodSnap = path . join ( opts . outputDir , "prod" , `${ cleanPath } .png` ) ;
156182 const prevSnap = path . join ( opts . outputDir , "preview" , `${ cleanPath } .png` ) ;
157183 const diffImg = path . join ( opts . outputDir , "diff" , `${ cleanPath } .png` ) ;
184+ const page = await context . newPage ( ) ;
158185 try {
159186 await screenshotFullPage ( page , url , prodSnap ) ;
160187 await screenshotFullPage (
@@ -176,8 +203,11 @@ async function run() {
176203 skipped += 1 ;
177204 pages . push ( { path : `/${ cleanPath } ` , status : "skip" } ) ;
178205 }
206+ await page . close ( ) ;
179207 }
180208
209+ await promisePool ( paths , opts . concurrency , processPath ) ;
210+
181211 await browser . close ( ) ;
182212 console . log (
183213 `Total: ${ total } , Matches: ${ matches } , Diffs: ${ mismatches } , Skipped: ${ skipped } `
0 commit comments