@@ -17,6 +17,7 @@ import {
1717 createBrotliCompress ,
1818 createBrotliDecompress ,
1919} from 'node:zlib' ;
20+ import { limitFunction } from 'p-limit' ;
2021import rehypeAutolinkHeadings from 'rehype-autolink-headings' ;
2122import rehypePresetMinify from 'rehype-preset-minify' ;
2223import rehypePrismDiff from 'rehype-prism-diff' ;
@@ -53,6 +54,7 @@ type SlugFile = {
5354} ;
5455
5556const root = process . cwd ( ) ;
57+ const FILE_CONCURRENCY_LIMIT = 200 ;
5658const CACHE_COMPRESS_LEVEL = 4 ;
5759const CACHE_DIR = path . join ( root , '.next' , 'cache' , 'mdx-bundler' ) ;
5860mkdirSync ( CACHE_DIR , { recursive : true } ) ;
@@ -176,51 +178,60 @@ async function getDocsFrontMatterUncached(): Promise<FrontMatter[]> {
176178export async function getDevDocsFrontMatter ( ) : Promise < FrontMatter [ ] > {
177179 const folder = 'develop-docs' ;
178180 const docsPath = path . join ( root , folder ) ;
179- const files = getAllFilesRecursively ( docsPath ) ;
181+ const files = await getAllFilesRecursively ( docsPath ) ;
180182 const fmts = (
181183 await Promise . all (
182- files . map ( async file => {
183- const fileName = file . slice ( docsPath . length + 1 ) ;
184- if ( path . extname ( fileName ) !== '.md' && path . extname ( fileName ) !== '.mdx' ) {
185- return undefined ;
186- }
187-
188- const source = await readFile ( file , 'utf8' ) ;
189- const { data : frontmatter } = matter ( source ) ;
190- return {
191- ...( frontmatter as FrontMatter ) ,
192- slug : fileName . replace ( / \/ i n d e x .m d x ? $ / , '' ) . replace ( / \. m d x ? $ / , '' ) ,
193- sourcePath : path . join ( folder , fileName ) ,
194- } ;
195- } )
184+ files . map (
185+ limitFunction (
186+ async file => {
187+ const fileName = file . slice ( docsPath . length + 1 ) ;
188+ if ( path . extname ( fileName ) !== '.md' && path . extname ( fileName ) !== '.mdx' ) {
189+ return undefined ;
190+ }
191+
192+ const source = await readFile ( file , 'utf8' ) ;
193+ const { data : frontmatter } = matter ( source ) ;
194+ return {
195+ ...( frontmatter as FrontMatter ) ,
196+ slug : fileName . replace ( / \/ i n d e x .m d x ? $ / , '' ) . replace ( / \. m d x ? $ / , '' ) ,
197+ sourcePath : path . join ( folder , fileName ) ,
198+ } ;
199+ } ,
200+ { concurrency : FILE_CONCURRENCY_LIMIT }
201+ )
202+ )
196203 )
197204 ) . filter ( isNotNil ) ;
198205 return fmts ;
199206}
200207
201208async function getAllFilesFrontMatter ( ) : Promise < FrontMatter [ ] > {
202209 const docsPath = path . join ( root , 'docs' ) ;
203- const files = getAllFilesRecursively ( docsPath ) ;
210+ const files = await getAllFilesRecursively ( docsPath ) ;
204211 const allFrontMatter : FrontMatter [ ] = [ ] ;
212+
205213 await Promise . all (
206- files . map ( async file => {
207- const fileName = file . slice ( docsPath . length + 1 ) ;
208- if ( path . extname ( fileName ) !== '.md' && path . extname ( fileName ) !== '.mdx' ) {
209- return ;
210- }
214+ files . map (
215+ limitFunction ( async file => {
216+ const fileName = file . slice ( docsPath . length + 1 ) ;
217+ if ( path . extname ( fileName ) !== '.md' && path . extname ( fileName ) !== '.mdx' ) {
218+ return ;
219+ }
211220
212- if ( fileName . indexOf ( '/common/' ) !== - 1 ) {
213- return ;
214- }
221+ if ( fileName . indexOf ( '/common/' ) !== - 1 ) {
222+ return ;
223+ }
215224
216- const source = await readFile ( file , 'utf8' ) ;
217- const { data : frontmatter } = matter ( source ) ;
218- allFrontMatter . push ( {
219- ...( frontmatter as FrontMatter ) ,
220- slug : formatSlug ( fileName ) ,
221- sourcePath : path . join ( 'docs' , fileName ) ,
222- } ) ;
223- } )
225+ const source = await readFile ( file , 'utf8' ) ;
226+ const { data : frontmatter } = matter ( source ) ;
227+ allFrontMatter . push ( {
228+ ...( frontmatter as FrontMatter ) ,
229+ slug : formatSlug ( fileName ) ,
230+ sourcePath : path . join ( 'docs' , fileName ) ,
231+ } ) ;
232+ } ,
233+ { concurrency : FILE_CONCURRENCY_LIMIT } )
234+ )
224235 ) ;
225236
226237 // Add all `common` files in the right place.
@@ -251,46 +262,56 @@ async function getAllFilesFrontMatter(): Promise<FrontMatter[]> {
251262 continue ;
252263 }
253264
254- const commonFileNames : string [ ] = getAllFilesRecursively ( commonPath ) . filter (
265+ const commonFileNames : string [ ] = ( await getAllFilesRecursively ( commonPath ) ) . filter (
255266 p => path . extname ( p ) === '.mdx'
256267 ) ;
257268
258269 const commonFiles = await Promise . all (
259- commonFileNames . map ( async commonFileName => {
260- const source = await readFile ( commonFileName , 'utf8' ) ;
261- const { data : frontmatter } = matter ( source ) ;
262- return { commonFileName, frontmatter : frontmatter as FrontMatter } ;
263- } )
270+ commonFileNames . map (
271+ limitFunction (
272+ async commonFileName => {
273+ const source = await readFile ( commonFileName , 'utf8' ) ;
274+ const { data : frontmatter } = matter ( source ) ;
275+ return { commonFileName, frontmatter : frontmatter as FrontMatter } ;
276+ } ,
277+ { concurrency : FILE_CONCURRENCY_LIMIT }
278+ )
279+ )
264280 ) ;
265281
266282 await Promise . all (
267- commonFiles . map ( async f => {
268- if ( ! isSupported ( f . frontmatter , platformName ) ) {
269- return ;
270- }
271-
272- const subpath = f . commonFileName . slice ( commonPath . length + 1 ) ;
273- const slug = f . commonFileName
274- . slice ( docsPath . length + 1 )
275- . replace ( / \/ c o m m o n \/ / , '/' ) ;
276- const noFrontMatter = (
277- await Promise . allSettled ( [
278- access ( path . join ( docsPath , slug ) ) ,
279- access ( path . join ( docsPath , slug . replace ( '/index.mdx' , '.mdx' ) ) ) ,
280- ] )
281- ) . every ( r => r . status === 'rejected' ) ;
282- if ( noFrontMatter ) {
283- let frontmatter = f . frontmatter ;
284- if ( subpath === 'index.mdx' ) {
285- frontmatter = { ...frontmatter , ...platformFrontmatter } ;
286- }
287- allFrontMatter . push ( {
288- ...frontmatter ,
289- slug : formatSlug ( slug ) ,
290- sourcePath : 'docs/' + f . commonFileName . slice ( docsPath . length + 1 ) ,
291- } ) ;
292- }
293- } )
283+ commonFiles . map (
284+ limitFunction (
285+ async f => {
286+ if ( ! isSupported ( f . frontmatter , platformName ) ) {
287+ return ;
288+ }
289+
290+ const subpath = f . commonFileName . slice ( commonPath . length + 1 ) ;
291+ const slug = f . commonFileName
292+ . slice ( docsPath . length + 1 )
293+ . replace ( / \/ c o m m o n \/ / , '/' ) ;
294+ const noFrontMatter = (
295+ await Promise . allSettled ( [
296+ access ( path . join ( docsPath , slug ) ) ,
297+ access ( path . join ( docsPath , slug . replace ( '/index.mdx' , '.mdx' ) ) ) ,
298+ ] )
299+ ) . every ( r => r . status === 'rejected' ) ;
300+ if ( noFrontMatter ) {
301+ let frontmatter = f . frontmatter ;
302+ if ( subpath === 'index.mdx' ) {
303+ frontmatter = { ...frontmatter , ...platformFrontmatter } ;
304+ }
305+ allFrontMatter . push ( {
306+ ...frontmatter ,
307+ slug : formatSlug ( slug ) ,
308+ sourcePath : 'docs/' + f . commonFileName . slice ( docsPath . length + 1 ) ,
309+ } ) ;
310+ }
311+ } ,
312+ { concurrency : FILE_CONCURRENCY_LIMIT }
313+ )
314+ )
294315 ) ;
295316
296317 const guidesPath = path . join ( docsPath , 'platforms' , platformName , 'guides' ) ;
@@ -319,30 +340,41 @@ async function getAllFilesFrontMatter(): Promise<FrontMatter[]> {
319340 }
320341
321342 await Promise . all (
322- commonFiles . map ( async f => {
323- if ( ! isSupported ( f . frontmatter , platformName , guideName ) ) {
324- return ;
325- }
326-
327- const subpath = f . commonFileName . slice ( commonPath . length + 1 ) ;
328- const slug = path . join ( 'platforms' , platformName , 'guides' , guideName , subpath ) ;
329- try {
330- await access ( path . join ( docsPath , slug ) ) ;
331- return ;
332- } catch {
333- // pass
334- }
335-
336- let frontmatter = f . frontmatter ;
337- if ( subpath === 'index.mdx' ) {
338- frontmatter = { ...frontmatter , ...guideFrontmatter } ;
339- }
340- allFrontMatter . push ( {
341- ...frontmatter ,
342- slug : formatSlug ( slug ) ,
343- sourcePath : 'docs/' + f . commonFileName . slice ( docsPath . length + 1 ) ,
344- } ) ;
345- } )
343+ commonFiles . map (
344+ limitFunction (
345+ async f => {
346+ if ( ! isSupported ( f . frontmatter , platformName , guideName ) ) {
347+ return ;
348+ }
349+
350+ const subpath = f . commonFileName . slice ( commonPath . length + 1 ) ;
351+ const slug = path . join (
352+ 'platforms' ,
353+ platformName ,
354+ 'guides' ,
355+ guideName ,
356+ subpath
357+ ) ;
358+ try {
359+ await access ( path . join ( docsPath , slug ) ) ;
360+ return ;
361+ } catch {
362+ // pass
363+ }
364+
365+ let frontmatter = f . frontmatter ;
366+ if ( subpath === 'index.mdx' ) {
367+ frontmatter = { ...frontmatter , ...guideFrontmatter } ;
368+ }
369+ allFrontMatter . push ( {
370+ ...frontmatter ,
371+ slug : formatSlug ( slug ) ,
372+ sourcePath : 'docs/' + f . commonFileName . slice ( docsPath . length + 1 ) ,
373+ } ) ;
374+ } ,
375+ { concurrency : FILE_CONCURRENCY_LIMIT }
376+ )
377+ )
346378 ) ;
347379 }
348380 }
@@ -475,21 +507,17 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
475507 ) ;
476508 }
477509
478- let cacheKey : string | null = null ;
479- let cacheFile : string | null = null ;
480- if ( process . env . CI === '1' ) {
481- cacheKey = md5 ( source ) ;
482- cacheFile = path . join ( CACHE_DIR , cacheKey ) ;
510+ const cacheKey = md5 ( source ) ;
511+ const cacheFile = path . join ( CACHE_DIR , cacheKey ) ;
483512
484- try {
485- const cached = await readCacheFile < SlugFile > ( cacheFile ) ;
486- return cached ;
487- } catch ( err ) {
488- if ( err . code !== 'ENOENT' && err . code !== 'ABORT_ERR' ) {
489- // If cache is corrupted, ignore and proceed
490- // eslint-disable-next-line no-console
491- console . warn ( `Failed to read MDX cache: ${ cacheFile } ` , err ) ;
492- }
513+ try {
514+ const cached = await readCacheFile < SlugFile > ( cacheFile ) ;
515+ return cached ;
516+ } catch ( err ) {
517+ if ( err . code !== 'ENOENT' && err . code !== 'ABORT_ERR' ) {
518+ // If cache is corrupted, ignore and proceed
519+ // eslint-disable-next-line no-console
520+ console . warn ( `Failed to read MDX cache: ${ cacheFile } ` , err ) ;
493521 }
494522 }
495523
@@ -618,12 +646,10 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
618646 } ,
619647 } ;
620648
621- if ( cacheFile ) {
622- writeCacheFile ( cacheFile , JSON . stringify ( resultObj ) ) . catch ( e => {
623- // eslint-disable-next-line no-console
624- console . warn ( `Failed to write MDX cache: ${ cacheFile } ` , e ) ;
625- } ) ;
626- }
649+ writeCacheFile ( cacheFile , JSON . stringify ( resultObj ) ) . catch ( e => {
650+ // eslint-disable-next-line no-console
651+ console . warn ( `Failed to write MDX cache: ${ cacheFile } ` , e ) ;
652+ } ) ;
627653
628654 return resultObj ;
629655}
0 commit comments