I’ve been playing with HTMLRewriter recently and am loving the flexibility of it, however have run into a limitation that I’m not entirely sure how to solve, or if I’m just missing something with the API.
My use-case is proxying my blog from another domain, and essentially rewriting all content, HTML attributes, link/meta tags etc. from one domain to another. Up until this point, I’ve just had the entire payload in memory, replaced with regex, and then served it back in one go. That works just fine, but if I can make these changes faster, more efficient and not affect TTFB… that’s very cool.
With text nodes, does .replace
replace only that individual chunk of text? I guess it would make sense if so, but then, how can I manipulate the content of elements like <div>HELLO replace.example.com</div>
, read the contents, and make replacements if necessary, with any degree of reliability with the text chunking?
For a very stripped down code example, I currently have this:
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
class elementHandler{
element(){
// reset nextText for chunking
this.nextText = '';
}
text(text){
// append to nextText for chunking
this.nextText += text.text;
if(text.lastInTextNode){
// this is the last bit of text in the chunk. Check and replace as necessary
if(this.nextText.includes('replace.example.com')){
text.replace(this.nextText.replace(/replace.example.com/g, 'some.other.domain.com'));
}
}
}
}
async function handleRequest(request){
const response = new Response(`<div>HELLO replace.example.com <span>nope.example.com</span></div>`);
const rewriter = new HTMLRewriter();
rewriter.on('*', new elementHandler());
return rewriter.transform(response);
}
As you can see, I’m essentially just trying to replace all occurrences of replace.example.com
with some.other.domain.com
.
I would expect this to produce:
<div>HELLO some.other.domain.com <span>nope.example.com</span></div>
But instead, it actually produces:
<div>HELLO replace.example.com HELLO some.other.domain.com <span>nope.example.com</span></div>