利用 Bun 内置 HTMLRewriter(基于 Cloudflare lol-html) 实现 HTML 过滤到纯文本
之前使用 happy-dom 经常出现 OOM 内存崩溃问题,改用了这个内置的组件。
当前版本(2025/03/18)代码实现如下,可以只取首行,限制最大字数。
export class HTMLText {
private static stop: number;
private static first: boolean;
private static value: string;
private static rewriter = new HTMLRewriter().on('*', {
element: e => {
if (this.stop == 2) { return; }
if (['p', 'br', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(e.tagName)) {
this.value += ' '
// 如果只取首行 且遇到换行符 则标记预备停止
if (this.first && !this.stop) {
this.stop = 1;
e.onEndTag(() => {
this.stop = 2;
})
}
}
},
text: t => {
if (this.stop == 2) { return; }
if (t.text) {
this.value += t.text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/ /g, " ")
.trim()
}
}
});
public static run(html: BodyInit | null, len: number) {
if (!html) { return '...' }
this.stop = 0;
this.value = '';
this.rewriter.transform(new Response(html)).text();
let text = this.value.trim();
if (len > 0) {
const lenOld = text.length
if (lenOld > len) {
text = text.slice(0, len - 3) + '...'
}
}
return text
}
// 取首行
public static one(html: BodyInit | null, len = 0) {
this.first = true;
return this.run(html, len)
}
// 取全文
public static all(html: BodyInit | null, len = 0) {
this.first = false;
return this.run(html, len)
}
}