Skip to content

Commit 0aa21e7

Browse files
committed
外部连接按钮处理,修复 301问题
1 parent a56d1d5 commit 0aa21e7

2 files changed

Lines changed: 48 additions & 84 deletions

File tree

astro.config.mjs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import rehypeKatex from 'rehype-katex';
1010
import remarkBreaks from 'remark-breaks';
1111
import remarkMath from 'remark-math';
1212

13-
14-
1513
import AstroPureIntegration from './packages/pure/index.ts';
1614
// Local integrations
1715
// Local rehype & remark plugins
@@ -28,7 +26,10 @@ export default defineConfig({
2826
// Top-Level Options
2927
site: 'https://8cat.life',
3028
// base: '/docs',
31-
trailingSlash: 'always',
29+
trailingSlash: 'never',
30+
build: {
31+
format: 'file'
32+
},
3233

3334
// Adapter
3435
// https://docs.astro.build/en/guides/deploy/

packages/pure/plugins/rehype-external-links.ts

Lines changed: 44 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ export default function rehypeExternalLinks(options: ExternalLinkOptions = {}) {
2323
customIcons = {}
2424
} = options
2525

26-
return async function transformer(tree: Root): Promise<void> {
27-
const nodesToProcess: { node: Element; hostname: string }[] = []
28-
26+
return function transformer(tree: Root): void {
2927
visit(tree, 'element', (node: Element) => {
3028
if (node.tagName === 'a' && typeof node.properties?.href === 'string') {
3129
const href = node.properties.href
@@ -43,92 +41,57 @@ export default function rehypeExternalLinks(options: ExternalLinkOptions = {}) {
4341
const url = protocolRelative ? `http:${href}` : href
4442
try {
4543
const hostname = new URL(url).hostname
46-
nodesToProcess.push({ node, hostname })
47-
} catch (e) {
48-
// Ignore invalid URLs
49-
}
50-
}
51-
}
52-
})
53-
54-
await Promise.all(
55-
nodesToProcess.map(async ({ node, hostname }) => {
56-
let iconNode: Element | undefined
44+
let iconNode: Element | undefined
5745

58-
const customIconKey = customIcons?.[hostname]
59-
if (customIconKey) {
60-
let svgString = Icons[customIconKey as keyof typeof Icons]
61-
if (svgString) {
62-
if (!svgString.trim().startsWith('<svg')) {
63-
svgString = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">${svgString}</svg>`
64-
}
65-
const dataUri = `data:image/svg+xml;base64,${Buffer.from(svgString).toString('base64')}`
66-
iconNode = {
67-
type: 'element',
68-
tagName: 'img',
69-
properties: {
70-
src: dataUri,
71-
className: ['external-link-icon'],
72-
alt: '', // Decorative
73-
width: 16,
74-
height: 16
75-
},
76-
children: []
46+
const customIconKey = customIcons?.[hostname]
47+
if (customIconKey) {
48+
let svgString = Icons[customIconKey as keyof typeof Icons]
49+
if (svgString) {
50+
if (!svgString.trim().startsWith('<svg')) {
51+
svgString = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">${svgString}</svg>`
52+
}
53+
const dataUri = `data:image/svg+xml;base64,${Buffer.from(svgString).toString(
54+
'base64'
55+
)}`
56+
iconNode = {
57+
type: 'element',
58+
tagName: 'img',
59+
properties: {
60+
src: dataUri,
61+
className: ['external-link-icon'],
62+
alt: '', // Decorative
63+
width: 16,
64+
height: 16
65+
},
66+
children: []
67+
}
68+
}
7769
}
78-
}
79-
}
8070

81-
if (!iconNode) {
82-
const controller = new AbortController()
83-
const timeout = setTimeout(() => {
84-
controller.abort()
85-
}, 2000)
86-
87-
try {
88-
const response = await fetch(`https://www.google.com/s2/favicons?domain=${hostname}&size=16`, {
89-
signal: controller.signal
90-
})
91-
92-
if (!response.ok) {
93-
throw new Error(`Failed to fetch favicon for ${hostname}, status: ${response.status}`)
71+
if (!iconNode) {
72+
iconNode = {
73+
type: 'element',
74+
tagName: 'img',
75+
properties: {
76+
src: `https://www.google.com/s2/favicons?domain=${hostname}&size=16`,
77+
className: ['external-link-icon'],
78+
alt: '', // Decorative
79+
width: 16,
80+
height: 16,
81+
onerror: "this.parentNode.replaceChild(document.createTextNode('🌐'), this)"
82+
},
83+
children: []
84+
}
9485
}
9586

96-
const buffer = await response.arrayBuffer()
97-
const base64 = Buffer.from(buffer).toString('base64')
98-
const type = response.headers.get('content-type') || 'image/x-icon'
99-
const dataUri = `data:${type};base64,${base64}`
100-
101-
iconNode = {
102-
type: 'element',
103-
tagName: 'img',
104-
properties: {
105-
src: dataUri,
106-
className: ['external-link-icon'],
107-
alt: '', // Decorative
108-
width: 16,
109-
height: 16
110-
},
111-
children: []
87+
if (iconNode) {
88+
node.children.unshift(iconNode)
11289
}
11390
} catch (e) {
114-
// When timeout or other fetch error occurs
115-
iconNode = {
116-
type: 'element',
117-
tagName: 'span',
118-
properties: {
119-
className: ['external-link-icon']
120-
},
121-
children: [{ type: 'text', value: '🌐' }]
122-
}
123-
} finally {
124-
clearTimeout(timeout)
91+
// Ignore invalid URLs
12592
}
12693
}
127-
128-
if (iconNode) {
129-
node.children.unshift(iconNode)
130-
}
131-
})
132-
)
94+
}
95+
})
13396
}
13497
}

0 commit comments

Comments
 (0)