让我们使用Gatsby.js的图像优化插件gatsby-image!
2021/03/22追記:
最新发布了一个名为gatsby-plugin-image的新插件。该插件改进了gatsby-image存在的一些问题,正如本文所介绍的那样。因此,现在不推荐使用gatsby-image,但我将保留这篇文章作为备忘录。
首先
我参考了@Takumon的网页文章。该文章非常简洁地总结了gatsby.js的插件,对我的学习很有帮助。我表示感谢。
本次是一篇关于gatsby.js中的图片优化插件gatsby-image的文章,总结了「实施了什么」、「想要做什么」和「无法实现的事情」。
开发环境
基础环境。
MacOS 10.14
Gatsby.js 2.0.76 ( https://www.gatsbyjs.org )
React.js 16.6.3 ( https://reactjs.org )
◯ 插件等
-
- gatsby-image
-
- gatsby-plugin-sharp
-
- gatsby-transformer-sharp
- gatsby-source-filesystem
关于gatsby-image
阅读官方网站
直译:原文的意思
意译:保持原文的表达方式
译文:保持原文不变
为每个设备和屏幕分辨率加载最佳图像大小
加载图像时保持位置,使页面在图像加载时不会跳动
使用“模糊逐渐清晰”效果,即加载图像的同时显示一个缩小版本的图像,直到完整图像加载完成
或者提供一个使用“描边占位符” SVG 的图像
延迟加载图像以减少带宽使用并加快初始加载时间
如果浏览器支持该格式,使用 WebP 图像
请将以下内容以中文本地化描述,只需要一个选项:
日本语翻译
-
- 各デバイスのサイズと画面解像度に最適なイメージサイズを読み込みます
-
- 画像の読み込み中に画像の位置を保持します
-
- 画像全体が読み込まれている間に表示する画像の小さな画像を読み込みます。
-
- レイジーは画像をロードして帯域幅を減らし、初期ロード時間を短縮します
- ブラウザーがその形式をサポートしている場合、WebPイメージを使用します。
请原生中文将以下内容译为巧妙的方式,只需提供一种选择:
关于图像优化的繁琐事务,插件会一切都处理得很好。
实施部分
module.exports = {
plugins: {
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
...(以下省略)
}
}
在gatsby-config.js中,我们需要指定存放图像的目录路径。gatsby-image是一个依赖于gatsby-transformer-sharp和gatsby-plugin-sharp库的库,而不是插件,因此不需要在plugins:{}中进行描述。
import React from 'react'
import { Link, StaticQuery, graphql } from 'gatsby'
import Img from 'gatsby-image'
import Layout from '../components/layout' // 詳細は割愛
const IndexPage = () => (
<StaticQuery
query={query}
render={ data => (
<Layout>
<div>
<Img fixed={data.file.childImageSharp.fixed}/>
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)}
/>
)
export default IndexPage
const query = graphql`
query {
file(relativePath: {eq: "logo.jpg"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
}
}
`
这是最初的实施方案。我们使用GraphQL来进行本地文件搜索,并简单地实现了一系列步骤,以显示与搜索匹配的图像。
我想做的事情 (Wǒ zuò de
-
- 多个图像的显示
-
- 可以通过不同的描述方式进行处理
- 仅通过路径指定来显示
1. 多张图片展示
const query = graphql`
query {
file(relativePath: {eq: "logo.jpg"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
}
}
`
通过阅读Gatsby.js的官方参考文档,我发现在这个部分只能指定一张图片。
因为我遇到了类似于“每页只能使用一张图片吗?”这样的疑问,所以我阅读了Gatsby.js的官方参考文档:
https://www.gatsbyjs.org/docs/graphql-reference/#aliasing
根据官方网站参考文档中的Aliasing的说明,似乎可以一次请求多个文件。所以我将进行相应的实现。
import React from 'react'
import { Link, StaticQuery, graphql } from 'gatsby'
import Img from 'gatsby-image'
import Layout from '../components/layout' // 詳細は割愛
const IndexPage = () => (
<StaticQuery
query={query}
render={ data => (
<Layout>
<div>
<Img fixed={data.logo1.childImageSharp.fixed}/>
<Img fixed={data.logo2.childImageSharp.fixed}/>
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)}
/>
)
export default IndexPage
const query = graphql`
query {
logo1:file(relativePath: {eq: "logo.jpg"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
},
logo2:file(relativePath: {eq: "logo2.jpg"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
}
}
`
这次只是改了名字,但显示确实成功了。(这次只是改了名字,但使用了相同的图片) 在aliasing中可以自由指定名字呢。这次我用了logo1和logo2这两个名字,但如果给它们起一个我自己容易理解的名字,似乎就能避免错误了。
2. 采用多种表达方式来应对。
const IndexPage = () => (
<StaticQuery
query={query}
render={ data => (
<Layout>
<div>
<Img fixed={data.logo1.childImageSharp.fixed}/>
<Img fixed={data.logo2.childImageSharp.fixed}/>
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)}
/>
)
我正在使用StaticQuery来进行绘图,但我希望能更直观地进行编写。因此,我将尝试使用另一种描述方法进行实现。
import React from 'react'
import { Link, graphql } from 'gatsby'
import Img from 'gatsby-image'
import Layout from '../components/layout'
export default props => {
return <Layout>
<div>
<Img fixed={props.data.logo1.childImageSharp.fixed}/>
<Img fixed={props.data.logo2.childImageSharp.fixed}/>
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
}
export const query = graphql`
query {
logo1:file(relativePath: {eq: "logo.jpg"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
},
logo2:file(relativePath: {eq: "logo2.jpg"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
}
}
`
好的,可以顯示出來。
在Gatsby.js中,如果不使用StaticQuery,它會自動儲存在props中。由於fixed的內容略有變化,需要注意一下。整體的程式碼量也減少了,感覺還不錯。
希望能够通过仅指定路径来实现显示。
这是最后的挑战。我试着按自己的方式来优化,只指定路径而不写GraphQL的查询,因为觉得写查询很麻烦!不过,由于我的实现并没有成功,所以我想分享一下这个案例。
请将以下信息仅作为参考信息。
在使用JavaScript的模板字面量时,通过路径进行指定不起作用。我想要做的是:
import * as React from 'react'
import {graphql, StaticQuery} from 'gatsby'
import Image from 'gatsby-image'
const getQuery = path => {
return graphql`
query {
file(relativePath: {eq: "${path}"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
}
}
`
}
export default () => {
return <StaticQuery
query={ getQuery("logo.jpg") }
render={data => (
<Image fixed={data.file.childImageSharp.fixed}/>
)}
/>
}
只需指定路径即可动态生成GraphQL查询,并查询本地的图像。然而,这个方法有一些弱点。GraphQL的参数是一个名为TemplateStringsArray的类型,它指的是使用“(模板字面量)的字符串。然而,这种方法存在一个很大的陷阱,
const getQuery = path => {
return graphql`
query {
file(relativePath: {eq: "${path}"}) {
childImageSharp{
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
}
}
`
}
在使用模板文字中进行表达式展开时,返回的结果会被转换为string类型。因此,graphql函数的参数类型不匹配,会导致错误发生。
尽管我一直努力寻找解决方法,但是无论如何,我仍然无法将TemplateStringsArray类型存储为参数,因为它总是被转换为string类型,所以最终我决定放弃了…(←因为我技术不足)
※2019/3/28添加
简单来说,使用GraphQL标记的模板文字面量来进行文件查询只能在编译时使用。如果你仍然想使用它,那么你需要黑魔法般地自定义babel配置,或者向Gatsby的OSS发送pull请求。
由于Gatsby是一个静态网站生成器,所以无法避免。静态图像的处理非常简单,这是非常令人感激的,因此我们应该自己优化动态图像的加载。
※2020/2/27更新
我常常参考的开发者已经开发了一种使用路径指定实现的可行组件。
创建一种能够通过传递路径显示图像的组件的方法,可以使用gatsby-image。
具体来说,使用gatsby-source-filesystem来收集指定文件夹中的所有图片,然后从中提取与指定路径匹配的图片。虽然这是一种粗糙的技巧,但它可以实现想要的功能!太棒了!因此,希望读者能将本文介绍的部分内容作为参考信息接受。
总结
虽然发生了很多事情,gatsby-image是一个非常方便的图像优化处理库,它会为我处理繁琐的图像优化工作。希望这篇文章对于使用gatsby.js的时候能提供参考。
非常感谢您阅读到这里!