Gatsby 在处理和管理图像方面做得非常出色。例如,它可以帮助您节省图像优化的时间,因为您无需手动优化每个图像。
通过插件和一些配置,您甚至可以使用 Gatsby 为图像设置图像预加载和一种称为**模糊加载**的技术。这有助于提供更流畅、更快速、更吸引人的用户体验。
我发现将gatsby-source-filesystem、GraphQL、Sharp 插件和gatsby-image组合起来进行组织和理解非常繁琐,尤其是在这种功能相当普遍的情况下。此外,gatsby-image 的工作方式与普通的<img>
标签完全不同,并且在配置整个系统时,实现网站的一般用例可能会变得复杂。

如果您还没有这样做,应该阅读gatsby-image 文档。它是 Gatsby 用于处理和放置响应式、延迟加载图像的 React 组件。此外,它还保存图像位置,防止在加载时页面跳动,您甚至可以为每个图像创建模糊加载预览。
对于响应式图像,您通常会使用<img>
标签,并在srcset
属性中包含一系列大小合适的图像,以及一个sizes
属性,用于告知图像将用于的布局情况。
<img srcset="img-320w.jpg 320w,
img-480w.jpg 480w,
img-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="img-800w.jpg">
您可以在Mozilla 文档中了解更多关于此工作原理的信息。这是使用 gatsby-image 的优势之一:它会在设置srcset
属性的同时自动执行所有调整大小和压缩操作,这些属性位于<img />
标签中。
图像目录结构
项目规模和复杂性很容易增长。即使是一个单页面网站也可能包含大量的图像资源,从图标到完整的幻灯片。将图像按某种顺序组织起来,而不是将它们全部堆积在服务器上的单个目录中,会很有帮助。这有助于我们更直观地设置处理流程并分离关注点。
在尝试组织文件时,还需要考虑的是,Gatsby 使用自定义的 webpack 配置来处理、压缩和导出项目中的所有文件。生成的输出将放置在/public
文件夹中。gatsby-starter-default 使用的整体结构如下所示
/
|-- /.cache
|-- /plugins
|-- /public
|-- /src
|-- /pages
|-- /components
|-- /images
|-- html.js
|-- /static (not present by default)
|-- gatsby-config.js
|-- gatsby-node.js
|-- gatsby-ssr.js
|-- gatsby-browser.js
在此处阅读有关 Gatsby 项目结构的工作原理的更多信息 此处。
让我们从可能遇到的需要组织的常见图像文件开始
例如
- 图标
- 徽标
- 网站图标
- 装饰性图像(通常是矢量或 PNG 文件)
- 图像库(例如“关于我们”页面上的团队头像等)
我们如何分组这些资源?考虑到我们追求效率的目标以及上面提到的 Gatsby 项目结构,最佳方法是将其分成两组:一组不需要处理,可以直接导入项目;另一组需要处理和优化的图像。
您的定义可能有所不同,但该分组可能如下所示
静态,不需要处理
- 不需要处理的图标和徽标
- 预优化图像
- 网站图标
- 其他矢量文件(如装饰性艺术作品)
需要处理
- 非矢量艺术作品(例如 PNG 和 JPG 文件)
- 图库图像
- 任何其他可以处理的图像,基本上是矢量以外的常见图像格式
现在,我们已经以某种顺序组织了这些内容,可以继续管理每个组。
“静态”组
Gatsby 提供了一个非常简单的处理静态组的方法:将所有文件添加到项目根目录下名为static
的文件夹中。打包程序会自动将内容复制到public
文件夹中,最终构建可以直接访问这些文件。
假设您有一个名为logo.svg
的文件,它不需要处理。将其放在static
文件夹中,并在组件文件中使用它,如下所示
import React from "react"
// Tell webpack this JS file requires this image
import logo from "../../static/logo.svg"
function Header() {
// This can be directly used as image src
return <img src={logo} alt="Logo" />
}
export default Header
是的,就这么简单——就像导入组件或变量然后直接使用它一样。Gatsby 有详细的文档,介绍如何将资源直接导入文件,您可以参考以进一步了解。
特殊情况:网站图标
插件gatsby-plugin-manifest
不仅会向项目添加manifest.json
文件,还会为所有所需大小生成网站图标并在网站中链接它们。
通过最少的配置,我们就可以拥有网站图标,无需手动调整大小,也无需在 HTML 头部添加单独的链接。将favicon.svg
(或 .png 或您使用的任何格式)放在static
文件夹中,并使用gatsby-plugin-manifest
的设置调整gatsby-config.js
文件。
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `Absurd`,
icon: `static/favicon.svg`,
},
},
“处理”组
理想情况下,我们希望gatsby-image
像img
标签一样工作,我们指定src
,它会在后台执行所有处理。不幸的是,它并不那么简单。Gatsby 要求您配置gatsby-source-filesystem以处理文件,然后使用 GraphQL 查询并使用 Gatsby Sharp 插件(例如gatsby-transformer-sharp、gatsby-plugin-sharp)和gatsby-image对其进行处理。结果是一个响应式、延迟加载的图像。
我不会带您逐步了解如何在 Gatsby 中设置图像处理(这已经在Gatsby 文档中得到了很好的说明),而是将向您展示针对一些常见用例优化此过程的几种方法。我假设您具备 Gatsby 图像处理工作原理的基本知识——但如果没有,我强烈建议您先阅读文档。
用例:图像库
让我们以“关于我们”页面上的个人资料图像的常见情况为例。排列方式基本上是一个包含标题、描述和图像的数据数组,以网格或集合的形式显示在特定部分。
数据数组将类似于
const TEAM = [
{
name: 'Josh Peck',
image: 'josh.jpg',
role: 'Founder',
},
{
name: 'Lisa Haydon',
image: 'lisa.jpg',
role: 'Art Director',
},
{
name: 'Ashlyn Harris',
image: 'ashlyn.jpg',
role: 'Frontend Engineer',
}
];
现在,让我们将所有图像(josh.jpg
、lisa.jpg
等)放在src/images/team
中。您可以根据组别在images
中创建文件夹。由于我们正在处理“关于我们”页面上的团队成员,因此我们使用了images/team
。下一步是查询这些图像并将其与数据链接起来。
为了使这些文件在 Gatsby 系统中可用以进行处理,我们使用 gatsby-source-filesystem。此特定文件夹的gatsby-config.js
中的配置如下所示
{
resolve: `gatsby-source-filesystem`,
options: {
name: `team`,
path: `${__dirname}/src/images/team`,
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
},
要查询来自此特定文件夹的文件数组,我们可以使用sourceInstanceName
。它采用gatsby-config.js
中指定的名称的值。
{
allFile(filter: { sourceInstanceName: { eq: "team" } }) {
edges {
node {
relativePath
childImageSharp {
fluid(maxWidth: 300, maxHeight: 400) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
这将返回一个数组
// Sharp-processed image data is removed for readability
{
"data": {
"allFile": {
"edges": [
{
"node": {
"relativePath": "josh.jpg"
}
},
{
"node": {
"relativePath": "ashlyn.jpg"
}
},
{
"node": {
"relativePath": "lisa.jpg"
}
}
]
}
}
如您所见,我们使用relativePath
将我们需要关联的图像与数据数组中的项目关联起来。一些简单的 JavaScript 可以在这里提供帮助
// Img is gatsby-image
// TEAM is the data array
TEAM.map(({ name, image, role }) => {
// Finds associated image from the array of images
const img = data.allFile.edges.find(
({ node }) => node.relativePath === image
).node;
return (
<div>
<Img fluid={img.childImageSharp.fluid} alt={name} />
<Title>{name}</Title>
<Subtitle>{role}</Subtitle>
</div>
);
})
这是我们最接近使用类似于<img>
标签的src
的方式。
用例:艺术作品
尽管艺术作品可以使用相同类型的文件创建,但这些文件通常分散在不同部分(例如页面和组件)中,并且每个文件通常具有不同的尺寸。
很明显,像之前那样查询整个数组是行不通的。但是,我们仍然可以将所有图像组织到一个文件夹中。这意味着我们仍然可以使用sourceInstanceName
来指定我们要从哪个文件夹中查询图像。
类似于我们之前的用例,让我们创建一个名为src/images/art
的文件夹并配置gatsby-source-filesystem。在查询时,我们不会获取整个数组,而是根据我们的需求查询特定尺寸和规格的图像。
art_team: file(
sourceInstanceName: { eq: "art" }
name: { eq: "team_work" }
) {
childImageSharp {
fluid(maxWidth: 1600) {
...GatsbyImageSharpFluid
}
}
}
这可以直接在组件中使用。
<Img fluid={data.art_team.childImageSharp.fluid} />
此外,对于需要从该组中获取图像的每个组件或部分,都可以重复此操作。
特殊情况:内联 SVG
Gatsby 会自动将较小的图像编码为 base64 格式并将其数据内联,从而减少请求次数以提高性能。这通常很好,但实际上可能会对 SVG 文件造成损害。相反,我们可以手动处理 SVG 以获得相同的性能优势,或者在我们需要使内容更具交互性时,加入动画。
我发现gatsby-plugin-svgr 是这里最方便的解决方案。它允许我们将所有 SVG 文件导入为 React 组件。
import { ReactComponent as GithubIcon } from './github.svg';
由于我们在技术上处理的是 SVG 文件而不是栅格图像,因此将 SVG 文件从static
文件夹中移出并将其放在使用它的组件的文件夹中是有意义的。
结论
在几个项目中使用 Gatsby 后,我克服了在处理图像以获得良好的模糊放大效果时遇到的几个障碍。我认为它们可能对您有用,特别是对于我们所看到的常见用例。
这里使用到的所有约定都来自我在 GitHub 上设置的gatsby-absurd 启动项目。以下是结果。
如果您想查看在项目中使用的示例,最好查看一下。查看Team.js
以了解如何从同一组中查询多个图像。其他部分,例如About.js
和Header.js
,演示了如何查询设计图形(跨不同部分共享的图像组)。Footer.js
和Navbar.js
提供了处理图标的示例。
谢谢,但不要,谢谢。
这似乎太复杂了。
我的解决方案简单得多。
inotify 检测指定目录中的新图像,并执行本地 Linux 命令来调整大小和优化新图像。
用几行 bash 脚本完成。
你应该写一篇关于如何操作的文章!我很想读一读。