Recap of Part one
In part 1 of our blog series, "Building a JAMStack App with CloudFlare Workers and AthenaHealth APIs," we focused on creating a simple JAMStack application that fetches and caches data from the AthenaHealth API using CloudFlare Workers. We developed the app to include paths for fetching department and provider information, demonstrating the seamless integration between CloudFlare Workers and AthenaHealth APIs to deliver an efficient and scalable JAMStack application.
We developed a CloudFlare Worker that fetches and serves a list of healthcare providers from the AthenaHealth API, which can be accessed at https://jamstack.perisicdesigns.workers.dev/providers. As we progress to the next stage, our objective is to create an engaging, simple and user-friendly interface for patients to view this information. To achieve this, we will utilize CloudFlare Pages, a powerful JAMStack solution, in combination with Eleventy.js, a static site generator. This approach enables us to build a fast, secure, and easily maintainable website, while also enhancing the user experience. By leveraging the capabilities of CloudFlare Pages and Eleventy.js, we will bring the data retrieved by our CloudFlare Worker to life and deliver a seamless, responsive experience for patients accessing the list of providers.
Environment Set-up
To publish a website to CloudFlare Pages using Eleventy and GitHub, there are several essential
steps you must follow to prepare the environment. First, ensure that Node.js (v14 or newer) and
npm (Node Package Manager) are installed on your local machine, as Eleventy depends on these tools.
You can verify the installation by running node -v
and npm -v
.
INext, create a new GitHub repository to host your project's source code. Then, install Eleventy.js
globally on your system using npm install -g @11ty/eleventy
. After that, initiate
a new Eleventy project within your GitHub repository by running the appropriate commands:
mkdir your-project-name
cd your-project-name
npm init -y
npm install --save-dev @11ty/eleventy
Finally, set up the file structure for the project and create the initial files. You can refer to this GitHub repository for an example of the necessary setup: https://github.com/stevoPerisic/jamstack-pages-athenaHealth .
Files Breakdown
Here is a brief explanation of waht each file does:
-
The _includes/base.njk file is a Nunjucks template that forms the foundation of our website. It provides the core HTML structure, which comprises the head and body sections, and ensures that the Bootstrap CSS and JavaScript files are properly linked. The
{{ content | safe }}
line acts as a versatile placeholder, allowing content from other templates to be seamlessly integrated into the overall layout. This base template enables a consistent design and structure throughout the website while still allowing for the flexibility to accommodate diverse content. -
The two CSS files, theme.css and hs-mega-menu.min.css, serve distinct purposes within the website. The theme.css file contains the overall styling for the website, ensuring that its visual elements are consistent and appealing. On the other hand, hs-mega-menu.min.css focuses specifically on the menu's styling, providing a polished and functional navigation experience for users. Both of these files are linked within the _includes/base.njk file, ensuring they are properly loaded and applied throughout the site.
-
Next we have the _data/providers.js file. It is essentially a JavaScript module that fetches a list of providers from an API endpoint and assigns random headshots to each provider using the randomuser.me API. It starts by importing the cross-fetch library to enable fetch in both browser and node environments. The getRandomHeadshot function is defined to fetch random user data, including headshots, from the randomuser.me API and return an array of headshot URLs. The main function fetches a list of providers, filters them to only include providers of type "Person," and calls the getRandomHeadshot function to obtain headshots for the filtered providers. Finally, it creates a new array of provider objects with an added headshotUrl property and returns the array as the module's output.
const fetch = require('cross-fetch'); async function getRandomHeadshot(num) { const response = await fetch(`https://randomuser.me/api/?results=${num}`); const data = await response.json(); const headshots = data.results.map(user => user.picture.large); return headshots; } module.exports = async function () { const response = await fetch("https://jamstack.perisicdesigns.workers.dev/providers"); const data = await response.json(); const providers = data.providers.filter(provider => provider.entitytype === "Person"); const headshots = await getRandomHeadshot(providers.length); const providersWithHeadshots = providers.map((provider, index) => { return { ...provider, headshotUrl: headshots[index % headshots.length], }; }); return providersWithHeadshots; };
-
The _eleventy.js configuration file plays a crucial role in customizing the Eleventy build process for our specific needs. In this snippet, the
eleventyConfig.addPassthroughCopy()
function is used twice to ensure that the 'css' and 'js' directories are copied directly into the output folder during the build process, without any modifications. This allows for static assets, such as stylesheets and JavaScript files, to be served correctly when the site is live. The 'return' statement defines the configuration object, specifying the input directory as '.', which is the root directory containing the Eleventy files. It also sets the 'includes' directory to '_includes', the location where template files like 'base.njk' are stored. This configuration ensures that Eleventy knows where to find the necessary files and directories during the build process, allowing for a smooth and efficient development experience.module.exports = function (eleventyConfig) { eleventyConfig.addPassthroughCopy("css"); eleventyConfig.addPassthroughCopy("js"); return { dir: { input: ".", // The root directory for your Eleventy files includes: "_includes", // The directory where your includes (like 'base.njk') are located // ... other configuration properties }, }; };
-
The code snippet below is from the index.njk file which is an Eleventy template file that defines the structure and content for the "Providers" page of the website. It begins with front matter that specifies the base layout as 'base.njk' and sets the page title to "Providers".
Within the HTML, a container and row classes are used to establish a responsive grid layout. The 'title' variable, set in the front matter, is displayed as an 'h2' heading. The main content of the page consists of a loop that iterates through each 'provider' object in the 'providers' array.
For each provider, a column is created containing an image with the provider's headshot, their first and last name as an 'h5' heading, their provider type, and a link to the provider's details page. The loop ends after all providers have been processed, and the resulting layout will display a responsive grid of provider cards with relevant information and links to individual provider pages.
--- layout: base.njk title: Providers --- <div class="container"> <div class="row"> <!-- Team --> <div class="container content-space-1"> <!-- Heading --> <div class="w-lg-65 text-center mx-lg-auto mb-5 mb-sm-7 mb-lg-10"> <h2>{{ title }}</h2> </div> <!-- End Heading --> <div class="row row-cols-1 row-cols-sm-2 row-cols-lg-3"> {% for provider in providers %} <div class="col mb-10"> <!-- Team --> <div class="w-sm-65 text-center mx-auto"> <img class="img-fluid rounded-3 mb-4" src="{{ provider.headshotUrl }}" alt="{{ provider.firstname }} {{ provider.lastname }}"> <h5 class="mb-1">{{ provider.firstname }} {{ provider.lastname }}</h5> <span class="d-block">{{ provider.providertype }}</span> <span class="d-block"> <a href="/provider/{{ provider.providerid }}">View Details</a> </span> </div> <!-- End Team --> </div> <!-- End Col --> {% endfor %} </div> </div> </div> </div>
-
Lastly we have the provider.njk template file that displays the details of a specific healthcare provider. It uses the base layout defined in the base.njk file and sets the title as "Provider Details." The file also utilizes Eleventy's pagination feature to generate individual pages for each provider.
The pagination configuration in the front matter specifies the providers data collection as the data source, sets the page size to 1 to create a separate page for each provider, and assigns the current provider data to an alias named provider. The permalink configuration generates a unique URL for each provider page based on their providerid.
Inside the main content area, the template uses the Bootstrap framework to create a responsive layout displaying the provider's profile. The profile includes the provider's headshot, name, and provider type. A sample description text (Lorem ipsum) is added as a placeholder for any additional information about the provider. At the bottom, a "Follow" button is included, which can be customized to implement a follow functionality.
The template employs Eleventy's Nunjucks templating engine to output dynamic content using double curly braces, such as
{{ provider.headshotUrl }}
,{{ provider.firstname }}
, and{{ provider.lastname }}
. This allows the template to be rendered with the specific data for each provider, resulting in personalized pages for every individual in the providers data collection.--- layout: base.njk title: Provider Details pagination: data: providers size: 1 alias: provider permalink: /provider/{{ provider.providerid }}/ -- <!-- User Profile --> <div class="container content-space-1"> <div class="row justify-content-md-center"> <div class="col-md-8"> <div class="text-center"> <img class="avatar avatar-xxl avatar-circle mb-3" src="{{ provider.headshotUrl }}" alt="{{ provider.firstname }} {{ provider.lastname }}"> <div class="mb-4"> <h3>{{ provider.firstname }} {{ provider.lastname }}</h3> <span class="d-block mb-1">{{ provider.providertype }}</span> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ornare turpis quis dui accumsan, sit amet vehicula velit blandit. Nam porttitor dolor a nulla pulvinar, vitae commodo quam luctus. Suspendisse potenti. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras ac mollis est. Sed accumsan ante sed pharetra facilisis. Curabitur porttitor risus consectetur faucibus egestas. </p> </div> <button type="button" class="btn btn-outline-primary btn-sm"> <i class="bi-person-plus-fill me-1"></i> Follow </button> </div> </div> <!-- End Col --> </div> <!-- End Row --> </div> <!-- End User Profile -->
The .gitignore file update
The .gitignore file is a configuration file used by Git to determine which files and directories should not be tracked by the version control system. In other words, the files and directories listed in the .gitignore file will be ignored when committing changes to the Git repository.
In the case of an Eleventy project, the generated site files are typically placed in a folder named _site by default. These files are the result of Eleventy processing your templates and data, and they represent the static output of your website. Since these files are generated automatically during the build process, there's no need to track them in the Git repository. Tracking the generated files could lead to unnecessary conflicts and clutter in the version control history.
By adding _site (or the appropriate folder name) to the .gitignore file, you ensure that the generated site files are not tracked by Git, keeping your repository clean and focused on the source files required to build your Eleventy project. This also prevents any potential issues when deploying the site using services like CloudFlare Pages, as these services will build and deploy the site from the source files in the Git repository.
Deploying to CloudFlare Pages
With our project set up, we can proceed to deploy it to CloudFlare Pages. First, push your project to a new GitHub repository. Next, sign in to your CloudFlare account and navigate to the CloudFlare Pages dashboard. Click "Create a project" and select the GitHub repository you just pushed. To configure the build settings, set the build command to eleventy and the build output directory to _site. Then, click "Begin setup" followed by "Save and deploy". CloudFlare Pages will build and deploy your site, and once the deployment is complete, you can visit your site using the provided URL. In our case we have the result deployed to https://jamstack-pages-athenahealth.pages.dev/
In this comprehensive tutorial, we began by building a JAMstack application using Cloudflare Workers and AthenaHealth APIs. The app fetches data from the Departments and Providers APIs and displays a JSON data response using separate paths in the worker. With this foundation in place, we continued to use the JAMStack approach to create an appealing User Interface, displaying our data in a more attractive way for our users..
Furthermore, we guided you through the process of creating JAMStack pages using CloudFlare Pages, Eleventy.js, and Bootstrap 5. We demonstrated how to set up the project environment, configure Eleventy, create the necessary files, and deploy the website to CloudFlare Pages. By following these steps, you can create your own JAMStack website and leverage the benefits of modern web development technologies for faster, more secure, and scalable web applications. This tutorial provides a solid foundation for you to build upon, allowing you to create engaging and efficient web applications with ease.