@@ -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,56 @@ 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+ ) ;
136163 const paths = parseUrlsFromSitemap ( await sitemapXml ) ;
137164 console . log ( `Found ${ paths . length } paths.` ) ;
138165
139166 const browser = await chromium . launch ( ) ;
140167 const context = await browser . newContext ( {
141168 viewport : { width : opts . width , height : opts . viewHeight } ,
142169 } ) ;
143- const page = await context . newPage ( ) ;
144-
145170 let total = 0 ;
146171 let matches = 0 ;
147172 let mismatches = 0 ;
148173 let skipped = 0 ;
149174 const pages : { path : string ; status : string } [ ] = [ ] ;
150175
151- for ( const url of paths ) {
176+ async function processPath ( url : string ) {
152177 total += 1 ;
153178 const cleanPath =
154179 new URL ( url ) . pathname . replace ( / ^ \/ / , "" ) . replace ( / \/ $ / , "" ) || "root" ;
155180 const prodSnap = path . join ( opts . outputDir , "prod" , `${ cleanPath } .png` ) ;
156181 const prevSnap = path . join ( opts . outputDir , "preview" , `${ cleanPath } .png` ) ;
157182 const diffImg = path . join ( opts . outputDir , "diff" , `${ cleanPath } .png` ) ;
183+ const page = await context . newPage ( ) ;
158184 try {
159185 await screenshotFullPage ( page , url , prodSnap ) ;
160186 await screenshotFullPage (
@@ -176,8 +202,11 @@ async function run() {
176202 skipped += 1 ;
177203 pages . push ( { path : `/${ cleanPath } ` , status : "skip" } ) ;
178204 }
205+ await page . close ( ) ;
179206 }
180207
208+ await promisePool ( paths , opts . concurrency , processPath ) ;
209+
181210 await browser . close ( ) ;
182211 console . log (
183212 `Total: ${ total } , Matches: ${ matches } , Diffs: ${ mismatches } , Skipped: ${ skipped } `
0 commit comments