Gatsby Drupal 数据源基准测试站点深度解析:从 gatsby-source-drupal 到构建性能验证
【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby
导读
本文围绕 Gatsby 仓库中的 Drupal Benchmark 基准测试站点展开,该站点是一个专门用于衡量「从 Drupal 作为数据源进行构建」性能的可运行示例。通过完整阅读本文,你将掌握:基准测试站点的目录结构与工作流程、gatsby-source-drupal插件与 GraphQL 数据查询的配置方式、用 Layout 组件切换模拟多页面代码变更的测试手法,以及如何通过 Drupal JSON:API 数据更新脚本驱动增量构建的验证方法。
基准测试站点的设计目标
根据 benchmarks/source-drupal/README.md 的说明,该基准测试的核心前提是:
This benchmark requires space on Drupal and will source its data from there while running the benchmark.
也就是说,它不是一个自包含的静态示例——它要求你先在一个真实的 Drupal 实例上准备好空间与数据,构建过程会实时从 Drupal 拉取内容。其数据模型非常简单:查询 Drupal 中文章的标题(title)、正文(body)与封面图(cover image),并为每一篇文章生成一个页面,把这些内容以 "Articles"(文章)的形式渲染出来。
从源码结构看,这个基准测试站在 Gatsby 层面只做三件事:
- 通过
gatsby-source-drupal从 Drupal 获取node__article类型的数据节点; - 在
createPages中为每篇文章创建一个独立页面; - 首页与文章详情页共用同一个 Layout 组件,通过切换 layout_1.js / layout_2.js 模拟「一个共享组件变更影响多个页面」的场景。
这一设计使得它既能度量「大量内容从外部 CMS 拉取」时的构建耗时,又能度量「共享组件改动导致多页面重建」时的增量构建效率,是 Gatsby 性能基准测试体系中针对 Drupal 数据源的专门样例。
目录结构与关键文件
该基准站点位于仓库的 benchmarks/source-drupal 目录,核心文件如下:
| 文件 | 作用 |
|---|---|
| gatsby-config.js | 站点元信息与插件装配,核心是gatsby-source-drupal |
| gatsby-node.js | 为文章节点生成 slug 字段,并批量创建文章页面 |
| src/pages/index.js | 首页:渲染站点标题与全部文章链接列表 |
| src/templates/article.js | 文章详情页模板:标题、正文与封面图 |
| src/components/layout_1.js | 共享布局组件(Header A) |
| src/components/layout_2.js | 共享布局组件(Header B),用于模拟变更 |
| scripts/data-update.ts | 数据更新入口,读取环境变量并触发更新 |
| scripts/updater.ts | 通过 Drupal JSON:API 修改文章标题,模拟数据变更 |
| package.json | 基准测试相关的 npm 脚本与依赖声明 |
环境变量与 Drupal 连接配置
站点通过 dotenv 按环境加载.env.${NODE_ENV}文件,见 gatsby-config.js:
require("dotenv").config({ path: `.env.${process.env.NODE_ENV}`, })这意味着开发环境读取.env.development,生产构建读取.env.production。整个基准站点依赖以下环境变量:
| 环境变量 | 用途 | 来源文件 |
|---|---|---|
BENCHMARK_DRUPAL_BASE_URL | Drupal 站点地址,传给gatsby-source-drupal的baseUrl | gatsby-config.js |
BENCHMARK_DRUPAL_USERNAME | 用于 JSON:API 认证的用户名 | scripts/data-update.ts |
BENCHMARK_DRUPAL_PASSWORD | 用于 JSON:API 认证的密码 | scripts/data-update.ts |
BENCHMARK_REPORTING_URL | 置为true时构建结束会上报基准数据 | package.json 的build:send脚本 |
在 gatsby-config.js 中,gatsby-source-drupal的配置如下:
{ resolve: `gatsby-source-drupal`, options: { baseUrl: process.env.BENCHMARK_DRUPAL_BASE_URL, // Auth needed for POST }, }注意源码中的注释:用户名/密码认证是为POST/PATCH 写操作准备的(也就是data-update脚本),而构建时拉取数据并不需要。因此若只做纯构建基准测试,只需配置BENCHMARK_DRUPAL_BASE_URL;若要运行数据更新脚本,则还需配置用户名与密码。
插件装配与站点元信息
gatsby-config.js 中共装配了四个插件,分工清晰:
module.exports = { siteMetadata: { siteTitle: `Gatsby Drupal Benchmark`, }, plugins: [ `gatsby-plugin-benchmark-reporting`, `gatsby-plugin-sharp`, `gatsby-transformer-sharp`, { resolve: `gatsby-source-filesystem`, options: { name: `pages`, path: `${__dirname}/src/pages/`, }, }, { resolve: `gatsby-source-drupal`, options: { /* ... */ } }, ], }- gatsby-plugin-benchmark-reporting:基准数据上报插件,与
build:send脚本配套,把构建性能指标发送到基准测试服务端; - gatsby-plugin-sharp / gatsby-transformer-sharp:处理图片处理与转换,为 Drupal 的封面图生成响应式/优化后的派生节点(
childImageSharp); - gatsby-source-filesystem:以
src/pages/为内容目录,保证页面组件被正确收集; - gatsby-source-drupal:核心数据源,负责从 Drupal JSON:API 拉取内容。
该配置体现了基准测试的两个衡量维度:外部 CMS 数据拉取(gatsby-source-drupal)与本地图片处理流水线(Sharp)都会显著影响构建耗时,二者叠加构成贴近真实站点的负载。
从 Drupal 节点到页面:gatsby-node.js 的两段式流程
gatsby-node.js 实现了两个 API,完整呈现了「数据节点 → slug → 页面」的标准链路。
onCreateNode:为文章生成 slug
const kebabCase = require(`lodash.kebabcase`) exports.onCreateNode = ({ actions, node }) => { const { createNodeField } = actions if (node.internal.type === "node__article") { createNodeField({ node, name: "slug", value: kebabCase(node.title) }) } }只有当节点类型为node__article(即 Drupal 的 Article 内容类型经gatsby-source-drupal映射而来)时,才用 lodash.kebabcase 将标题转换为 kebab-case 形式的 slug。这里体现了 Gatsby 的字段扩展机制:createNodeField写入的fields.slug会与节点一起进入 GraphQL 层,供后续查询使用。
createPages:批量创建文章页面
exports.createPages = async ({ actions, graphql, reporter }) => { const { createPage } = actions const result = await graphql(` { articles: allNodeArticle { nodes { fields { slug } } } } `) if (result.errors) { reporter.panicOnBuild(result.errors) } result.data.articles.nodes.map(article => { createPage({ path: article.fields.slug, component: require.resolve(`./src/templates/article.js`), context: { slug: article.fields.slug }, }) }) }流程要点:
- 通过
allNodeArticle查询出所有文章的fields.slug; - 若 GraphQL 查询报错,调用
reporter.panicOnBuild使构建失败并输出错误——这是构建期失败的标准做法; - 对每篇文章调用
createPage,页面路径即 slug,模板指向src/templates/article.js,并把 slug 放入context。
context.slug会被注入到模板的 GraphQL 查询变量中(详见下文 article.js 的query($slug: String!)),这是 Gatsby 把页面数据与模板关联起来的经典模式。文章数量越多,这里的createPage调用与模板渲染次数就越多——正是基准测试希望放大的负载。
首页与文章模板:GraphQL 查询的两种形态
首页 index.js:列表查询
src/pages/index.js 渲染站点标题与全部文章链接:
export const query = graphql` { site { siteMetadata { siteTitle } } articles: allNodeArticle { nodes { title fields { slug } } } } `这是一个不带变量的静态查询:一次拿到站点元信息siteTitle与所有文章的title、fields.slug,然后用<Link>生成指向各文章的导航列表。
文章模板 article.js:变量查询与图片管线
src/templates/article.js 的查询以 slug 为变量:
export const query = graphql` query($slug: String!) { article: nodeArticle(fields: { slug: { eq: $slug } }) { title body { processed } relationships { field_image { localFile { childImageSharp { fluid(maxWidth: 960, quality: 90) { ...GatsbyImageSharpFluid_withWebp_tracedSVG } } } } } } } `该查询展示了三个与基准场景直接相关的数据点:
body.processed:Drupal 侧处理后的 HTML 正文,模板中通过dangerouslySetInnerHTML渲染,模拟真实站点富文本输出;relationships.field_image.localFile.childImageSharp.fluid:Drupal 图片字段经gatsby-source-drupal下载为本地文件、再由 Sharp 流水线生成fluid变体(maxWidth: 960, quality: 90,并启用 WebP 与 traced SVG 占位图),完整覆盖「外部媒体 → 本地文件 → 图片优化」的重负载链路;- 模板对图片做了容错处理:当
childImageSharp不存在时显示Image can't be displayed,避免构建因缺图失败。
渲染时使用gatsby-image的Img组件输出优化图片,并提供一个Go back to index page链接返回首页,形成完整的站内导航闭环。
共享 Layout 与多页面变更模拟
README 特别强调的设计意图是:文章页与首页共享同一个 Layout 组件,可以整体替换以模拟一次影响多个页面的代码变更。
仓库中提供了两个等价实现:
- layout_1.js:输出
Header A; - layout_2.js:输出
Header B。
两者结构完全一致,唯一的差异是 header 文案。当前首页与文章模板都import Layout from "../components/layout_1";当你把两处 import 改为layout_2时,所有页面(首页 + 全部文章页)的共享布局同时发生变化——这正是增量构建基准测试中「少量代码改动触发大量页面重新生成」的标准载荷。基准测试中验证此类场景时,可在修改 import 后执行npm run build,观察仅共享组件变更时的重建耗时。
数据更新脚本:驱动增量构建的「内容变更源」
scripts/data-update.ts 与 scripts/updater.ts 共同构成一个用于模拟「Drupal 侧内容变更」的工具,目的是为增量构建(incremental builds)测试制造真实的数据扰动。
入口与鉴权参数
require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` }) const username = process.env.BENCHMARK_DRUPAL_USERNAME const password = process.env.BENCHMARK_DRUPAL_PASSWORD const server = process.env.BENCHMARK_DRUPAL_BASE_URL update(username, password, server)入口脚本只做三件事:加载环境变量、读取用户名/密码/站点地址、调用update()。如果三者缺失,update会打印You must pass username, password and server并直接返回,见 updater.ts。
JSON:API 数据变更流程
updater.ts 的核心逻辑分两步:
const getFirstArticle = async (server: string): Promise<IArticle> => { const url = `${server}/jsonapi/node/article?page[limit]=1&sort=created` const response = await fetch(url) const body = await response.json() return body.data[0] }第一步先查询「创建时间最早的一篇文章」(sort=created+page[limit]=1);第二步对它发起 PATCH 请求,修改标题:
const updateTitle = (title: string): string => `${title.substring(0, title.lastIndexOf(` `))} ${faker.lorem.word()}`updateTitle会去掉标题的最后一个单词,并用 faker 生成的随机单词替换它——这样每次运行都能产生确定可观察、又不破坏数据结构的标题变化。PATCH 请求本身使用 Drupal JSON:API 规范:
const response = await fetch(url, { method: `PATCH`, headers: { "Content-Type": `application/vnd.api+json`, Authorization: `Basic ${Buffer.from(`${username}:${password}`).toString(`base64`)}`, }, body: JSON.stringify({ data: { type: `node--article`, id: article.id, attributes: { title: updateTitle(article.attributes.title) }, }, }), })这里使用了HTTP Basic 认证(Authorization: Basic base64(username:password))与 JSON:API 媒体类型application/vnd.api+json,请求体结构符合 JSON:API 的 resource object 规范(type+id+attributes)。这也印证了 gatsby-config.js 中「Auth needed for POST」注释的含义——写操作需要凭据,而构建拉取数据不需要。
npm 脚本与基准测试运行流程
package.json 定义了完整的操作入口:
| 脚本 | 命令 | 用途 |
|---|---|---|
build | gatsby build | 常规生产构建 |
build:send | cross-env BENCHMARK_REPORTING_URL=true gatsby build | 构建并上报基准数据 |
clean | gatsby clean | 清理缓存 |
data-update | ts-node scripts/data-update.ts | 修改 Drupal 文章标题,模拟内容变更 |
develop | gatsby develop | 开发模式 |
start | npm run develop | 开发模式别名 |
serve | gatsby serve | 预览生产构建产物 |
依赖方面,该基准站点固定在 Gatsby v3 生态:gatsby ^3.5.1、gatsby-source-drupal ^4.7.2、gatsby-image ^3.5.0,配合react ^17.0.2;工具链使用ts-node+typescript ^4.2.4运行数据脚本,cross-env用于跨平台设置环境变量。对应的 TypeScript 编译配置见 tsconfig.json(target ES2018、strict 模式、commonjs 模块)。
一个典型的基准测试循环如下:
- 准备 Drupal 实例与内容,设置
BENCHMARK_DRUPAL_BASE_URL(如需运行数据脚本,再设置BENCHMARK_DRUPAL_USERNAME/BENCHMARK_DRUPAL_PASSWORD); - 执行
npm run build(或带上报的npm run build:send)得到首轮构建基线; - 执行
npm run contenteditable="false">【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考