Building the Expedia Group Open Source Site
Sharing the technology stack behind our new site
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.
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:
$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:
- Static sites where the HTML is generated at build time with a static site generator
- 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.
Build pages with React
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 (
surname), its simplistic behavior is to concatenate those into a full name, its markup is a single HTML
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
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:
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.
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!