udpate: img src通过配置onerror字段实现图源容灾

This commit is contained in:
afoim
2025-05-31 16:46:03 +08:00
parent d96fd18e05
commit c49d195e5f
5 changed files with 42 additions and 1 deletions

View File

@@ -14,6 +14,7 @@ import remarkMath from "remark-math";
import remarkSectionize from "remark-sectionize";
import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs";
import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs";
import { rehypeImageFallback } from "./src/plugins/rehype-image-fallback.mjs";
import { parseDirectiveNode } from "./src/plugins/remark-directive-rehype.js";
import { remarkExcerpt } from "./src/plugins/remark-excerpt.js";
import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs";
@@ -65,6 +66,7 @@ export default defineConfig({
rehypePlugins: [
rehypeKatex,
rehypeSlug,
rehypeImageFallback,
[
rehypeComponents,
{

View File

@@ -10,6 +10,7 @@ interface Props {
}
import { Image } from "astro:assets";
import { url } from "../../utils/url-utils";
import { imageFallbackConfig } from "../../config";
const { id, src, alt, position = "center", basePath = "/" } = Astro.props;
const className = Astro.props.class;
@@ -48,6 +49,10 @@ const imageStyle = `object-position: ${position}`;
<div id={id} class:list={[className, 'overflow-hidden relative']}>
<div class="transition absolute inset-0 dark:bg-black/10 bg-opacity-50 pointer-events-none"></div>
{isLocal && img && <Image src={img} alt={alt || ""} class={imageClass} style={imageStyle}/>}
{!isLocal && <img src={isPublic ? url(src) : src} alt={alt || ""} class={imageClass} style={imageStyle}/>}
{!isLocal && (
imageFallbackConfig.enable && src.includes(imageFallbackConfig.originalDomain) ?
<img src={isPublic ? url(src) : src} alt={alt || ""} class={imageClass} style={imageStyle} onerror={`this.onerror=null; this.src='${(isPublic ? url(src) : src).replace(imageFallbackConfig.originalDomain, imageFallbackConfig.fallbackDomain)}';`}/> :
<img src={isPublic ? url(src) : src} alt={alt || ""} class={imageClass} style={imageStyle}/>
)}
</div>

View File

@@ -1,4 +1,5 @@
import type {
ImageFallbackConfig,
LicenseConfig,
NavBarConfig,
ProfileConfig,
@@ -81,3 +82,9 @@ export const licenseConfig: LicenseConfig = {
name: "CC BY-NC-SA 4.0",
url: "https://creativecommons.org/licenses/by-nc-sa/4.0/",
};
export const imageFallbackConfig: ImageFallbackConfig = {
enable: true,
originalDomain: "r2.afo.im",
fallbackDomain: "pub-d433ca7edaa74994b3d7c40a7fd7d9ac.r2.dev",
};

View File

@@ -0,0 +1,21 @@
import { visit } from 'unist-util-visit';
import { imageFallbackConfig } from '../config.ts';
export default function rehypeImageFallback() {
return (tree) => {
visit(tree, 'element', (node) => {
if (node.tagName === 'img' && node.properties && node.properties.src) {
const src = node.properties.src;
// 检查是否启用回退功能并且是来自指定域名的图片
if (imageFallbackConfig.enable && typeof src === 'string' && src.includes(imageFallbackConfig.originalDomain)) {
// 生成备用 URL
const fallbackSrc = src.replace(imageFallbackConfig.originalDomain, imageFallbackConfig.fallbackDomain);
// 添加 onerror 属性
node.properties.onerror = `this.onerror=null; this.src='${fallbackSrc}';`;
}
}
});
};
}

View File

@@ -67,6 +67,12 @@ export type LicenseConfig = {
url: string;
};
export type ImageFallbackConfig = {
enable: boolean;
originalDomain: string;
fallbackDomain: string;
};
export type LIGHT_DARK_MODE =
| typeof LIGHT_MODE
| typeof DARK_MODE