Add Grid-aware Websites to an existing site with Netlify Edge Functions

Overview

Using Grid-aware Websites with Netlify Edge Functions allows you to add grid awareness to an existing website that is hosted on, or proxied through, Cloudflare's network.

In this tutorial, you will learn how to:

  • Create a new Netlify Edge Functions project
  • Add Grid-aware Websites to the Netlify Edge Function
  • Use the HTMLRewriter API to make a change to the page
  • Publish the Netlify Edge Function to target a specific route on your website

Before starting

You should have:

You should also be aware of the limits and pricing of Netlify Edge Functions, available on the Cloudflare website.

Adding edge functions to a Netlify project

To begin using Grid-aware Websites on an existing website through Netlify Edge Functions, we will first need to add them to a Netlify project. To do this, you can create a netlify/edge-functions folder at the root of your project. The Netlify docs have instructions if you want to save your edge functions in a different location.

Within the netlify/edge-functions folder, let's create our edge function file. For this demo, we'll call it gaw.js.

The netlify/edge-functions/gaw.js file will contain the code the runs whenever our function is invoked.

Configuring our edge function

We can declare the configuration for our edge function from inside the gaw.js file we've just created. To do this, add the following code to the file:

export const config = {
  path: "/*",
  onError: "bypass"
}

Here, we have configured the edge function to run on every route of our site. We've also configured the edge function to be skipped in the event that an error is encountered.

The Netlify docs have more information about all the available configuration options for edge functions.

Adding the Electricity Maps API

Later in the project, we'll use the Electricity Maps API to get information about the power breakdown of a country's energy grid. For this, you'll need an Electricity Maps API key added to your project. We'll first set this up for our development environment, and later in this tutorial we'll set it up for production.

There are a few ways to add environment variables to a Netlify project. We'll use a local .env file, and import it using the Netlify CLI. First, create a .env file in the root of your project if you don't have one already. Add your Electricity Maps API key as follows:

EMAPS_API_KEY="<your_api_key>"

Then, use Netlify CLI to upload the contents of your .env file to your project.

npx netlify env:import .env

Adding Grid-aware Websites to the Edge Function

We can now start coding. To begin, we'll add the Netlify Edge Functions specific plugin for Grid-aware Websites to our gaw.js edge function. To do this, add the following code to the gaw.js file.

import gridAwareAuto from "https://esm.sh/@greenweb/gaw-plugin-netlify-edge@next";

export default async (request, context) => {
  return gridAwareAuto(request, context);
};

This code uses the gridAwareAuto helper function to take care of setting up and executing the Grid-aware Websites code. We can deploy this code as it is, and it would run in our project. However, when applying Grid-aware Websites to a project you will probably want to configure the grid aware code a bit more.

Further grid-aware configuration

The gridAwareAuto function accepts an options object as the third parameter. This allows for some configuration to be made to the implementation. Accepted options values are:

Configuration Options for Grid-Aware Websites
Option Type Required Default Possible values Description
gawDataApiKey String Required '' "xyz123" API key for the Electricity Maps
locationType String Optional 'latlon' "latlon", "country" Type of location data to use
contentType String[] Optional ['text/html'] Example: ['text/html', 'text/css'] Defines the content types that should be processed
ignoreRoutes String[] Optional [] Example: ['/wp-admin', '/assets/js'] A list of routes where grid-aware code should not be applied
ignoreGawCookie String Optional 'gaw-ignore' "gaw-ignore" A cookie that when present will result in grid-aware code being skipped
userOptIn Boolean Optional false true, false Allows developers to specify if users are required to opt-in to the grid-aware website experience
htmlChanges Object Optional {} {"low": HTMLRewriter, "moderate": HTMLRewriter, "high": HTMLRewriter} An object to capture the different HTML changes that are applied at each different grid intesity level
htmlChanges.low HTMLRewriter Optional null Custom HTMLRewriter for page modification at low grid intensity level
htmlChanges.moderate HTMLRewriter Optional null Custom HTMLRewriter for page modification at moderate grid intensity level
htmlChanges.high HTMLRewriter Optional null Custom HTMLRewriter for page modification at high grid intensity level
infoBar Object Optional {} {target: "", version: "latest", learnMoreLink: "#", popoverText: "", customViews: ""} Configuration for the info bar element
infoBar.target String Optional '' Example: "header", "#info-container" Target element for the info bar
infoBar.version String Optional 'latest' "latest", "1.0.0" Version of the info bar to use
infoBar.learnMoreLink String Optional '#' Example: "https://example.com/learn-more" Link to learn more about the info bar
infoBar.popoverText String Optional '' Example: "This website adapts based on carbon intensity" Provide a custom string of text to be used in the info bar popover element
infoBar.customViews String Optional '' Example: "custom-low,custom-moderate,custom-high" Custom views for the grid-aware website experience
defaultView String/null Optional null null, "low", "moderate", "high" Default view for the grid-aware website experience
dev Boolean Optional false true, false Whether to enable development mode
devConfig Object Optional {} {hostname: "", port: "", protocol: ""} Configuration for development mode
devConfig.hostname String Optional '' Example: "localhost" Hostname for development mode
devConfig.port String Optional '' Example: "8080" Port for development mode
devConfig.protocol String Optional '' Example: "http" Protocol for development mode
debug String Optional "none" "none", "full", "headers", "logs" Activates debug mode which outputs logs and returns additional response headers

In this tutorial, we want to make a change to the page which will be applied when the grid-aware checks return a result that indicate the grid is dirtier than normal. The gridAwareAuto function will perform these checks for us, so we can use the htmlChanges option to pass it the changes we want applied.

In the example below we will:

  • Set out edge functions to ignore certain routes in our project.
  • Add our Electricity Maps API key.
  • Set debug to "full" so that we see logs in our console and browser.
  • Add the data-grid-aware="true" to the <html> tag when the Electricity Maps API returns a "high" result.

To do this, we'll also need to import the HTMLRewriter tool into our project.

import gridAwareAuto from "https://esm.sh/@greenweb/gaw-plugin-netlify-edge@next";
import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter/index.ts";

export default async (request, context) => {
    return gridAwareAuto(request, context, {
      // Ignore these routes
      ignoreRoutes: ["/company/", "/profile/"],
      // Use this API key that has been saved as a secret
      gawDataApiKey: env.EMAPS_API_KEY,
      debug: "full",
      // Make these changes to the web page using HTMLRewriter when the grid intensity is high.
      // All other states (low, moderate) will return the page as normal - no changes applied.
      htmlChanges: {
        high: new HTMLRewriter().on("html", {
          element(element) {
            element.setAttribute("data-grid-aware", "true");
          },
        }),
      },
    });
};

Testing the code

We can now do a first test of our code to ensure it works as expected before moving on. In your terminal, run the command below:

npx netlify dev

This command will use the Netlify CLI to run a version of your project in the development environment.

When the CLI runs, a browser window should open automatically showing your project. In your terminal, you should see log outputs including information about the grid data that has been used to make perform the grid-aware checks.

In order to test that the changes you have made are working, you'll need some way to test your Edge Function from different locations around the World. Unfortunately, the ability to mock geolocation using the Netlify CLI does not work when used with the Grid-aware Websites code. You can, instead, resort to one or more of the following workarounds:

  1. Use a VPN service to test a few locations
  2. Manually set a fixed value for the country variable, and adjust that to test different locations
  3. Share your code with a colleague in another location and have them test it
  4. Test in production. YOLO. (this suggestion is made in jest, we do not recommend it.)

Deploying to production

When you're ready, you can deploy your worker to run on your website for the actual path you've configured.

Now, you can run npx netlify deploy in your terminal to deploy your Netlify site and edge fuction to production.

Share your grid-aware website

If you've deployed Grid-aware Websites to your own site we'd love to hear from you! Share your experience with us using the contact form via our website.