Earlier, we explored how to build themes from scratch using the Gatsby theme workspace starter. But this isn’t the only way to create a new theme; Gatsby developers can also convert starters into working Gatsby themes. In fact, the Gatsby documentation pinpoints this conversion path from starters to themes as one of the major motivations for how themes were designed in the first place.
Recall that a starter is a sample Gatsby boilerplate that, once modified, loses all tether to its original source. Meanwhile, a theme is a type of plugin that can be updated and modified according to version updates and modifications made by theme users. In many cases, you may wish to convert a starter into a theme to allow the theme user to receive updates to code that cannot be handled by starters as a rule.
In other words, modifying a starter immediately forces the developer to track all of their changes, whereas shadowing a theme means overriding defaults that are updated as new theme versions are released.
The first step to convert a starter is to modify your package.json file so that it represents the typical characteristics expected of a theme. To ensure Gatsby itself and other developers who choose to use your theme are able to discover it, follow these steps:
- Modify the name to match Gatsby naming conventions. Recall that whereas Gatsby starter names are prefixed with
gatsby-starter-
, Gatsby theme names begin withgatsby-theme-
. For instance, if your starter is namedgatsby-starter-hello-world
, you can change it in package.json togatsby-theme-hello-world
. If you plan to release your theme publicly as a registered package, ensure the namespace you plan to occupy is unused. - Include required development dependencies. Because themes are packages in their own right but cannot be used in isolation from a Gatsby site, it’s important to clarify to users of your package that there are certain required dependencies. Every theme should include
gatsby
,react
, andreact-dom
aspeerDependencies
, as in the following example://
package.json
{
"name"
:
"gatsby-theme-blog"
,
//
...
"peerDependencies"
:
{
"gatsby"
:
"^3.0.0"
,
"react"
:
"^17.0.0"
,
"react-dom"
:
"^17.0.0"
},
}
- Create an index.js file at the project root. Every JavaScript package must include an index.js file, even if it’s empty, to be executable as JavaScript. This is a limitation of Node.js, as Node.js seeks an index.js file first and foremost when Gatsby resolves the theme dependency. You could also provide an alternative file for the
main
key, as seen here://
package.json
{
"name"
:
"gatsby-theme-blog"
,
"version"
:
"3.0.0"
,
"description"
:
"A Gatsby theme for miscellaneous blogging with a >>>
dark/light mode"
,
"main"
:
"other-alternative-file.js"
,
}
The second step is handling path resolution. Starters and themes differ in one fundamental way: whereas starters are composed of executable Gatsby code, themes converted from starters are no longer automatically executed whenever a Gatsby CLI command is run, as all of the logic is now housed in a dependency. Because the Gatsby CLI looks for pages to build within the site and not in dependencies, you may encounter errors after following the preceding steps for unresolved paths.
To ensure that the paths represented in your starter are created whenever Gatsby builds a site based on your new theme, you can enforce the creation of those required paths using the createPage
function in gatsby-node.js, as follows:
// gatsby-theme-minimal/gatsby-node.js
const
createArticles
=
(
createPage
,
createRedirect
,
edges
)
=>
{
edges
.
forEach
(
(
{
node
}
,
i
)
=>
{
// Additional logic goes here.
createPage
(
{
path
:
pagePath
,
component
:
require
.
resolve
(
`
./src/templates/article.js
`
)
,
context
:
{
id
:
node
.
id
,
prev
,
next
,
}
,
}
)
}
)
}
If you had this code in your starter’s gatsby-node.js file, it would simply look for the template found in the site’s src/templates/article.js rather than the location you intend: node_modules/gatsby-theme-minimal/src/templates/post.js. To avoid this issue, you use require.resolve
to point to a local template rather than path.resolve
, which would have Gatsby seek the template in the surrounding site instead.
Pay close attention to where these paths need to switch their resolution, now that you have two places where paths need to be represented properly: your surrounding Gatsby site and your theme dependency. Another common place where path.resolve
invocations may need to be substituted with require.resolve
is in your theme’s gatsby-config.js file.
SOURCING PAGES FROM CUSTOM DIRECTORIES
Most starters use Gatsby’s default behavior to account for pages from the path src/pages, but some starters choose to supply pages from other directories too. To enable this same behavior in your theme, you’ll need to use the gatsby-plugin-page-creator
plugin, which allows you to source pages from custom directories. After installing the plugin, you can configure the custom directory in your gatsby-config.js file:
module
.
exports
=
{
plugins
:
[
{
resolve
:
`gatsby-plugin-page-creator`
,
options
:
{
path
:
path
.
join
(
__dirname
,
`src`
,
`{custom-dictionary}`
),
},
},
],
}
Leave a Reply