1- import { BinaryLike , createHash } from 'crypto' ;
2-
3- import { cache } from 'react' ;
41import matter from 'gray-matter' ;
52import { s } from 'hastscript' ;
63import yaml from 'js-yaml' ;
74import { bundleMDX } from 'mdx-bundler' ;
5+ import { BinaryLike , createHash } from 'node:crypto' ;
86import { createReadStream , createWriteStream , mkdirSync } from 'node:fs' ;
9- import { access , opendir , readFile } from 'node:fs/promises' ;
7+ import { access , cp , mkdir , opendir , readFile } from 'node:fs/promises' ;
108import path from 'node:path' ;
119// @ts -expect-error ts(2305) -- For some reason "compose" is not recognized in the types
1210import { compose , Readable } from 'node:stream' ;
@@ -34,6 +32,7 @@ import rehypeSlug from './rehype-slug.js';
3432import remarkCodeTabs from './remark-code-tabs' ;
3533import remarkCodeTitles from './remark-code-title' ;
3634import remarkComponentSpacing from './remark-component-spacing' ;
35+ import remarkDsnComments from './remark-dsn-comments' ;
3736import remarkExtractFrontmatter from './remark-extract-frontmatter' ;
3837import remarkFormatCodeBlocks from './remark-format-code' ;
3938import remarkImageSize from './remark-image-size' ;
@@ -42,7 +41,6 @@ import remarkVariables from './remark-variables';
4241import { FrontMatter , Platform , PlatformConfig } from './types' ;
4342import { isNotNil } from './utils' ;
4443import { isVersioned , VERSION_INDICATOR } from './versioning' ;
45- import remarkDsnComments from './remark-dsn-comments' ;
4644
4745type SlugFile = {
4846 frontMatter : Platform & { slug : string } ;
@@ -74,14 +72,15 @@ async function readCacheFile<T>(file: string): Promise<T> {
7472}
7573
7674async function writeCacheFile ( file : string , data : string ) {
75+ const bufferData = Buffer . from ( data ) ;
7776 await pipeline (
78- Readable . from ( data ) ,
77+ Readable . from ( bufferData ) ,
7978 createBrotliCompress ( {
8079 chunkSize : 32 * 1024 ,
8180 params : {
8281 [ zlibConstants . BROTLI_PARAM_MODE ] : zlibConstants . BROTLI_MODE_TEXT ,
8382 [ zlibConstants . BROTLI_PARAM_QUALITY ] : CACHE_COMPRESS_LEVEL ,
84- [ zlibConstants . BROTLI_PARAM_SIZE_HINT ] : data . length ,
83+ [ zlibConstants . BROTLI_PARAM_SIZE_HINT ] : bufferData . length ,
8584 } ,
8685 } ) ,
8786 createWriteStream ( file )
@@ -523,17 +522,33 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
523522 ) ;
524523 }
525524
526- const cacheKey = md5 ( source ) ;
527- const cacheFile = path . join ( CACHE_DIR , cacheKey ) ;
525+ let cacheKey : string | null = null ;
526+ let cacheFile : string | null = null ;
527+ let assetsCacheDir : string | null = null ;
528+ const outdir = path . join ( root , 'public' , 'mdx-images' ) ;
529+ await mkdir ( outdir , { recursive : true } ) ;
528530
529- try {
530- const cached = await readCacheFile < SlugFile > ( cacheFile ) ;
531- return cached ;
532- } catch ( err ) {
533- if ( err . code !== 'ENOENT' && err . code !== 'ABORT_ERR' ) {
534- // If cache is corrupted, ignore and proceed
535- // eslint-disable-next-line no-console
536- console . warn ( `Failed to read MDX cache: ${ cacheFile } ` , err ) ;
531+ if ( process . env . CI ) {
532+ cacheKey = md5 ( source ) ;
533+ cacheFile = path . join ( CACHE_DIR , `${ cacheKey } .br` ) ;
534+ assetsCacheDir = path . join ( CACHE_DIR , cacheKey ) ;
535+
536+ try {
537+ const [ cached , _ ] = await Promise . all ( [
538+ readCacheFile < SlugFile > ( cacheFile ) ,
539+ cp ( assetsCacheDir , outdir , { recursive : true } ) ,
540+ ] ) ;
541+ return cached ;
542+ } catch ( err ) {
543+ if (
544+ err . code !== 'ENOENT' &&
545+ err . code !== 'ABORT_ERR' &&
546+ err . code !== 'Z_BUF_ERROR'
547+ ) {
548+ // If cache is corrupted, ignore and proceed
549+ // eslint-disable-next-line no-console
550+ console . warn ( `Failed to read MDX cache: ${ cacheFile } ` , err ) ;
551+ }
537552 }
538553 }
539554
@@ -632,8 +647,12 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
632647 '.svg' : 'dataurl' ,
633648 } ;
634649 // Set the `outdir` to a public location for this bundle.
635- // this where this images will be copied
636- options . outdir = path . join ( root , 'public' , 'mdx-images' ) ;
650+ // this is where these images will be copied
651+ // the reason we use the cache folder when it's
652+ // enabled is because mdx-images is a dumping ground
653+ // for all images, so we cannot filter it out only
654+ // for this specific slug easily
655+ options . outdir = assetsCacheDir || outdir ;
637656
638657 // Set write to true so that esbuild will output the files.
639658 options . write = true ;
@@ -663,17 +682,30 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
663682 } ,
664683 } ;
665684
666- writeCacheFile ( cacheFile , JSON . stringify ( resultObj ) ) . catch ( e => {
667- // eslint-disable-next-line no-console
668- console . warn ( `Failed to write MDX cache: ${ cacheFile } ` , e ) ;
669- } ) ;
685+ if ( assetsCacheDir && cacheFile ) {
686+ await cp ( assetsCacheDir , outdir , { recursive : true } ) ;
687+ writeCacheFile ( cacheFile , JSON . stringify ( resultObj ) ) . catch ( e => {
688+ // eslint-disable-next-line no-console
689+ console . warn ( `Failed to write MDX cache: ${ cacheFile } ` , e ) ;
690+ } ) ;
691+ }
670692
671693 return resultObj ;
672694}
673695
696+ const fileBySlugCache = new Map < string , Promise < SlugFile > > ( ) ;
697+
674698/**
675699 * Cache the result of {@link getFileBySlug}.
676700 *
677701 * This is useful for performance when rendering the same file multiple times.
678702 */
679- export const getFileBySlugWithCache = cache ( getFileBySlug ) ;
703+ export function getFileBySlugWithCache ( slug : string ) : Promise < SlugFile > {
704+ let cached = fileBySlugCache . get ( slug ) ;
705+ if ( ! cached ) {
706+ cached = getFileBySlug ( slug ) ;
707+ fileBySlugCache . set ( slug , cached ) ;
708+ }
709+
710+ return cached ;
711+ }
0 commit comments