11ty GraphQL Directives
Parallel page generation with Eleventy and GraphQL directives for building static sites with dynamic data from Shopify UCP Catalog and other sources.
Overview
Eleventy (11ty) is a powerful static site generator that can fetch data from GraphQL APIs at build time. This approach combines the performance benefits of static sites with the flexibility of dynamic data sources, making it ideal for e-commerce catalogs, product listings, and content-heavy applications.
Key Benefits
- โช Build-time Data Fetching: Query GraphQL APIs during the build process, generating static HTML pages with fresh data
- โช Parallel Processing: Generate multiple pages concurrently for improved build performance
- โช Type Safety: Leverage GraphQL's type system for predictable data structures
- โช SEO Optimization: All content is pre-rendered, ensuring excellent search engine visibility
Project Setup
Install the required dependencies for your 11ty project with GraphQL support.
# Create new 11ty project
mkdir my-11ty-site && cd my-11ty-site
npm init -y
# Install dependencies
npm install @11ty/eleventy dotenv node-fetch@2
# Create directory structure
mkdir -p src/_data src/_includes src/css
GraphQL Client Configuration
Create a GraphQL client module to handle API requests to Shopify or other GraphQL endpoints.
const fetch = require('node-fetch');
require('dotenv').config();
class GraphQLClient {
constructor(endpoint, headers = {}) {
this.endpoint = endpoint;
this.headers = {
'Content-Type': 'application/json',
...headers
};
}
async query(query, variables = {}) {
try {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({ query, variables })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.errors) {
console.error('GraphQL errors:', result.errors);
throw new Error(result.errors[0].message);
}
return result.data;
} catch (error) {
console.error('GraphQL query failed:', error);
throw error;
}
}
}
module.exports = GraphQLClient;
11ty Data Files
Create data files that fetch from GraphQL APIs at build time. These files export async functions that return data to your templates.
Fetch Products from Shopify
const GraphQLClient = require('./graphqlClient');
module.exports = async function() {
const client = new GraphQLClient(
process.env.SHOPIFY_STOREFRONT_URL,
{
'X-Shopify-Storefront-Access-Token': process.env.SHOPIFY_ACCESS_TOKEN
}
);
const query = `
query GetProducts($first: Int!) {
products(first: $first) {
edges {
node {
id
title
handle
description
priceRange {
minVariantPrice {
amount
currencyCode
}
}
images(first: 1) {
edges {
node {
url
altText
}
}
}
}
}
}
}
`;
try {
const data = await client.query(query, { first: 100 });
return data.products.edges.map(edge => edge.node);
} catch (error) {
console.error('Failed to fetch products:', error);
return [];
}
};
Parallel Page Generation
Use 11ty's pagination feature to generate individual pages for each product or collection item in parallel.
---
pagination:
data: products
size: 1
alias: product
permalink: "/products//"
---
<h1></h1>
<div class="product-detail">
<img src="" alt="">
<p></p>
<p class="price">
</p>
</div>
Build Process
How It Works
-
01.
11ty runs all data files in the
_datadirectory - 02. GraphQL queries are executed, fetching data from APIs
- 03. Data is cached and made available to all templates
- 04. Templates are processed in parallel, generating static HTML files
-
05.
Static site is output to the
_sitedirectory
Best Practices
Caching Strategy
Implement caching for GraphQL responses to reduce API calls during development. Use environment variables to control cache behavior in production vs. development.
Error Handling
Always implement robust error handling in data files. Return fallback data or empty arrays to prevent build failures when APIs are unavailable.
Incremental Builds
For large catalogs, consider implementing incremental builds that only regenerate pages for changed products. This significantly reduces build times.
Rate Limiting
Respect API rate limits by implementing request throttling and batching. Use GraphQL's ability to fetch multiple resources in a single query.