title |
---|
Porting an HTML Site to Gatsby |
When introducing Gatsby into an existing static HTML site, it may or may not be feasible to rewrite the entire site at once. It's possible to port pieces of a site to Gatsby one at a time, while the rest of the site still uses HTML, might be preferable. This page will guide you through this process.
Note: The aim of this guide is to take a shallow, focused path to porting part of a static HTML website to Gatsby. The full Gatsby tutorial is more broad, with deeper dives on the core concepts and technologies.
There are a few particularly helpful Gatsby features for porting HTML websites:
- Defining the blocks that make up your site as reusable components that can take inputs.
- Options to accomodate serving your website at a path, such as
/docs
, and hosting your assets at a seperate domain. - An open and ongoing conversation to join, with our vibrant community of contributors. Over 2500 people have worked on Gatsby and its wealth of documentation to date.
- A modular system to lift the content out of your code and into files or external services, when the time is right.
We're proud of the Gatsby core philosophy, it sets out the overall vision, and philosophy on tooling and community. In short, as a member of the community, You belong here!
Here is the structure of an example static HTML/CSS website that this guide will walk through:
website-domain
├── assets
│ ├── favicon.ico
│ ├── person.png
│ ├── normalize.css
│ └── style.css
├── index.html
├── 404.html
├── about.html
├── contact.html
├── services
│ ├── index.html
│ ├── growing.html
│ ├── cleaning.html
│ └── shrinking.html
└── who
├── index.html
├── ellla-arborist.html
├── marin-leafer.html
└── sam-surgeon.html
The /who
section of the site is a great candidate for porting as it is all within a single folder. Through this guide, you will develop the ported Gatsby section in isolation before integrating into the site by telling Gatsby about the hosting path, /who
.
The example site uses global CSS files (style.css
and normalize.css
); more sophisticated styling structures like Sass architectures or CSS-in-JS can be accommodated but will not be covered here.
No client-side JavaScript (e.g jQuery etc.) is on the example site. If your site includes client-side JavaScript libraries and functionality, Gatsby may conflict with it if not handled or removed when porting. Learn more about Debugging HTML Builds.
Gatsby generates websites and web applications for production through a compilation and build process, and it also has tools optimized for local development. To set up the Gatsby CLI and development environment (if you haven't already) check out Part Zero of the Gatsby tutorial.
Now that you are set up, you can use the Gatsby and npm CLI tools in your terminal to get this site section ported! Make a new project using the Gatsby hello world starter with the following command:
gatsby new gatsby-site-section https://github.com/gatsbyjs/gatsby-starter-hello-world
You should now have a folder called gatsby-site-section
containing a basic Gatsby website. Open the new folder in your code editor and cd
(change directory) into the folder in your terminal to continue:
cd gatsby-site-section
The /src
folder contains most of the front-end code for the Gatsby site. In the Gatsby build process, every component file in the /src/pages
folder will automatically create an HTML page. Currently, the only page created is from the index page component in /src/pages/index.js
:
import React from "react"
export default () => <div>Hello world!</div>
Run the development server with gatsby develop
in the command line to see the website in your browser.
gatsby develop
You can now visit the page running in your browser at http://localhost:8000
. Hello Gatsby! 👋
Here is /who/index.html
from the example site structure above:
<html lang="en">
<head>
<title>Taylor's Tidy Trees - Who We Are</title>
<link href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="/assets/normalize.css" />
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
</head>
<body>
<header>
<a href="/" class="brand-color logo-text">Taylor's Tidy Trees</a>
<nav>
<ul>
<li><a href="/about.html">About</a></li>
<li><a href="/services/index.html">Services</a></li>
<li><a href="/index.html">Who We Are</a></li>
<li><a href="/contact.html">Contact</a></li>
</ul>
</nav>
</header>
<main>
<h1>Who We Are</h1>
<h2>These are our staff:</h2>
<ul>
<li><a href="/who/ella-arborist.html">Ella (Arborist)</a></li>
<li><a href="/who/sam-surgeon.html">Sam (Tree Surgeon)</a></li>
<li><a href="/who/marin-leafer.html">Marin (Leafer)</a></li>
</ul>
</main>
</body>
</html>
In the following sections, you'll convert this block of HTML into its equivalent code in Gatsby.
You might have noticed that the component in /src/pages/index.js
doesn't include <html>
, <head>
or <body>
. Gatsby makes a default HTML structure for each page and places the output from /src/pages/index.js
into its body. More <head>
child elements and HTML attributes are added to the output page with a module called React Helmet. React Helmet is added to a Gatsby project in the command line with npm and then to the Gatsby config file:
npm install --save react-helmet gatsby-plugin-react-helmet
Gatsby projects have a config file at /gatsby-config.js
where site metadata and options can be specified and plugins added. Add a plugin line with gatsby-plugin-react-helmet
to your config file:
/**
* Configure your Gatsby site with this file.
*
* See: https://www.gatsbyjs.org/docs/gatsby-config/
*/
module.exports = {
plugins: ["gatsby-plugin-react-helmet"], // highlight-line
}
Now you can import the <Helmet>
component to the index.js
file and place <header>
& <main>
elements for the existing HTML. Gatsby components must have a single root parent in their code structure so one technique is to add a React Fragment component around them:
import React from "react"
import Helmet from "react-helmet"
export default () => (
<>
<Helmet></Helmet>
<header></header>
<main>
<div>Hello world!</div>
</main>
</>
)
Note the mix of components and native HTML elements in the React markup here: this is the JSX templating language, which Gatsby compiles into HTML that browsers can parse and render to users. Further sections of this guide will explain it even more.
Copy in the contents of each of the 3 sections from the /who/index.html
file above:
import React from "react"
import Helmet from "react-helmet"
export default () => (
<>
<Helmet>
{/* highlight-start */}
<title>Taylor's Tidy Trees - Who We Are</title>
<link
href="/assets/favicon.ico"
rel="shortcut icon"
type="image/x-icon"
/>
<link rel="stylesheet" type="text/css" href="/assets/normalize.css" />
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
{/* highlight-end */}
</Helmet>
<header>
{/* highlight-start */}
<a href="/" className="brand-color logo-text">
Taylor's Tidy Trees
</a>
<nav>
<ul>
<li>
<a href="/about.html">About</a>
</li>
<li>
<a href="/services/index.html">Services</a>
</li>
<li>
<a href="/index.html">Who We Are</a>
</li>
<li>
<a href="/contact.html">Contact</a>
</li>
</ul>
</nav>
{/* highlight-end */}
</header>
<main>
{/* highlight-start */}
<h1>Who We Are</h1>
<h2>These are our staff:</h2>
<ul>
<li>
<a href="/who/ella-arborist.html">Ella (Arborist)</a>
</li>
<li>
<a href="/who/sam-surgeon.html">Sam (Tree Surgeon)</a>
</li>
<li>
<a href="/who/marin-leafer.html">Marin (Leafer)</a>
</li>
</ul>
{/* highlight-end */}
</main>
</>
)
Opening the site in a browser again at http://localhost:8000
, you should have a functional website! Next, this guide will explore how HTML and JavaScript combine in a Gatsby application.
The code for Gatsby pages looks like a hybrid of JavaScript and HTML. The code for each page is typically a JavaScript function describing a block of HTML given a set of inputs, or "props". Gatsby runs each page's JavaScript function during the build process to produce a static HTML file.
The appearance of a Gatsby component depends on how dynamic the content and behavior is. The code for a very static page will include mostly all HTML markup wrapped in a bit of JavaScript for Gatsby to assemble. The code for a component with props (a.k.a. "inputs"), and logic applied to those props, will interweave more JavaScript through JSX: examples could include data sourced with GraphQL or imported from a file to produce dynamic markup, such as a list of related links.
This guide will stay on the HTML side of the balance to suit a more static site. Using Gatsby to arrange the necessary client-side JavaScript with React early can open many future possibilities though. While Gatsby produces static pages from your components, it can also deliver dynamic client-side JavaScript after the page loads and the site hydrates into a full React web application.
Your pasted HTML in /gatsby-site-section/src/pages/index.js
needs a small change to be valid: class
attributes must be renamed to className
for usage with React, as class
is a reserved word in JavaScript.
There are 3 pages in the /who
section of Taylor's Tidy Trees for members of the team. Here is the one for Ella:
<html lang="en">
<head>
<title>Taylor's Tidy Trees - Who We Are - Ella</title>
<link href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="/assets/normalize.css" />
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
</head>
<body>
<header>
<a href="/" class="brand-color logo-text">Taylor's Tidy Trees</a>
<nav>
<ul>
<li><a href="/about.html">About</a></li>
<li><a href="/services/index.html">Services</a></li>
<li><a href="/who/index.html">Who We Are</a></li>
<li><a href="/contact.html">Contact</a></li>
</ul>
</nav>
</header>
<main>
<h1>Ella - Arborist</h1>
<h2>Ella is an excellent Arborist. We guarantee it.</h2>
<div class="bio-card">
<img
alt="Comically crude stick person sketch"
src="/assets/person.png"
/>
<p>Ella</p>
</div>
</main>
</body>
</html>
The foundational building block for building and styling pages in Gatsby is the <Layout>
component. The <Layout>
component wraps around page content, providing the common structure that appears on all pages. Looking at the /index.html
and /who/ella-arborist.html
you can see that most of the page is identical. Other than the title of the page, everything except for the contents of the main block is repeated.
Create a folder inside /src
, next to /src/pages
called components
. Inside components
make a file called Layout.js
. Here is a basic structure to use for the file:
import React from "react"
import Helmet from "react-helmet"
export default ({ children }) => (
<>
<Helmet></Helmet>
<header></header>
<main>{children}</main>
</>
)
Like in /src/pages/index.js
the file exports a JavaScript function that returns an HTML-like JSX structure, but this time the function takes an argument. The first argument provided to a component function is always an object for the props. On the props object, the children of the component are available to be passed in. Within the JSX markup, the curly braces wrap a JavaScript expression whose result will be placed there. In this case it is an expression that results in the contents of the children
variable.
The common elements from the /index.html
and /who/ella-arborist.html
files can now copied into the <Layout>
component. A second prop is also added and used in a second JavaScript expression in the <title>
element. The added expression results in the title with the staffName
prop added conditionally if it is provided. You'll see the prop used again later on when porting the /who/ella-arborist.html
page.
import React from "react"
import Helmet from "react-helmet"
import { Link } from "gatsby"
export default ({ children, staffName }) => (
<>
<Helmet>
<title>
Taylor's Tidy Trees - Who We Are{staffName ? ` - ${staffName}` : ""}
</title>
<link
href="/assets/favicon.ico"
rel="shortcut icon"
type="image/x-icon"
/>
<link rel="stylesheet" type="text/css" href="/assets/normalize.css" />
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
</Helmet>
<header>
<a href="/" className="brand-color logo-text">
Taylor's Tidy Trees
</a>
<nav>
<ul>
<li>
<a href="/about.html">About</a>
</li>
<li>
<a href="/services/index.html">Services</a>
</li>
<li>
<Link to="/">Who We Are</Link>
</li>
<li>
<a href="/contact.html">Contact</a>
</li>
</ul>
</nav>
</header>
<main>{children}</main>
</>
)
The next step is to use that <Layout>
component in the index.js
page file. Gatsby itself provides a number of core building blocks: <Link>
is one of them. The <Link>
component is imported at the top of the file to use in place of <a>
tags for on-site links, with a to
prop instead of the href
attribute. When the site builds, <Link>
produces native HTML anchors with added performance optimizations like prefetching page content before a user activates a link.
import React from "react"
import Layout from "../components/Layout"
import { Link } from "gatsby"
export default () => (
<Layout>
<h1>Who We Are</h1>
<h2>These are our staff:</h2>
<ul>
<li>
<Link to="/ella-arborist">Ella (Arborist)</Link>
</li>
<li>
<Link to="/sam-surgeon">Sam (Tree Surgeon)</Link>
</li>
<li>
<Link to="/marin-leafer">Marin (Leafer)</Link>
</li>
</ul>
</Layout>
)
Now it's time for the work to really pay off! Ella's page is a matter of using your <Layout>
component again and copying in the main content. Don't forget to change class
to className
! A staffName
prop can be passed to <Layout>
this time to change the dynamic page title. Passing props is similar to an attribute on an HTML element:
import React from "react"
import Layout from "../components/Layout"
import { Link } from "gatsby"
export default () => (
{/* highlight-start */}
<Layout staffName="Ella">
{/* highlight-end */}
<h1>Ella - Arborist</h1>
<h2>Ella is an excellent Arborist. We guarantee it.</h2>
<div className="bio-card">
<img
alt="Comically crude stick person sketch"
src="/assets/person.png"
/>
<p>Ella</p>
</div>
</Layout>
)
The other 2 pages for Marin and Sam can now be made with a similar structure. Maybe you are even thinking about another component for the Bio Card!
With your new Gatsby application taking shape, it's time to integrate it into your existing HTML website. If you were to build the Gatsby application into static files now and upload them in the place of the existing HTML files, the paths of the links made by Gatsby would not be correct. There are a couple of Gatsby configuration options to fix this.
The pathPrefix
option in /gatsby-config.js
tells Gatsby the path at which the build output will be served from. For example, links to other pages within your Gatsby site will be prefixed with the pathPrefix
value. Here is some config code to tell Gatsby it should only handle and care about the /who
path for now:
module.exports = {
plugins: [`gatsby-plugin-react-helmet`],
pathPrefix: `/who`, // highlight-line
}
Note: If you want to host non-HTML resources on a dedicated CDN, Gatsby can accomodate this with the Asset Prefix option.
You now have a site that mirrors the existing HTML site section. Stop the development server if it's still running; it's time to run the production build! 🎉
gatsby build --prefix-paths
Note: The
--prefix-paths
option must be used for path prefix to be applied
Once a build is complete, the compiled set of files can be found in /public
. It's all in there and ready to replace the existing files! In the case of the example site, the folder contents are deployed directly to the /who
path of the website domain in place of the existing HTML files.
Here is the structure of the HTML & non-JavaScript asset files after the built Gatsby /who
section is added to website domain:
website-domain
├── assets
│ ├── favicon.ico
│ ├── person.png
│ ├── normalize.css
│ └── style.css
├── index.html
├── 404.html
├── about.html
├── contact.html
├── services
│ ├── index.html
│ ├── growing.html
│ ├── cleaning.html
│ ├── shrinking.html
└── who
{/* highlight-start */}
├── index.html
├── ellla-arborist
│ └── index.html
├── marin-leafer
│ └── index.html
└── sam-surgeon
└── index.html
{/* highlight-end */}
To replace multiple parts of a website with a single Gatsby application there are a few additional steps:
-
Mirror the website structure within the Gatsby
/src/pages
folder. -
Adjust the
pathPrefix
Gatsby configuration option to reflect the new root path at which the Gatsby application will be served. -
Ensure the
to
props on all Gatsby<Link>
components are correct relative to/src/pages/
as the application root.
For the example website covered in this guide, here is what each step involves for also migrating the services
part of the site:
- Create a
/src/pages/who
folder, and move into it all the files currently in/src/pages
. Create a new/src/pages/services
folder and follow the html migration steps above for the/services/
HTML files. The already completed Layout component will save a lot of the work!
gatsby-site-sections/src/pages
├── who
│ ├── index.js
│ ├── ellla-arborist.js
│ ├── marin-leafer.js
│ └── sam-surgeon.js
└── services
├── index.js
├── growing.js
├── cleaning.js
└── shrinking.js
-
The
pathPrefix
configuration option is no longer needed as the Gatsby application will now be served at the root of the site alongside the remaining HTML files. -
Update
<Link>
tagto
props to be relative to the new serving location; the root of the domain. This should be done in/src/pages/who/index.js
,/src/pages/services/index.js
, and/src/components/Layout.js
. Here's the updatedindex.js
for/who
:
import React from "react"
import Layout from "../components/Layout"
import { Link } from "gatsby"
export default () => (
<Layout>
<h1>Who We Are</h1>
<h2>These are our staff:</h2>
<ul>
<li>
<Link to="/who/ella-arborist">Ella (Arborist)</Link>
</li>
<li>
<Link to="/who/sam-surgeon">Sam (Tree Surgeon)</Link>
</li>
<li>
<Link to="/who/marin-leafer">Marin (Leafer)</Link>
</li>
</ul>
</Layout>
)
After following those steps for the example site it is pretty much entirely Gatsby! Migrating the rest of the HTML files, /about.html
, /contact.html
, /404.html
and /index.html
to Gatsby pages would enable pre-fetching links between all the pages in the site. The complete Gatsby application is ready to take full advantage of Gatsby and it's community.
Gatsby can handle assets through direct imports to page and component files; the asset import documentation covers imports as well as the less-optimized static
folder. Once assets are handled through Gatsby, plugins can be used to optimize their processing and delivery.
The building with components doc has information about why Gatsby uses React component architecture and how it fits into a Gatsby application.
Sourcing content and data is a great next step if you are interested in separating your content from your website code, such as sourcing the site title from gatsby-config.js
with GraphQL.
Short guides can be found at the recipes section for adding functionality such as optimizing and querying local images, adding Markdown support and integrating various modern CSS tools. The adding website functionality page has longer guides for larger tasks such as making your site accessible, adding authentication, and fetching data with client-side JavaScript.
Gatsby is dedicated to making you feel welcome! Learn more and engage with the community by starting a conversation or contributing yourself. The community page has further information and channels where you can get support.