mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-19 10:54:06 -06:00
chore(cache): add cached link icon part in the icon link plugin
This commit is contained in:
parent
442371f401
commit
a1d8fc2751
@ -20,6 +20,10 @@ This plugin accepts the following configuration options:
|
||||
- `lazyLoad`: If `true`, adds lazy loading to resource elements (`img`, `video`, etc.) to improve page load performance. Defaults to `false`.
|
||||
- `externalLinkIcon`: Adds an icon next to external links when `true` (default) to visually distinguishing them from internal links.
|
||||
- `showLinkFavicon`: If `true`, displays the favicon of external websites before each external link, making it easier to visually identify the source of the link. Defaults to `false`.
|
||||
- **Note:** This feature is **disabled by default**. Favicons are fetched from Google's favicon service.
|
||||
- **Caching:** Favicons are cached in memory during the build process. Each unique domain is fetched only once, even if there are multiple links to that domain. This prevents excessive API calls and rate limiting issues.
|
||||
- `cacheLinkFavicons`: If `true`, preemptively fetches and caches external link favicons during the build process. This ensures favicons are available immediately on page load without additional runtime requests. Defaults to `false`.
|
||||
- **Use case:** Enable this option if you want to avoid any runtime favicon requests and ensure all favicons are cached during build time.
|
||||
|
||||
> [!warning]
|
||||
> Removing this plugin is _not_ recommended and will likely break the page.
|
||||
|
||||
40
package-lock.json
generated
40
package-lock.json
generated
@ -96,13 +96,13 @@
|
||||
"node_modules/@bufbuild/protobuf": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.0.tgz",
|
||||
"integrity": "sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ=="
|
||||
"integrity": "sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@citation-js/core": {
|
||||
"version": "0.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.14.tgz",
|
||||
"integrity": "sha512-dgeGqYDSQmn2MtnWZkwPGpJQPh43yr1lAAr9jl1NJ9pIY1RXUQxtlAUZVur0V9PHdbfQC+kkvB1KC3VpgVV3MA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@citation-js/date": "^0.5.0",
|
||||
"@citation-js/name": "^0.4.2",
|
||||
@ -2300,7 +2300,8 @@
|
||||
"node_modules/buffer-builder": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz",
|
||||
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg=="
|
||||
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
@ -2419,7 +2420,8 @@
|
||||
"node_modules/colorjs.io": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
|
||||
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw=="
|
||||
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/comma-separated-tokens": {
|
||||
"version": "2.0.3",
|
||||
@ -2792,7 +2794,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@ -2971,7 +2972,6 @@
|
||||
"integrity": "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
@ -3382,6 +3382,7 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -5525,7 +5526,6 @@
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.28.0.tgz",
|
||||
"integrity": "sha512-rytDAoiXr3+t6OIP3WGlDd0ouCUG1iCWzkcY3++Nreuoi17y6T5i/zRhe6uYfoVcxq6YU+sBtJouuRDsq8vvqA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
@ -6082,6 +6082,7 @@
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
|
||||
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
@ -6166,6 +6167,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6181,6 +6183,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6196,6 +6199,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6211,6 +6215,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6226,6 +6231,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6241,6 +6247,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6256,6 +6263,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6271,6 +6279,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6286,6 +6295,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6301,6 +6311,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6316,6 +6327,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6331,6 +6343,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6346,6 +6359,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6361,6 +6375,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6376,6 +6391,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6391,6 +6407,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6406,6 +6423,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6421,6 +6439,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6436,6 +6455,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6451,6 +6471,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -6620,7 +6641,6 @@
|
||||
"version": "1.26.2",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.26.2.tgz",
|
||||
"integrity": "sha512-iP7u2NA9A6JwRRCkIUREEX2cMhlYV5EBmbbSlfSRvPThwca8HBRbVkWuNWW+kw9+i6BSUZqqG6YeUs5dC2SjZw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@shikijs/core": "1.26.2",
|
||||
"@shikijs/engine-javascript": "1.26.2",
|
||||
@ -6790,6 +6810,7 @@
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
@ -7125,7 +7146,8 @@
|
||||
"node_modules/varint": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
|
||||
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="
|
||||
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/vfile": {
|
||||
"version": "6.0.3",
|
||||
|
||||
@ -22,7 +22,10 @@ interface Options {
|
||||
openLinksInNewTab: boolean
|
||||
lazyLoad: boolean
|
||||
externalLinkIcon: boolean
|
||||
/** Show favicon for external links (fetched from local cache or Google during build). Defaults to false. */
|
||||
showLinkFavicon: boolean
|
||||
/** Fetch and cache external link favicons during build time. Defaults to false. */
|
||||
cacheLinkFavicons: boolean
|
||||
}
|
||||
|
||||
const defaultOptions: Options = {
|
||||
@ -32,6 +35,24 @@ const defaultOptions: Options = {
|
||||
lazyLoad: false,
|
||||
externalLinkIcon: true,
|
||||
showLinkFavicon: false,
|
||||
cacheLinkFavicons: false,
|
||||
}
|
||||
|
||||
const _faviconCache: Map<string, string | "ERROR"> = new Map()
|
||||
|
||||
/**
|
||||
* Get cached favicon URL for a domain, or return the Google Favicon API URL.
|
||||
* Results are cached to ensure each unique domain is only fetched once per build.
|
||||
*/
|
||||
function getFaviconUrl(domain: string): string | null {
|
||||
if (_faviconCache.has(domain)) {
|
||||
const cached = _faviconCache.get(domain)
|
||||
return cached === "ERROR" ? null : cached!
|
||||
}
|
||||
|
||||
const faviconUrl = `https://s2.googleusercontent.com/s2/favicons?domain_url=${domain}`
|
||||
_faviconCache.set(domain, faviconUrl)
|
||||
return faviconUrl
|
||||
}
|
||||
|
||||
export const CrawlLinks: QuartzTransformerPlugin<Partial<Options>> = (userOpts) => {
|
||||
@ -41,7 +62,7 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
|
||||
htmlPlugins(ctx) {
|
||||
return [
|
||||
() => {
|
||||
return (tree: Root, file) => {
|
||||
return (tree: Root, file: any) => {
|
||||
const curSlug = simplifySlug(file.data.slug!)
|
||||
const outgoing: Set<SimpleSlug> = new Set()
|
||||
|
||||
@ -88,17 +109,21 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
|
||||
if (isExternal && opts.showLinkFavicon) {
|
||||
const domain = new URL(node.properties.href).hostname
|
||||
if (domain) {
|
||||
node.children.unshift({
|
||||
type: "element",
|
||||
tagName: "img",
|
||||
properties: {
|
||||
src: `https://s2.googleusercontent.com/s2/favicons?domain_url=${domain}`,
|
||||
alt: "",
|
||||
style:
|
||||
"width: 1em; height: auto; margin-left: 4px; margin-right: 4px; vertical-align: middle;",
|
||||
},
|
||||
children: [],
|
||||
})
|
||||
const faviconUrl = getFaviconUrl(domain)
|
||||
if (faviconUrl) {
|
||||
node.children.unshift({
|
||||
type: "element",
|
||||
tagName: "img",
|
||||
properties: {
|
||||
src: faviconUrl,
|
||||
alt: "",
|
||||
loading: "lazy",
|
||||
style:
|
||||
"width: 1em; height: auto; margin-left: 4px; margin-right: 4px; vertical-align: middle;",
|
||||
},
|
||||
children: [],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user