Gatsby 多主题组合实战:用 gatsby-theme-blog、gatsby-theme-notes 与组件 Shadowing 构建组合式站点
2026/9/20 14:51:04 网站建设 项目流程
  • 前端
  • 静态站点
  • Web框架

【免费下载链接】gatsby

React-based framework with performance, scalability, and security built in.

项目地址:https://gitcode.com/gh_mirrors/ga/gatsby
点击查看免费下载

导读

Gatsby Themes 是 Gatsby 对传统网站模板的一次创新重构:它把"预配置的功能 + 数据源 + UI 代码"打包成可独立升级、可任意组合的 npm 包。本篇教程将以gatsby-theme-bloggatsby-theme-notes@pauliescanlon/gatsby-mdx-embed三个主题为例,完整演示如何在单个站点中组合多个主题,并通过组件 Shadowing(组件阴影)与 Theme-UI 定制样式与布局。读完本文,你将掌握多主题组合的配置方法、内容目录的约定、basePath路由拆分、组件阴影的覆盖机制,以及如何用主题组合出一个"博客 + 笔记 + 视频嵌入 + 自定义导航"的一体化站点。

本仓库在 examples/using-multiple-themes 目录下提供了与本教程配套的完整可运行示例,文中的代码片段即取自该示例,完整源码可随时对照查看。

前置知识

本教程假设你已经具备以下基础:

  • 理解 Gatsby 基础概念(页面、插件、GraphQL 查询等基本用法);
  • 已经了解什么是 Gatsby Themes——简单说,主题就是包含gatsby-config.js、并带入了预配置功能、数据源和 UI 代码的插件,可以理解为"可组合的独立 Gatsby 站点"。

若对主题概念还比较陌生,建议先阅读仓库内的 What Are Gatsby Themes? 与 Using Multiple Gatsby Themes 两篇文档。

创建新站点

使用 hello-world starter 创建新站点并进入目录:

gatsby new multiple-themes https://github.com/gatsbyjs/gatsby-starter-hello-world cd multiple-themes

gatsby new会从 starter 拉取一个最小可运行的 Gatsby 项目骨架,后续所有主题相关配置都将写在这个项目的gatsby-config.js中。

安装并组合两个主题

本步骤将gatsby-theme-blog(博客主题)与gatsby-theme-notes(笔记主题)组合进同一个站点。

1. 安装主题

npm install gatsby-theme-blog gatsby-theme-notes

主题本质上是 npm 包,安装后即可像普通插件一样被gatsby-config.js引用;同时它们也具备版本化升级能力——上游主题发布新版本后,只需升级站点中的依赖版本即可同步获得更新。

2. 编辑gatsby-config.js

将主题加入plugins数组,并更新站点元数据:

module.exports = { siteMetadata: { title: `Your Site Title`, description: `A description for your blazing fast site, using multiple themes!`, author: `Your name`, social: [ { name: `Twitter`, url: `https://twitter.com/gatsbyjs`, }, { name: `GitHub`, url: `https://github.com/gatsbyjs`, }, ], }, plugins: [ { resolve: `gatsby-theme-blog`, options: { basePath: `/blog`, }, }, { resolve: `gatsby-theme-notes`, options: { basePath: `/notes`, }, }, ], }

这里的关键是basePath选项:它决定了主题生成的内容挂在哪个 URL 前缀下。gatsby-theme-blog的内容被安置到/bloggatsby-theme-notes的内容被安置到/notes,两个主题在同一站点内各占一段路由,互不干扰——这正是主题可组合性的直观体现。对照仓库中的示例配置 examples/using-multiple-themes/gatsby-config.js 可以看到完全一致的用法(示例中博客主题最终使用了默认的/作为basePath)。

3. 运行站点

gatsby develop

4. 验证结果

打开http://localhost:8000查看当前站点内容。

添加内容

两个主题会在站点根目录自动创建各自的内容文件夹(这是主题的约定:gatsby-theme-blog读取content/postsgatsby-theme-notes读取content/notes)。接下来向这些文件夹添加内容。

添加一篇博客文章

/content/posts下创建新文件:

--- title: My first blog post date: 2020-02-15 --- Multiple themes are great!

添加一条笔记

/content/notes下创建新文件:

--- title: My first note date: 2020-02-20 --- Multiple themes are awesome!

注意原教程中的目录名写为content/note/hello-notes.md,实际示例仓库中对应文件位于 examples/using-multiple-themes/content/notes/hello-notes.mdx,即笔记内容统一放在content/notes目录下。

这些内容文件采用 MDX 格式(frontmatter 中声明titledate),主题会读取它们并在运行时生成对应页面。

重新启动开发服务器gatsby develop,然后访问:

  • http://localhost:8000/blog/hello-posts/
  • http://localhost:8000/notes/hello-notes

即可看到新内容。注意 URL 与前面配置的basePath一一对应。

添加头像图片

将一张头像图片放入content/assets/目录。gatsby-theme-blog的 bio(作者简介)组件会读取该目录下的图片作为作者头像,文件名可以是avatar.pngavatar.jpg。示例仓库中对应的资源文件位于 examples/using-multiple-themes/content/assets/avatar.png。

把博客文章放到首页

默认情况下博客挂在/blog,若希望博客直接出现在站点首页/,只需两步:

  1. 删除现有的src/pages/index.js文件(把首页控制权让渡给主题);
  2. 修改gatsby-config.js中博客主题的basePath
{ resolve: `gatsby-theme-blog`, options: { // basePath 默认为 `/`,因此也可以不写 options,直接写成 `gatsby-theme-blog` basePath: `/`, }, },
  1. 重新运行gatsby develop验证新首页。

basePath默认值就是/,所以当博客希望占据根路径时,这一项甚至可以省略。示例仓库最终就采用了这种配置,笔记主题则保持basePath: /notes,形成"首页即博客、/notes放笔记"的布局。

组件 Shadowing(组件阴影)

主题提供的组件并非一成不变——通过"组件阴影"机制,你可以在自己的站点里用同名文件覆盖主题内部的组件,从而在不 fork 主题的前提下完成深度定制。核心规则是:把你自己的文件放到与主题内部组件完全相同的相对路径下,Gatsby 会优先加载你的版本。

💡 提示:第一次添加被阴影覆盖的组件时,别忘了停止并重启开发服务器,让构建管线重新识别阴影文件。

阴影bio-content.js

首先定制gatsby-theme-blogbio组件的文字内容。主题内该文件的路径是components/bio-content.js,因此你需要在站点中创建:

└── src ├── gatsby-theme-blog │ ├── components │ │ ├── bio-content.js // 阴影文件

bio 文案可以自由发挥,组件形态大致如下:

import React, { Fragment } from "react" import { Styled } from "theme-ui" export default function BioContent() { return ( <Fragment> Words by <Styled.a href="http://example.com/">Your Name</Styled.a>. <br /> Change me. Your awesome bio, about how great you are! </Fragment> ) }

完整版本可对照 examples/using-multiple-themes/src/gatsby-theme-blog/components/bio-content.js。注意这里的 JSX 路径前缀src/gatsby-theme-blog/——gatsby-theme-blog既是主题名,也是阴影目录的命名空间。

阴影 Theme-UI

gatsby-theme-bloggatsby-theme-notes都使用 Theme-UI 设计令牌(design tokens)来管理样式:颜色、字号、间距等。你同样可以通过组件阴影接管这些设计令牌。

与 bio 的做法一致,需要匹配主题的文件结构,即创建src/gatsby-plugin-theme-ui/index.js

└── src ├── gatsby-plugin-theme-ui │ ├── index.js // 阴影文件

颜色可随意选择,下面是一个示例:

import merge from "deepmerge" import defaultTheme from "gatsby-theme-blog/src/gatsby-plugin-theme-ui/index" export default merge(defaultTheme, { colors: { background: "ghostwhite", text: "black", primary: "mediumvioletred", modes: { dark: { background: "indigo", text: "ghostwhite", primary: "gold", }, }, }, })

这里有两个关键点:

  • 示例使用了deepmerge做深合并:你没有覆盖的 Theme-UI 配置会保留主题的默认值,只需声明你想改变的部分;
  • 由于gatsby-theme-notesgatsby-theme-blog共享同一个 Theme-UI 上下文,这份阴影配置会同时作用于两个主题,实现全站视觉统一。

对照示例仓库的 src/gatsby-plugin-theme-ui/index.js,可以看到相同的merge写法。此外,多个主题共存时 Theme-UI 上下文的归属存在约定:从 Using Multiple Gatsby Themes 文档可知,"在gatsby-config.js中最后出现的主题会覆盖其他主题的 Theme-UI 上下文",因此在多主题站点中,把承担主要样式职责的主题放在plugins数组末尾是一个实用的控制手段。

再添加一个小型主题

主题可以是大而全的(如gatsby-theme-blog),也可以只是一小组离散的组件或函数。@pauliescanlon/gatsby-mdx-embed就是后者的典型:它为 MDX 文件增加了直接嵌入社交媒体内容和视频的能力。

1. 安装主题

npm install @pauliescanlon/gatsby-mdx-embed

2. 更新gatsby-config.js

gatsby-mdx-embed作为插件加入数组:

module.exports = { siteMetadata: { // ...siteMetadata 保持不变。 }, plugins: [ `@pauliescanlon/gatsby-mdx-embed`, // 新增 { resolve: `gatsby-theme-blog`, options: { basePath: `/`, }, }, { resolve: `gatsby-theme-notes`, options: { basePath: `/notes`, }, }, ], }

注意这里没有配置对象、没有options——当一个主题无需任何配置时,可以像普通字符串插件一样直接声明。示例仓库 examples/using-multiple-themes/gatsby-config.js 最终也是以这种形式引入它的。

3. 在博客文章中嵌入视频

content/posts/video-post.md中添加 YouTube 视频:

--- title: Jason and Jackson Talk Themes date: 2020-02-21 --- Here is a video about composing and styling themes with J&J! <YouTube youTubeId="6Z4p-qjnKCQ" />

重启开发服务器后,这篇博客文章就会渲染出对应的 YouTube 播放器。对应的示例文件见 examples/using-multiple-themes/content/posts/video-post.mdx。由此可见,多主题组合不仅能堆叠"完整站点级"的大主题,也能以极低的成本叠加"组件级"的小主题,粒度完全由你决定。

添加导航菜单

最后,通过组件阴影给站点加上一个跨页面的导航菜单。

1. 在gatsby-config.js中新增menuLinks数组

module.exports = { siteMetadata: { title: `Your Site Title`, description: `A description for your blazing fast site, using multiple themes!`, author: `Your name`, menuLinks: [ { name: `Blog`, url: `/`, }, { name: `Notes`, url: `/notes`, }, ], social: [ // ...social 数组保持不变。 ], }, plugins: [ // ...plugins 数组保持不变。 ], }

导航项通过siteMetadata.menuLinks声明,与博客、笔记的basePath一一对应,保证菜单指向真实存在的路由。

2. 创建导航组件

import React from "react" import { Link, useStaticQuery, graphql } from "gatsby" import { Styled, css } from "theme-ui" export default function Navigation() { const data = useStaticQuery( graphql` query SiteMetaData { site { siteMetadata { menuLinks { name url } } } } ` ) const navLinks = data.site.siteMetadata.menuLinks return ( <nav css={css({ py: 2, // paddingTop 与 paddingBottom 的简写 })} > <ul css={css({ display: `flex`, listStyle: `none`, margin: 0, padding: 0, })} > {navLinks.map(link => ( <li css={css({ marginRight: 2, ":last-of-type": { marginRight: 0, }, })} > <Styled.a css={css({ fontFamily: `heading`, fontWeight: `bold`, textDecoration: `none`, ":hover": { textDecoration: `underline`, }, })} as={Link} to={link.url} > {link.name} </Styled.a> </li> ))} </ul> </nav> ) }

这个组件演示了两点:一是用useStaticQuery在组件内直接查询siteMetadata.menuLinks,导航数据完全由配置驱动;二是 Theme-UI 的cssprop 与Styled.a的配合——as={Link}让 Gatsby 的<Link>客户端路由能力与 Theme-UI 样式无缝结合。完整实现见 examples/using-multiple-themes/src/components/navigation.js。

3. 阴影header.js

接下来阴影gatsby-theme-blogheader.js。作为起点,可以从主题原始组件复制代码再修改。你的文件结构应为:

└── src ├── gatsby-theme-blog │ ├── components │ │ ├── header.js // 阴影文件

4. 导入导航并加入头部

import React from "react" import { css } from "theme-ui" import Navigation from "../../components/navigation" // 新增 export default function Header() { return ( <header> <div css={css({ maxWidth: `container`, mx: `auto`, px: 3, pt: 4, })} > <Navigation /> // 新增 </div> </header> ) }

这一步体现了组件阴影的另一个优势:被阴影的组件可以自由组合站点自身的其他组件(这里的Navigation就位于src/components/navigation.js,不在任何主题内部)。示例仓库中的真实 header 还在此基础上进一步保留了主题原有的暗色模式切换、站点标题与 bio 等能力,见 examples/using-multiple-themes/src/gatsby-theme-blog/components/header.js,可作为"从主题原组件出发做增量改造"的完整范本。

5. 验证

运行gatsby develop测试新的导航组件,首页与/notes页面顶部应出现"Blog / Notes"两个导航链接。

总结

通过本教程,你已经掌握了在单个 Gatsby 站点中组合多个主题的完整链路:

  • 组合配置:在gatsby-config.jsplugins数组中同时声明多个主题,并用basePath为每个主题划分路由;
  • 内容约定:主题按约定从content/下的固定目录(postsnotesassets)读取内容与资源;
  • 组件阴影:通过"同名同路径"规则(src/gatsby-theme-blog/components/...src/gatsby-plugin-theme-ui/index.js)覆盖主题组件与 Theme-UI 设计令牌,配合deepmerge做到最小化定制;
  • 组合粒度:既可以组合博客、笔记这类完整主题,也可以叠加gatsby-mdx-embed这类组件级小型主题;
  • 数据驱动 UI:导航等自定义组件可通过siteMetadata+useStaticQuery声明式渲染。

Gatsby Themes 是对传统网站模板的一次创新式重构——传统 starter 建出的站点与模板立即"脱钩",难以接收上游更新;而主题是可版本化、可升级、可复用的 npm 包,多站点可共享同一主题,多个主题可自由组合。理解并善用它们的潜力,等于给开发者工具箱中又添了一套强大的工具。

继续深入

  • 构建一个主题:从零编写自己的可发布主题;
  • What Are Gatsby Themes? 与 Using Multiple Gatsby Themes:主题的概念与多主题组合约定;
  • 本教程配套的完整示例仓库源码位于 examples/using-multiple-themes,所有最终配置与组件均可直接对照运行。
  • 前端
  • 静态站点
  • Web框架

【免费下载链接】gatsby

React-based framework with performance, scalability, and security built in.

项目地址:https://gitcode.com/gh_mirrors/ga/gatsby
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询