Building the Expedia Group Open Source Site

Sharing the technology stack behind our new site

A person paddling on a surfboard
Photo by Ishan seefromthesky on Unsplash

At Expedia Group™️ we believe in Open Source, so we contribute to the community as much as we can.
Recently, we launched our new Open Source website! This site is our public window to the great work we do in this space: it promotes our projects, blog posts, tweets and careers.

As an engineer who helped implementing it, I think the technology stack we used can be very interesting for a wide audience, hence this post to share some of the knowledge I got from this nice experience. I’ll go through tech by tech in the following paragraphs.

Get repository info with GitHub GraphQL API

Over time, GraphQL has emerged as a way to efficiently query data. We also use it internally at Expedia Group for building presentation-layer APIs.

GitHub also provides their GraphQL API, which we used to get the information related to our public GitHub projects. Things like the repo’s description, image and url:

Example of repository card shown on the website with the component name, description and image
Example of repository card shown on the website

Our goal was to make a GraphQL query putting together the fields we needed, and GitHub provides a useful explorer exactly for that purpose. The power of GraphQL is that tools like this can help you with auto-completion as you type. We came up with this query:

where $owner and $name are query variables, respectively the GitHub organization which owns the repos ("ExpediaGroup") and the name of the repo. The response is something like this:

Once we had the query, we could build a Node.js script using the GraphQL Apollo Client so that the repositories’ info is saved as a static JSON file that is generated at build time. We made this choice to avoid tons of runtime GraphQL queries from each visitor’s browser. After all, this information does not change frequently, so we can afford rebuilding it on a daily basis.

Build a static site with Docusaurus

We used Docusaurus v2 to build the site. Docusaurus is a static site generator that also builds a single-page application using React.
Confused? Let’s try to explain.
In terms of how pages are built, there are three categories of sites:

  1. Static sites where the HTML is generated at build time with a static site generator
  2. Single page applications (SPA) with client-side rendering (the HTML is generated by JavaScript in the browser)
  3. Server side rendered (SSR) sites where the HTML is generated on page load on the server

Surprisingly enough, Docusaurus belongs both to category 1 and category 2. How can this work? Well, it’s a static site that turns into a SPA once loaded. It builds all the pages as static assets, but when you load one of these pages on the browser, React takes over and for all subsequent navigation you do, it’s handled as a SPA with client-side navigation. So you get both the benefits of a static site (SEO friendly: static pages can be indexed by search engines) and of a SPA (fast updates).

There are two kind of pages that you can create in Docusaurus: Markdown pages, which are a good fit for simpler use cases (e.g. documentation sites) and React pages (the one we chose), where you can use the full power of React. There is also MDX, a hybrid solution where you can use React within Markdown pages.

Docusaurus is quite commonly used in the open source world, but of course it is not the only game in town. Another popular generator is Jekyll, but the list is long.

Build pages with React

React is a famous JavaScript library for building user interfaces. It is getting wide adoption also within Expedia Group to implement part of the presentation layer.

The only React feature I will highlight in this blog post is its modularization in terms of components. A component is an abstraction of a reusable part of the UI and mixes together in the same file both its behavior and its markup. Let’s see a very simple example:

The above component has two input properties (name and surname), its simplistic behavior is to concatenate those into a full name, its markup is a single HTML <h1> header tag. How is it possible to have HTML so nicely embedded into JavaScript? It's actually not HTML, it's a syntax extension to JavaScript named JSX.

The last thing to mention is that while historically components in React where implemented as ES6 classes, nowadays there is a push to have function components like the above, especially with the advent of Hooks.

Add styling with CSS Modules

In the previous section I showed how React components nicely mix behavior with markup. What about the styling? Docusaurus has a few styling approaches available: the first one is the classic global CSS, where you put everything into a single CSS file, whose rules and class names are globally available to all components.

A more modern approach (the one we adopted) uses CSS Modules. With CSS modules, you have a CSS file for each component, all class names are scoped locally to that component (avoiding the clashes you may have with multiple global files defining the same class names). The CSS is usually like a normal one:

but then you import it in the component as if it was a normal Node.js dependency, and use its class names as fields of a JS object (usually named styles):

Automate build and deploy with GitHub Actions

GitHub Actions is a CI/CD engine directly integrated into your GitHub repository, which helps automate building, testing and deploying your code. It’s widely used in the open source world and we are also using it internally at Expedia Group.

In Actions, you define your workflows and put them under folder .github/workflows, like this one we use for pull request builds:

A workflow is a sequence of jobs that runs when a certain event happens. In the above example, the event is the creation of a pull request targeted to the main branch.

Each job is made of multiple steps, that can either use already available actions, or specify an inline shell script to run. In the previous example, the job first checks out the repo (git checkout) in the runner’s local file system, then it installs Node.js in the runner, finally it runs some node commands to build the site.

A summary of all the workflows that ran, together with their logs, is available under the Actions tab.

Deliver the site with GitHub Pages

Once we have a site nicely rendering on our local machine, built as a bunch of static assets (HTML, CSS, JS, images, etc) by Docusaurus, how do we deliver it to the public? That’s when GitHub Pages comes into play.
Pages is a free static site hosting provided by GitHub: you can have a site not only for your GitHub account, but also for your organization or for each of your projects. In our case, we built the site for the ExpediaGroup organization, so following the naming convention for organization sites the repository is named expediagroup.github.io.

The control panel under Settings > Pages is pretty straightforward:

GitHub Pages settings to select which branch, folder and custom domain to use, with green confirmation box that the site is published to https://opensource.expediagroup.com
GitHub Pages Control Panel

In our case, it is configured to pick up the static assets from the root path of the special gh-pages branch. As soon as you commit something new there, Pages will detect it and redeploy it live, usually within a few minutes.

Moreover, we configured a custom domain which makes it possible to visit the site at the prettier https://opensource.expediagroup.com instead of the basic https://expediagroup.github.io .

Wrapping Up

I’ve come to the conclusion of this blog post, I hope you found some useful information. In general, I think this simple but comprehensive technology stack can serve a wide variety of use cases.

Thanks for reading and don’t forget to check out our Open Source website!



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store