マークダウンの投稿とページで画像を操作するためのGatsbyチュートリアルに従いましたが、これはうまく機能していますが、達成したいのは、画像の相対パスを使用するのではなく、静的な場所から画像をフェッチすることです。
このような画像を参照したい(フロントマター)
featuredImage: img/IMG_20190621_112048_2.jpg
IMG_20190621_112048_2.jpgが/src/data/img
下のマークダウンファイルと同じディレクトリの代わりにある場所/src/posts
私はgatsby-source-filesystem
このようにセットアップしようとしました:
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `data`,
path: `${__dirname}/src/data/`,
},
},
しかし、投稿テンプレートのgraphQLクエリは失敗します:
export const query = graphql`
query($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
html
frontmatter {
title
featuredImage {
childImageSharp {
fluid(maxWidth: 800) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
タイプ「String」にはサブフィールドがないため、GraphQLエラーフィールド「featuredImage」に選択を含めることはできません。
ポストマークダウンディレクトリとは別の場所から画像をフェッチする方法はありますか?
Gatsbyでこれを実現するのは以前はかなり面倒でしたが、新しいcreateSchemaCustomization
Node APIドキュメント(Gatsby 2.5以降)のおかげで比較的簡単です。
これが私があなたのリポジトリ構造を複製するデモです:github
関連するコードが存在する場所は次のとおりです:github
これを機能させるためのコードは次のとおりです。
// gatsby-node.js
const path = require('path')
exports.createSchemaCustomization = ({ actions }) => {
const { createFieldExtension, createTypes } = actions
createFieldExtension({
name: 'fileByDataPath',
extend: () => ({
resolve: function (src, args, context, info) {
const partialPath = src.featureImage
if (!partialPath) {
return null
}
const filePath = path.join(__dirname, 'src/data', partialPath)
const fileNode = context.nodeModel.runQuery({
firstOnly: true,
type: 'File',
query: {
filter: {
absolutePath: {
eq: filePath
}
}
}
})
if (!fileNode) {
return null
}
return fileNode
}
})
})
const typeDefs = `
type Frontmatter @infer {
featureImage: File @fileByDataPath
}
type MarkdownRemark implements Node @infer {
frontmatter: Frontmatter
}
`
createTypes(typeDefs)
}
これには2つの部分があります。
markdownRemark.frontmatter.featureImage
graphqlが文字列ではなくファイルノードに解決されるように拡張します。createTypes
@fileByDataPath
介して新しい体の拡大を作成しますcreateFieldExtension
現在、ギャツビーfrontmatter.featureImage
は文字列として推論しています。親タイプを変更して、代わりにfeatureImageを文字列として読み取るようにGatsbyに依頼します。
type Frontmatter {
featureImage: File
}
これだけでは不十分ですが、このFrontmatter
タイプもその親に渡す必要があります。
type Frontmatter {
featureImage: File
}
type MarkdownRemark implements Node {
frontmatter: Frontmatter
}
我々はまた、追加します@infer
つまり、ギャツビーが、それはこれらのタイプの他のフィールドを推測できることを知ることができますタグをfrontmatter.title
、markdownRemark.html
など
次に、これらのカスタムタイプを次の宛先に渡しますcreateTypes
。
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type Frontmatter @infer {
featureImage: File
}
type MarkdownRemark implements Node @infer {
frontmatter: Frontmatter
}
`
createTypes(typeDefs)
}
これで、起動localhost:8000/___graphql
して画像のクエリを試すことができます
query Post {
markdownRemark {
frontmatter {
featureImage {
id
}
}
}
}
そして、私たちは...
エラー:null不可能なフィールドFile.idに対してnullを返すことはできません。
これは、GatsbyfeatureImage
がファイルノードであるべきだと理解している一方で、そのファイルをどこで取得するかがわからないためです。
この時点で、を使用createResolvers
してフィールドを手動でファイルノードに解決createFileExtension
するか、同じことを行うことができます。createFileExtension
より多くのコードの再利用が可能になるため(任意のフィールドを拡張できます)、createResolvers
この場合は特定のフィールドに対してより便利であるため、私は選択します。src/data
ディレクトリからファイルを解決するだけでよいので、この拡張子を呼びますfieldByDataPath
。
resolve属性を見てみましょう。これは、以下を取り込む関数です。
frontmatter
)featureImage
クエリで渡される引数。これは必要ありませんnodeModel
、Gatsbyノードストアからノードを取得するために使用するが含まれますimg/photo.jpg
から元のパス()を見つけsrc.featureImage
、それをに接着してsrc/data
完全な絶対パスを取得します。次に、nodeModelにクエリを実行して、絶対パスが一致するファイルノードを見つけます。すでにポイントgatsby-source-filesystem
しているのでsrc/data
、画像(photo.jpg)はGatsbyノードストアにあります。
パスまたは一致するノードが見つからない場合は、を返しnull
ます。
resolve: async function (src, args, context) {
// look up original string, i.e img/photo.jpg
const partialPath = src.featureImage
if (!partialPath) {
return null
}
// get the absolute path of the image file in the filesystem
const filePath = path.join(__dirname, 'src/data', partialPath)
// look for a node with matching path
const fileNode = await context.nodeModel.runQuery({
firstOnly: true,
type: 'File',
query: {
filter: {
absolutePath: {
eq: filePath
}
}
}
})
// no node? return
if (!fileNode) {
return null
}
// else return the node
return fileNode
}
作業の99%を完了しました。最後に行うことは、これを移動してこの解決関数をcreateFieldExtension
;に渡すことです。createTypesに新しい拡張機能を追加するだけでなく
createFieldExtension({
name: 'fileByDataPath' // we'll use it in createTypes as `@fileByDataPath`
extend: () => ({
resolve, // the resolve function above
})
})
const typeDef = `
type Frontmatter @infer {
featureImage: File @fileByDataPath // <---
}
...
`
これで、src/data/
フロントマターから相対パスを使用できるようになりました。
fileByDataPath
実装方法では、という名前のフィールドでのみ機能しますfeatureImage
。これはあまり役に立たないので、名前が_data
;で終わるフィールドで機能するように変更する必要があります。または、少なくとも、作業するフィールド名のリストを受け入れます。
編集には少し時間があったので、これを行うプラグインを作成し、ブログも作成しました。
Edit 2 Gatsbyはそれ以来runQuery
非同期になり(2020年7月)、これを反映するように回答を更新しました。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加