Replace Text & Images Using Edge Functions and HTMLRewriter
Transform HTML at request time using HTMLRewriter and Edge Functions. Update text, element attributes, and more.
Edge Functions (also referred to as cloud workers or edge compute) are a powerful way to modify requests to web content without modifying the source code or using client-side JavaScript.
Developers can use edge functions to manage a range of tasks, including:
- Auth and access control
- Proxying and rewriting content
- Personalization and customization
- Localization and translation
- Content transformation
- Custom headers
- Cookies
- and more
In this tutorial, we’ll take a look at how to transform an HTML response using HTMLRewriter in a Netlify Edge Function.
Jump to the end: source code | demo
1. Set up an HTML page
For this example we’ll work with a simple HTML page with a little bit of custom CSS to make it look nice.
Expand to see the full HTML and CSS used in this example
Create a folder for your project and place the HTML and CSS in a public
folder. The folder structure should look like this:
2. Set up local dev and deployment
To make it possible to develop and test Edge Functions locally — and deploy them to production once they’re running — create a netlify.toml
at the folder root and place the following inside:
Next, install the Netlify CLI if you don’t already have it:
Start the site locally by running the following command from your project root:
This will open http://localhost:8888
in your browser and display the HTML.
3. Create an Edge Function
Create your first Edge Function by adding a new file at netlify/edge-functions/pizza-to-tacos.js
. Once it’s created, the file tree should look like this:
Inside the Edge Function, let’s start by making sure it’s running as expected. Add the following code:
To turn this on, we need to modify our netlify.toml
with the following:
The path
tells Netlify what URL path should trigger an Edge Function, and the function
identifies which Edge Function should be triggered.
Restart your local dev server (ctrl
+ C
, then run ntl dev
again), then load the homepage and check the console output to see the log. This means our Edge Function is running.
4. Transform streaming text with an Edge Function
In order to keep responses fast, Edge Functions will stream responses, which means that the response is sent to the browser in chunks instead of waiting until the full document is processed.
This is great for performance, but it can be confusing for transformations because we can’t just run a find-and-replace — it’s possible that the text we’re searching for will be broken across chunks! For example, the sentence “A great big ol’ honkin’ donut.” may be sent in two chunks: “A great big ” and “ol’ honkin’ donut.” This means that if we were trying to replace “big ol’” in our text, a straightforward find-and-replace would fail.
Set up HTMLRewriter
To solve for this, we can use the HTMLRewriter
tool, which was originally created by the Cloudflare team and later ported for use with Deno and other open runtimes by Florian Klampfer.
Let’s implement the HTMLRewriter
in our Edge Function by replacing the contents of pizza-to-tacos.js
with the following:
It’s worth noting that the import is done using Deno-style, URL-based packages. This means we don’t need a package.json
or other installation step — it will Just Work™.
The Edge Function takes two arguments:
request
— a standards-basedRequest
object with information from the incoming requestcontext
— a collection of Netlify-specific helpers and data
To get the data that will be returned to the browser, we use the context.next()
helper. Next, we return a new instance of the HTMLRewriter
that calls the transform()
method on the response.
Write a transform for all text nodes
Transformation works by using an element selector (very similar to CSS selectors), then running a function against the matched elements.
To transform text, we’ll use the text
method, put each chunk of streamed text into a buffer, and wait until we reach the end of the text node before running our transform to ensure all text is properly transformed.
Add the following code to transform every instance of the word “pizza” to the word “TACOS”:
Calling text.remove()
prevents the text from streaming to the browser before it’s replaced. We can do this safely because we’re storing all the text into the buffer
variable.
Save the changes and reload your local page to see the transformation in action:
5. Transform element attributes in streaming HTML responses
Our transformation isn’t complete yet — we’re still showing photos of pizza despite updating the text to be about tacos.
To fix this, we’ll add an additional transform to select images. On each matched image, we’ll get the classes applied to each. If the classes contain either cheesy
or salty
as class names, we’ll transform the src
attribute for the element to use a different image and add matching alt
text.
Make the following changes to pizza-to-tacos.js
:
Save the changes, then reload the browser to see the images transformed:
6. Deploy to production
Now that we have a working Edge Function transforming our HTML, we can deploy it to production on Netlify.
To start, make sure you’re logged into your Netlify account in the CLI:
Next, create a new GitHub repository and push your local code to it. We’ll use the GitHub CLI for this example.
Once the repo is created and you’ve pushed up your code, initialize a new site with the Netlify CLI:
Create a new site, then link your new GitHub repository to it. It will start building immediately and will rebuild any time you push to GitHub.
To view the site, click the link from the CLI output, visit your Netlify dashboard, or run this CLI command:
Your site is deployed to production and the HTML is being transformed. 😎
To see this site running in production, check out the demo. You can also review the source code on GitHub.
Resources
- Learn With Jason episode on Edge Functions
- Netlify Edge Functions docs
- A deep dive into Edge Functions
- HTMLRewriter docs
Acknowledgments
Huge thanks to the Cloudflare team and Florian Klampfer for making HTMLRewriter available. Thanks to @harris
on the Cloudflare team for writing up an example of using HTMLRewriter on streaming responses. Also shout-out to Phil and Salma for creating a library of Edge Functions examples that made writing this so much easier.