Gatsby: Вопрос: как выполнить запрос на основе имени исходной файловой системы gatsby?

Созданный на 27 июл. 2017  ·  20Комментарии  ·  Источник: gatsbyjs/gatsby

У меня есть несколько папок для разных типов страниц. Т.е. type1, type2 и т. д., которые содержат файлы разметки.

pages
   --type1
   --type2

Файлы в каждой папке преобразуются с помощью gatsby-transformer-remark .
Я хочу запрашивать только контент для type1, type2 и т. Д.
Например, мне нужна страница списка type1, которая содержит список всех страниц type1.

gatsby-config.js

   {
      resolve: 'gatsby-source-filesystem',
      options: {
        path: `${__dirname}/src/pages/type1`,
        name: 'type1',
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        path: `${__dirname}/src/pages/type2`,
        name: 'type2',
      },
    },

Я предполагал, что вы можете делать запросы на основе свойства name .

Что-то вроде:

{
  someQueryForGatsbySourceFilesystem(
    filter: {
      name: {
        eq: "type1"
      }
    }
  ) {
    edges {
      node {
        childMarkdownRemark {
          html
        }
      }
    }
  }
}

Я пробовал все разные запросы, такие как allSite и allFile, но не нашел решения.
Я тоже пробовал

  allSitePlugin(filter: {
    pluginOptions: {
      name: {
        eq: "type1"
      }
    }
  })

который, похоже, не возвращает что-то, что я могу использовать для рендеринга контента:

"Cannot query field \"childMarkdownRemark\" on type \"SitePlugin\".",

Как бы ты это сделал? Использовать allFile и фильтр на основе имени пути (т.е. регулярное выражение, которое соответствует папке type1 и расширению уценки)?

 allFile(
  filter: {
    absolutePath:{regex:"/(type1)\/.*\\.md$/"}
  }
) {...}
question or discussion

Самый полезный комментарий

@ tsiq-swyx Я использую что-то вроде этого, чтобы передать поле collection из File в MarkdownRemark .

exports.onCreateNode = ({ node, boundActionCreators, getNode }) => {
  const { createNodeField } = boundActionCreators

  if (_.get(node, 'internal.type') === `MarkdownRemark`) {
    // Get the parent node
    const parent = getNode(_.get(node, 'parent'))

    // Create a field on this node for the "collection" of the parent
    // NOTE: This is necessary so we can filter `allMarkdownRemark` by
    // `collection` otherwise there is no way to filter for only markdown
    // documents of type `post`.
    createNodeField({
      node,
      name: 'collection',
      value: _.get(parent, 'sourceInstanceName'),
    })

Подход regex действительно работает, но он хрупкий.

Все 20 Комментарий

Я подумал, что вы также можете отфильтровать путь с помощью allMarkdownRemark :

{
   allMarkdownRemark(
    sort: { order: DESC, fields: [frontmatter___date]},
    filter: {fileAbsolutePath: {regex: "/(type1)/.*\\.md$/"}}
  ) {
      edges {
        node {
          excerpt(pruneLength: 250)
          id
          frontmatter {
            title
            date(formatString: "MMMM DD, YYYY")
            path
          }
        }
      }
    }
}

Для файловых узлов имя исходного экземпляра задано как sourceInstanceName поэтому вы можете использовать его для запросов.

Использование регулярных выражений также является отличным решением, которое мы часто используем, например, на gatsbyjs.org.

Кстати, если вы еще не используете его, GraphiQL отлично подходит для изучения доступных данных.

@KyleAMathews Есть ли способ использовать sourceInstanceName в запросе allMarkdownRemark ? Я надеялся, что смогу получить sourceInstanceName узла файла для каждого узла уценки, подобного этому, чтобы я мог отделить свои сообщения в блоге от моих проектов без использования регулярного выражения в путях к файлам.

{
  allMarkdownRemark {
    edges {
      node {
        sourceInstanceName
      }
    }
  }
}

Но отладчик GraphQL показывает, что sourceInstanceName недоступен.

Как вы рекомендуете фильтровать страницы с уценкой по типу источника, например по проектам и сообщениям в блогах? Мое текущее решение для этого - получить fileAbsolutePath каждого узла уценки:

{
  allMarkdownRemark {
    edges {
      node {
        fileAbsolutePath
      }
    }
  }
}

А затем проверить, включает ли он определенные строки, например /pages/blog/ или /pages/projects/ . Но это сломается, если абсолютный путь к самому каталогу сайта gatsby содержит одну из этих строк. Что вы посоветуете в этом случае в качестве наилучшей практики? (Извините, если я что-то упустил в документации.)

@nwshane просто запрашивает allFile и фильтрует его. Вы можете фильтровать файлы уценки по internal.mediaType .

@KyleAMathews Как совместить запрос по allFile с сортировкой по переднему заданию? Это возможно?

Пытаюсь выяснить что-то подобное.

Я могу фильтровать по подпапке. Но я не вижу frontmatter в allFile .

screen shot 2018-02-25 at 8 18 51 p m

ОБНОВИТЬ:

Это сработало для меня.

У меня есть папки posts и pages внутри папки content а мой gatsby-config.js указывает на content .

export const query = graphql`
  query IndexQuery {
    allMarkdownRemark(
      filter: { fileAbsolutePath: {regex : "\/posts/"} },
      sort: {fields: [frontmatter___date], order: DESC},
    ) {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            slug
            date(formatString: "DD MMMM YYYY")
            category
          }
          excerpt
        }
      }
    }
  }
`;

@lukejanicke С момента моего последнего обновления я еще немного погрузился в систему узлов. Узлы allFile анализируются обработчиком уценки, а затем создаются новые узлы allMarkdownRemark . Итак, как вы выяснили, в allFile невозможно выполнить сортировку по frontmatter, потому что он генерируется только после того, как сработает анализатор уценки. Регулярное выражение работает, но на мой вкус оно немного хрупкое. Мое решение состояло в том, чтобы скопировать имя коллекции (указанное в конфигурации плагина исходного кода файловой системы) из узла файла в узел уценки с помощью хука onCreateNode . У меня нет кода для публикации примера, но это было очень быстро, а затем у меня есть поле внутри allMarkdownRemark которому я могу фильтровать.

Другая возможность, как советовал @KyleAMathews (в моем случае имя источника - projects )

allFile(filter: {internal: {mediaType: {eq: "text/markdown"}}, sourceInstanceName: {eq: "projects"}}) {
  edges {
    node {
      childMarkdownRemark {
        frontmatter {
            ...
        }
      }
    }
  }
}

@gbouteiller True, это получит frontmatter и позволит фильтровать по sourceInstanceName . Проблема в том, что вы не можете сортировать по чему-либо внутри frontmatter используя этот подход. Кажется, здесь люди говорят о сообщениях в блогах, и они обычно сортируются по дате. Дата обычно хранится внутри frontmatter .

Невозможно выполнить сортировку по чему-то из frontmatter и фильтровать по sourceInstanceName по умолчанию. sourceInstanceName не копируется из узла File узел markdownRemark . Единственный вариант - использовать регулярное выражение или скопировать некоторые данные в соответствии с моей предыдущей публикацией.

Если сортировка не требуется, что может быть верным во многих случаях, тогда ваш подход имеет большой смысл. Я не понимал, что childMarkdownRemark доступно как поле в file , это очень полезно знать, спасибо, что поделились.

возникла эта проблема, и он был разочарован тем, что поле «name» не работает с markdownRemark. есть ли здесь небольшой выигрыш, который мы можем сделать, чтобы передать эту информацию?

EDIT: немного поработав, я понял, что поле id раскрывает путь, и вы можете фильтровать на основе этого:

query AllQuery {
    DSes: allMarkdownRemark(
      limit: 3
      filter: { id: { regex: "/_design-systems/" } }
    ) {
      edges {
        node {
          frontmatter {
            title
            date
            company
            link
            image
            description
          }
          fields {
            slug
          }
        }
      }
    }

    Articles: allMarkdownRemark(
      limit: 3
      filter: { id: { regex: "/_articles/" } }
    ) {
      edges {
        node {
          frontmatter {
            title
            date
            company
            link
            image
            description
          }
          fields {
            slug
          }
        }
      }
    }
  }

поле name из исходной файловой системы по-прежнему ничего не делает для gatsby-transformer-comment, я бы сказал, что оно немного улучшает dx, чтобы передать его как запрашиваемое / фильтруемое поле, поскольку gatsby-transformer-remark никогда существует без gatsby-source-filesystem .

@ tsiq-swyx Я использую что-то вроде этого, чтобы передать поле collection из File в MarkdownRemark .

exports.onCreateNode = ({ node, boundActionCreators, getNode }) => {
  const { createNodeField } = boundActionCreators

  if (_.get(node, 'internal.type') === `MarkdownRemark`) {
    // Get the parent node
    const parent = getNode(_.get(node, 'parent'))

    // Create a field on this node for the "collection" of the parent
    // NOTE: This is necessary so we can filter `allMarkdownRemark` by
    // `collection` otherwise there is no way to filter for only markdown
    // documents of type `post`.
    createNodeField({
      node,
      name: 'collection',
      value: _.get(parent, 'sourceInstanceName'),
    })

Подход regex действительно работает, но он хрупкий.

@chmac, это очень умно и работает, спасибо, что поделились своим решением. @KyleAMathew извините за то, что пометил вас (lmk, если есть кто-то еще, чтобы пометить), но возможно ли, чтобы gatsby-source-filesystem работал таким образом (передача sourceInstanceName в поле узла или другое поле) по умолчанию?

@ tsiq-swyx Я не уверен на 100%, но предполагаю, что это может быть довольно простой запрос на перенос! ;-)

Я думаю, что сопровождающие Gatsby имеют твердое мнение об этих вещах, поэтому я думаю, что стоит обсудить это перед отправкой случайных незапрашиваемых PR :)

Хорошо, у меня все заработало, но мой экспорт createPages использует только один шаблон

Интересно видеть, что использование gatsby-source-filesystem вообще не требует AllFile в graphql. Что может ввести в заблуждение и не отражено в документации.
Я использую
const { createPage } = actions const result = await graphql(` query { allMarkdownRemark { edges { node { fields { slug } frontmatter { lang } } } } } `)
и он создает страницы без проблем. Однако не уверен, применим ли тот же принцип к gatsby-source-git

Спасибо @chmac

Мне нужно создавать страницы на основе gatsby-source-filesystem name ...

так вот мое решение:

const { createFilePath } = require("gatsby-source-filesystem")

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === `Mdx` && getNode(node.parent).sourceInstanceName === "careers") {
    const value = createFilePath({ node, getNode })

    createNodeField({
      name: "slug",
      node,
      value: `/careers${value}`
    })
  }
}

Это интересно, никогда не находил такой вариант node.parent существует

В понедельник, 27 апреля 2020 года, Номан Гюль [email protected] написал:

Спасибо @chmac https://github.com/chmac

Мне нужно создавать страницы на основе имени исходной файловой системы gatsby ...

так вот мое решение:

const {createFilePath} = require ("исходная-файловая система gatsby")
export.onCreateNode = ({узел, действия, getNode}) => {
const {createNodeField} = действия

if (node.internal.type === Mdx && getNode (node.parent) .sourceInstanceName === "карьера") {
значение const = createFilePath ({узел, getNode})

createNodeField({
  name: "slug",
  node,
  value: `/careers${value}`
})

}
}

-
Вы получили это, потому что оставили комментарий.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/gatsbyjs/gatsby/issues/1634#issuecomment-619670883 ,
или отписаться
https://github.com/notifications/unsubscribe-auth/AAEQPFX6KR7NUIY33Q7V4MDROTS7PANCNFSM4DUUPK6A
.

Я нахожусь в той же ситуации, которая, как мне кажется, является довольно распространенным случаем, и после прочтения этой темы; Лучшее и нехакерское решение, на мой взгляд, это:

{
  allMarkdownRemark(filter: {fileAbsolutePath: {regex: "/projects/"}}) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

Мой тип содержимого projects находится в /content/projects/ .

Была ли эта страница полезной?
0 / 5 - 0 рейтинги