@@ -5,7 +5,6 @@ import { Plugin } from "unified";
55import { visit } from "unist-util-visit" ;
66
77import { EMBED_MIN_HEIGHT , EMBED_SIZE } from "../constants" ;
8- import { fromHtml } from "hast-util-from-html" ;
98import { find } from "unist-util-find" ;
109import { getLargestManifestIcon } from "../../get-largest-manifest-icon" ;
1110import { IFramePlaceholder } from "./iframe-placeholder" ;
@@ -15,36 +14,43 @@ import * as stream from "stream";
1514import sharp from "sharp" ;
1615import * as svgo from "svgo" ;
1716import { fetchPageHtml , getPageTitle } from "utils/fetch-page-html" ;
17+ import { LRUCache } from "lru-cache" ;
1818
1919interface RehypeUnicornIFrameClickToRunProps {
2020 srcReplacements ?: Array < ( val : string , root : VFile ) => string > ;
2121}
2222
2323// default icon, used if a frame's favicon cannot be resolved
24- const defaultPageIcon = "/link.png " ;
24+ const defaultPageIcon = "/icons/website.svg " ;
2525
2626function getIconPath ( src : URL ) {
2727 return `generated/${ src . hostname } .favicon` ;
2828}
2929
3030// Cache the fetch *promises* - so that only one request per manifest/icon is processed,
3131// and multiple fetchPageInfo() calls can await the same icon
32- const pageIconMap = new Map < string , Promise < string > > ( ) ;
32+ const pageIconCache = new LRUCache < string , Promise < string > > ( {
33+ max : 50 ,
34+ } ) ;
35+
3336function fetchPageIcon ( src : URL , srcHast : Root ) : Promise < string > {
34- if ( pageIconMap . has ( src . hostname ) ) return pageIconMap . get ( src . hostname ) ! ;
37+ if ( pageIconCache . has ( src . hostname ) ) return pageIconCache . get ( src . hostname ) ! ;
3538
3639 const promise = ( async ( ) => {
3740 const iconPath = getIconPath ( src ) ;
38- const iconDir = await fs . promises
39- . readdir ( path . dirname ( iconPath ) )
41+ const iconDir = path . dirname ( "public/" + iconPath ) ;
42+ await fs . promises . mkdir ( iconDir , { recursive : true } ) ;
43+
44+ const existingIconFiles = await fs . promises
45+ . readdir ( iconDir )
4046 . catch ( ( ) => [ ] ) ;
4147
4248 // If an icon has already been downloaded for the origin (in a previous build)
43- const existingIconFile = iconDir . find ( ( file ) =>
49+ const existingIconFile = existingIconFiles . find ( ( file ) =>
4450 file . startsWith ( path . basename ( iconPath ) ) ,
4551 ) ;
4652 if ( existingIconFile ) {
47- return path . join ( path . dirname ( iconPath ) , existingIconFile ) ;
53+ return iconDir . replace ( / ^ p u b l i c / , "" ) + "/" + existingIconFile ;
4854 }
4955
5056 // <link rel="manifest" href="/manifest.json">
@@ -132,10 +138,13 @@ function fetchPageIcon(src: URL, srcHast: Root): Promise<string> {
132138 return "/" + iconPath + iconExt ;
133139 } ) ( )
134140 // if an error is thrown, or response is null, use the default page icon
135- . catch ( ( ) => null )
141+ . catch ( ( e ) => {
142+ console . error ( "[rehypeIFrameClickToRun]" , e ) ;
143+ return null ;
144+ } )
136145 . then ( ( p ) => p || defaultPageIcon ) ;
137146
138- pageIconMap . set ( src . hostname , promise ) ;
147+ pageIconCache . set ( src . hostname , promise ) ;
139148 return promise ;
140149}
141150
@@ -206,6 +215,7 @@ export const rehypeUnicornIFrameClickToRun: Plugin<
206215 src : String ( src ) ,
207216 pageTitle : String ( dataFrameTitle ?? "" ) || info . title || "" ,
208217 pageIcon : info . iconFile ,
218+ pageIconFallback : defaultPageIcon ,
209219 propsToPreserve : JSON . stringify ( propsToPreserve ) ,
210220 } ) ;
211221
0 commit comments