Gatsby: Вопрос - Как читать Markdown с фронтальной части

Созданный на 17 апр. 2018  ·  41Комментарии  ·  Источник: gatsbyjs/gatsby

Описание

Я хочу читать контент уценки из фронтмэттера. Например:

 halfBlocks:
 - title: это первое название
 содержание:> -
 ### Это фактическое содержимое в формате ** MarkDown **.

 - Это первая строка
 - Это второй ряд
 - Это третий ряд
 - title: Это второй заголовок
 содержание:> -
 ### Это фактическое содержимое в формате ** MarkDown **.

 - Это первая строка
 - Это второй ряд
 - Это третий ряд

Я использую следующий graphql:

 halfBlocks {
 заглавие
 образ
 содержание
 }

Как читать содержимое, преобразованное в HTML или отображаемое как HTML?

Ожидаемый результат

Я ожидаю, что смогу прочитать это из файла уценки, например index.md, и отобразить его как HTML.

Фактический результат

Markdown отображается как есть без интерпретации.

Окружающая обстановка

  • Версия Гэтсби ( npm list gatsby ): gatsby@^1.9.247
  • версия gatsby-cli ( gatsby --version ): 1.1.50
question or discussion

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

Это могло быть полностью отключено, но не могли бы вы просто создать компонент уценки, как показано ниже, который затем можно было бы использовать в своих шаблонах везде, где уценка необходима для преобразования в HTML.

import React from 'react'
import PropTypes from 'prop-types'
import showdown from 'showdown'

const converter = new showdown.Converter()

const MarkdownContent = ({ content, className }) => (
  <div className={className} dangerouslySetInnerHTML={{ __html: converter.makeHtml(content) }} />
)

MarkdownContent.propTypes = {
  content: PropTypes.string,
  className: PropTypes.string,
}


export default MarkdownContent

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

В руководстве это рассматривается, особенно в частях 5-7 https://www.gatsbyjs.org/tutorial/.

Вы также можете начать с одного из стартовых инструментов, многие из которых уже имеют поддержку уценки - https://www.gatsbyjs.org/docs/gatsby-starters/

Вопрос более тонкий и не рассматривается в руководстве, поэтому я открою его снова.

На мой взгляд, у вас есть 2 варианта:

  1. Вы можете разделить содержимое уценки на отдельные файлы и использовать ссылки пути:
Separate file - let's call it `someContent.md`
```md
### This is the actual content in **MarkDown** format.

- This is the first row
- This is second row
- This is third row
```
and reference that file in your main file (by relative path):
```md
halfBlocks:
  - title: This is first title
    content: "./someContent.md"
```
then in query you could
```
halfBlocks {
  content {
    childMarkdownRemark {
      html
    }
}
```
  1. Другой подход будет обрабатывать это программно - создавать узлы уценки для ваших полей переднего плана и добавлять их через createNodeField . Это более сложно. Вам, вероятно, потребуется просмотреть плагин Contentful source, чтобы увидеть, как создать узел MarkdownRemark.

Привет, @KyleAMathews, спасибо за предложение. Я читал их, но мне было трудно полностью понять, как это сделать. Я использую стартер, но это было сложнее. Используемый стартер: https://github.com/v4iv/gatsby-starter-business

@pieh Большое спасибо за то, что направили меня. Ты прав. Я подумал, что у меня будет слишком много маленьких файлов, поэтому я получил это, работая с приведенным ниже кодом. Я документирую это здесь, чтобы, если у кого-то еще есть такая же проблема, они также могли это увидеть.

Шаг 1. Чтение содержания

Я обычно читаю контент через Graphql. Это дает мне уценку в виде строки. Мне все еще нужно это преобразовать.

Шаг 2: преобразование в HTML

Для этого я решил оставить содержимое в виде строки до тех пор, пока мы не дойдем до фактического компонента, который будет отображать это. Там конвертирую в уценку.

Добавьте замечание, чтобы сделать это программно. Вы можете игнорировать комментарий-preset-lint-Recommended:

Установить примечание

yarn add remark remark-preset-lint-recommended remark-html

импорт

import remark from 'remark';
import recommended from 'remark-preset-lint-recommended';
import remarkHtml from 'remark-html';

Визуализировать
Позже в части рендеринга предполагается, что content - это уценка, которая была прочитана как строка:

content = remark()
      .use(recommended)
      .use(remarkHtml)
      .processSync(content).toString();

Теперь я могу интерпретировать контент как HTML.

Шаг 3. Добавление содержимого в уценку

Есть еще одна проблема, с которой я столкнулся. Форматирование было неправильным, когда я использовал многострочность с >- :

content: >-
    ### This is the actual content in **MarkDown** format.
    - This is the first row
    - This is second row

Но с вертикальной чертой | отлично работает.

content: |
    ### This is the actual content in **MarkDown** format.
    - This is the first row
    - This is second row

А пока я закрываю это. Пожалуйста, не стесняйтесь открывать снова, если хотите.

Благодаря!!

Я также хотел бы использовать уценку для обложки (заголовок и, если быть точным, отрывок), и я думаю, что он должен поддерживаться по умолчанию.

Было бы здорово иметь соглашение об именах, чтобы gatsby-transformer-remark понимал, например, что title.md - это поле уценки.

@omeid @ thorn0 это может быть что-то, что мы поддерживаем непосредственно в gatsby-transformer-comment, но пока вы можете создать плагин, который сделает это за вас, например https://github.com/gatsbyjs/gatsby/issues/5729#issuecomment -395701042 и createNodeField

Приносим извинения за комментарий к уже закрытой проблеме, но просто хотел поделиться фрагментом, который я использовал в своем собственном gatsby-node.js который работал у меня, следуя тому, на что вы все ссылались:

// Need to `yarn add remark remark-html`, then include the following code in
// gatsby-node.js.
const remark = require('remark');
const remarkHTML = require('remark-html');

exports.onCreateNode = ({ node }) => {
  // Conditionals, etc. can be used here, but I omitted those just for example's sake.
  const markdown = node.frontmatter.my_field;
  node.frontmatter.my_field = remark()
    .use(remarkHTML)
    .processSync(markdown)
    .toString();
  return node;
};

Так можно ли сделать это без использования createNodeField ? Я не совсем понимаю.

@ thorn0 лучше использовать createNodeField вместо node.frontmatter.my_field = потому что изменение node может затруднить отладку ошибок

@amitjindal @nshki Он работает приводит к сбою моего производственного процесса сборки, так как я установил библиотеку "response-flickity-component":

success delete html and css files from previous builds — 0.626 s
success open and validate gatsby-config — 0.018 s
success copy gatsby files — 0.075 s
success onPreBootstrap — 2.782 s
error UNHANDLED EXCEPTION


  TypeError: Cannot set property 'Compiler' of null

  - index.js:16 plugin
    [blog]/[remark-html]/index.js:16:17

  - index.js:271 Function.use
    [blog]/[unified]/index.js:271:25

  - gatsby-node.js:63 exports.onCreateNode.postscriptumsMarkdown.forEach.postscr    iptum
    /home/projects/blog/gatsby-node.js:63:12

  - Array.forEach

  - gatsby-node.js:61 Object.exports.onCreateNode
    /home/projects/blog/gatsby-node.js:61:29

  - api-runner-node.js:110 runAPI
    [blog]/[gatsby]/dist/utils/api-runner-node.js:110:36

  - api-runner-node.js:187 
    [blog]/[gatsby]/dist/utils/api-runner-node.js:187:33

  - map.js:27 
    [blog]/[async]/internal/map.js:27:9

  - eachOfLimit.js:66 replenish
    [blog]/[async]/internal/eachOfLimit.js:66:17

  - eachOfLimit.js:50 iterateeCallback
    [blog]/[async]/internal/eachOfLimit.js:50:17

  - onlyOnce.js:12 module.exports
    [blog]/[async]/internal/onlyOnce.js:12:16

  - map.js:29 
    [blog]/[async]/internal/map.js:29:13

  - util.js:16 tryCatcher
    [blog]/[bluebird]/js/release/util.js:16:23

  - nodeify.js:23 Promise.successAdapter
    [blog]/[bluebird]/js/release/nodeify.js:23:30

  - promise.js:566 Promise.module.exports.Promise._settlePromise
    [blog]/[bluebird]/js/release/promise.js:566:21

  - promise.js:606 Promise.module.exports.Promise._settlePromiseCtx
    [blog]/[bluebird]/js/release/promise.js:606:10


Waiting for the debugger to disconnect...

Process finished with exit code 130 (interrupted by signal 2: SIGINT)

Попытка исключить библиотеку из Webpack не работает ( @see https://github.com/gatsbyjs/gatsby/issues/7599)

Привет, Дэвид (@comxd), извини, что ехал.
К сожалению, я не понимаю этого. Пытался проверить код. Компилятор с нулевым значением, похоже, исходит из библиотеки замечаний.

Кажется, вы используете цикл в файле gatsby-node.js.
Это может быть связано с тем, что поступает какой-то контент, который не является уценкой или, что еще хуже, пустым, и вы пытаетесь его обработать. Попробуйте поместить туда несколько операторов console.log и посмотрите, найдете ли вы шаблон, в котором что-то пустое вызывает это.

Это могло быть полностью отключено, но не могли бы вы просто создать компонент уценки, как показано ниже, который затем можно было бы использовать в своих шаблонах везде, где уценка необходима для преобразования в HTML.

import React from 'react'
import PropTypes from 'prop-types'
import showdown from 'showdown'

const converter = new showdown.Converter()

const MarkdownContent = ({ content, className }) => (
  <div className={className} dangerouslySetInnerHTML={{ __html: converter.makeHtml(content) }} />
)

MarkdownContent.propTypes = {
  content: PropTypes.string,
  className: PropTypes.string,
}


export default MarkdownContent

@blakenoll определенно не полностью выключен! Это разумный подход.

Тем не менее, одним из больших преимуществ Gatsby является то, что вы выполняете эти операции во время сборки, что приятно, потому что тогда нам не нужно продавать анализатор Markdown конечному пользователю!

@DSchau Разве анализатор Markdown не будет отправлен пользователю после

@blakenoll Люблю нестандартное мышление!

Есть ли у нас что-нибудь доступное для установки всех плагинов / конфигураций замечаний, которые мы включили в gatsby-config.js чтобы нам не нужно было дублировать все функции, выполняемые за кулисами, которые предоставляет нам реализация Gatsby примечания ? Это упростило бы создание полей узла; но невероятно громоздко, когда вы думаете о вложенных, повторяемых полях и разнообразии содержимого на странице.

@blakenoll Большое спасибо за ваш совет по вскрытию карт. Очень полезно и сделал то, что мне нужно, чтобы использовать HTML на переднем плане. Тем не менее, кажется неуклюжим подход к использованию Markdown для создания веб-страницы, которая должна передавать разные фрагменты контента в разные части страницы.

Есть ли способ применить какую-то функцию markdownParser в разделе frontmatter нашего запроса graphQL (аналогично тому, как мы можем манипулировать изображениями), которая будет анализировать входящую строку markdown в frontmatter и преобразовывать ее в HTML? Не эксперт по graphQL ... просто пытаюсь думать.

Это важная проблема, IMO b / c, если вы используете Gatsby с Netifly CMS, Netifly предоставляет возможность, чтобы различные поля внешнего интерфейса принимали Markdown в качестве значений. Но при запросе этих полей они возвращаются как разметка в строке, а не анализируются в HTML. Решения @amitjindal и @blakenoll работают, но, как упоминалось в @DSchau , отправлять пользователю анализ уценки

@skylarweaver Я определенно на одной странице с тобой. Хотя я понимаю природу создания поля узла, которое может анализировать эту информацию, оно также становится немного громоздким с данными CMS, которые могут иметь повторяющиеся поля и большое количество вариаций имен полей, которые нужно просеивать; вдобавок к отсутствию четкого способа повторно использовать какие-либо / все плагины Gatsby Remark в то время.

+1 что сказал @skylarweaver !

@amitjindal Может быть, глупый вопрос, но что вообще делает "> -"? Используя стартер netlify cms, кажется, нет абсолютно никакой разницы в сгенерированном выводе, есть ли у меня>,> -, | или вообще ничего.

@ nol13 См. блочные скаляры , речь идет о новых строках .

Как мне вставить таблицу? Это не работает

content: |
        |   |   |   |   |   |
        |---|---|---|---|---|
        |   |   |   |   |   |
        |   |   |   |   |   |
        |   |   |   |   |   |

@ qnguyen12 Я бы попробовал использовать такой инструмент, как https://jmalarcon.github.io/markdowntables/, чтобы помочь вам с преобразованием.

Да, я имею в виду, что он отображается как источник, а не таблица
Например:

text: |
        test   
        ### This is the actual content in **MarkDown** format.  
        |Month|Savings|Spending|
        |--- |--- |--- |
        |January|$100|$900|
        |July|$750|$1000|
        |December|$250|$300|
        |April|$400|$700|

он генерирует:
контрольная работа

Это актуальный контент в формате MarkDown .

| Месяц | Экономия | Расходы | | --- | --- | --- | | Январь | 100 $ | 900 $ | | Июль | 750 $ | 1000 $ | | Декабрь | 250 $ | 300 $ | | Апрель | 400 $ | 700 $ |

@KyleAMathews Спасибо, такая работа, но, очевидно, вам нужно либо ответить на конфигурацию плагина примечания и плагины, либо вы получите другие результаты. Есть ли планы по поддержке фронтматтера уценки? Возможно, поле frontmattermd вместе с необработанным frontmatter ?

@omeid У меня нет никаких планов, нет - это был бы отличный плагин, который кто-то может создать и поделиться с сообществом!

Я создал плагин, который должен делать это: gatsby-transformer-comment-frontmatter . Судя по результатам моего тестирования, он работает, и я планирую использовать его в проекте, который делаю для клиента, но я был бы признателен, если бы вы, ребята, взглянули и сказали мне, есть ли что-то, что выглядит неправильно , так как я впервые пишу плагин для Гэтсби. Он выбирает маршрут, предложенный frontmattermd в узел MarkdownRemark.

Первоначально, прежде чем я понял, что могу просто создать новые узлы файлов уценки для использования gatsby-transformer-comment, я придумал действительно хакерское решение, включающее вызов преобразователей, экспортируемых функцией setFieldsOnGraphQLNodeType gatsby-transformer-comment, и передачу нового узел уценки, созданный в другом преобразователе. Это позволяло запрашивать любое поле на узле MarkdownRemark, используя перечисление полей, подобное тому, что используется для групповой функции, что мне очень понравилось, но было похоже на хакерское использование для чего-либо. Я сохранил это здесь для потомков.

привет @WhiteAbeLincoln, я попытался установить и протестировать:
npm i gatsby-transformer-remark-frontmatter npm ERR! code ENOVERSIONS npm ERR! No valid versions available for gatsby-transformer-remark-frontmatter

Извините, я понял, что еще не опубликовал в npm. Я опубликую его, как только выйду с работы, и дам вам знать.

- Эйб Уайт

17 июня 2019 г., в 22:53, брокер [email protected] написал:

привет @WhiteAbeLincoln, я попытался установить и протестировать:
npm i gatsby-transformer-comment-frontmatter npm ERR! код ENOVERSIONS npm ERR! Нет доступных версий для gatsby-transformer-comment-frontmatter

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите обсуждение.

@WhiteAbeLincoln. Я попробовал gatsby-transformer-comment-frontmatter, но у меня возникла ошибка.

ОШИБКА № 11325

Ваш сайт "gatsby-node.js" создал страницу с несуществующим компонентом.

Вы получаете эту ошибку?

Изначально @obeid сообщил об этом в

Может, я просто неправильно им пользуюсь. Так что некоторая помощь приветствуется.

Основываясь на ответе @nshki и с комментарием @pieh о мутации узла. Это полностью работает для меня:

const remark = require("remark");
const remarkHTML = require("remark-html");

exports.onCreateNode = ({ node, actions: { createNodeField } }) => {
  const my_field = node.frontmatter.my_field;

  if (my_field) {
    const value = remark()
      .use(remarkHTML)
      .processSync(my_field)
      .toString();

    // new node at:
    // fields {
    //   my_field_html
    // }
    createNodeField({
      name: `my_field_html`,
      node,
      value
    });
  }
};

изменить: my_field => my_field_html

@aziaziazi Как я могу сделать то же самое, но для поля, вложенного в массив?

---
pressEventsList:
  - body: >-
      *My md content...*
    image: 'https://res.cloudinary.com/press/01.jpg'
  - body: >-
      *My md content...*
    image: 'https://res.cloudinary.com/press/02.jpg'
---

Мне нужно преобразовать каждый pressEventsList[i].body .

@alexeychikk, я думаю, вы можете искать pressEventList а затем отображать содержимое для создания массива результатов:

const remark = require("remark");
const remarkHTML = require("remark-html");

exports.onCreateNode = ({ node, actions: { createNodeField } }) => {
const pressEventList = node.frontmatter.pressEventList;

if (pressEventList) {
  const value = pressEventList.map(event =>
     remark()
    .use(remarkHTML)
    .processSync(event.body)
    .toString()
  )

  createNodeField({
    name: `pressEventList`,
    node,
    value
  });
}
};

Я заинтересован в создании плагина для анализа пользовательских тегов YAML для достижения вышеуказанного без использования createNodeField (точно так же, как резкий анализ URL-адресов изображений).
Может ли кто-нибудь указать мне на код, в котором анализируются URL-адреса изображений, чтобы увидеть пример того, как это делается в настоящее время с Sharp?

👋 Для тех, кто использует MDX, я создал плагин для добавления поддержки frontmatter https://www.gatsbyjs.org/packages/gatsby-plugin-mdx-frontmatter/

@zslabs , не часто вы видите решение, опубликованное «9 часов назад»! Я попробую! Хорошая работа.

Я боролся с этим, так как хотел использовать более сложную структуру данных для одной из моих страниц.
Вначале у меня был массив разделов с несколькими полями, такими как заголовок и избранное изображение, а затем для каждого я сделал тело с уценкой.
Использование createNodeField не помогло мне, потому что у меня возникли проблемы с их логической связью, поскольку они создаются в их собственном поле, а не добавляются к существующей структуре frontmatter.
В итоге я использовал createFieldExtension, чтобы при запросе моего section.body он возвращался в HTML.
Пожалуйста, кто-нибудь поправьте меня, если это не хорошее решение, похоже, оно работает для меня, но у меня есть тошнотворное чувство, что это неправильный путь к этому.

моя передняя структура выглядит так:

templateKey: project-entry
date: 2020-06-22T13:16:57.702Z
featuredproject: true
title: Project title
description: Description for listing the project on other pages
featuredimage: Image for listing the project on other pages
featuredpost: false
sections:
  - heading: Section heading
    standout: false
    intro: >-
      Introduction to be displayed separately to body
    body: >-
       ## section title
       * bullet point
       * bullet point
       Some other text here

И код, который я использовал в gatsby-node.js

exports.createSchemaCustomization = ({actions}) => {
  const { createTypes, createFieldExtension} = actions

  createFieldExtension({
    name: 'toHTML',
    extend:() => ({
        resolve(source) {
          return remark().use(remarkHTML).processSync(source.body).toString()
        }
      })
  })
  const typeDefs = `
  type MarkdownRemark implements Node {
    frontmatter: Frontmatter
  }
  type Frontmatter <strong i="14">@infer</strong> {
    sections: [section]
  }
  type section <strong i="15">@infer</strong> {
    body: String <strong i="16">@toHTML</strong>
  }
  `
  createTypes(typeDefs)
}

Для всех, кто заинтересован, я решил это, используя пользовательский тип YAML, чтобы разрешить синтаксический анализ любого произвольного поля как уценки следующим образом:

---
title: My Page
inline: !md Some **bold** and _italic_ text
block: !md |
  ## I'm a H2 title
  [I'm an inline-style link](https://www.google.com)
---

Для этого создайте собственный тип, а затем переопределите синтаксический анализатор YAML серого вещества:

// custom-yaml.js
const yaml = require('js-yaml')
const remark = require('remark')
const remarkHTML = require('remark-html')

const MarkdownYamlType = new yaml.Type('!md', {
  kind: 'scalar',
  construct: data => remark().use(remarkHTML).processSync(data).toString(),
})

const MARKDOWN_SCHEMA = yaml.Schema.create(MarkdownYamlType)

module.exports = doc => yaml.safeLoad(doc, { schema: MARKDOWN_SCHEMA })
// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        engines: { yaml: require("path/to/custom-yaml.js") },
      },
    }
  ]
}

Я решил это немного иначе. Я создал расширение поля под названием @md и использовал его в определении типа frontmatter в сочетании с переименованием поля, чтобы достичь желаемой абстракции.

exports.createSchemaCustomization = ({ actions }) => {
  actions.createFieldExtension({
    name: "md",
    args: {
      from: {
        type: "String!",
        defaultValue: true,
      },
    },

    extend() {
      return {
        args: {
          from: "String!",
        },
        resolve(source, args) {
          const fieldValue = source[args.from]
          return convertToHTML(fieldValue)
        },
      }
    },
  })
  const typeDefs = `
    type MarkdownRemark implements Node <strong i="7">@infer</strong> {
      frontmatter: Frontmatter
    }
    type Frontmatter {
      markdownField: String! <strong i="8">@md</strong>
    }
  `
  actions.createTypes(typeDefs)
}

вот пример использования:

...
frontmatter {
        title: markdownField(from: "title")
        subtitle: markdownField(from: "subtitle")
}

Я решил это немного иначе.

Для меня это не совсем подходит. Сначала я получаю сообщение об ошибке, отклоняющее defaultValue: true для аргумента from - это должна быть строка. Изменив это на defaultValue: '' , я получаю эту ошибку:

Encountered an error parsing the provided GraphQL type definitions:
Argument "from" of required type "String!" was not provided.

  1 |
  2 |     type MarkdownRemark implements Node <strong i="11">@infer</strong> {
  3 |       frontmatter: Frontmatter
  4 |     }
  5 |     type Frontmatter {
> 6 |       markdownField: String! <strong i="12">@md</strong>
    |                              ^
  7 |     }

Я не знаю, как это решить.

Для всех, кто заинтересован, я решил это, используя пользовательский тип YAML, чтобы разрешить синтаксический анализ любого произвольного поля как уценки следующим образом:

---
title: My Page
inline: !md Some **bold** and _italic_ text
block: !md |
  ## I'm a H2 title
  [I'm an inline-style link](https://www.google.com)
---

Для этого создайте собственный тип, а затем переопределите синтаксический анализатор YAML серого вещества:

// custom-yaml.js
const yaml = require('js-yaml')
const remark = require('remark')
const remarkHTML = require('remark-html')

const MarkdownYamlType = new yaml.Type('!md', {
  kind: 'scalar',
  construct: data => remark().use(remarkHTML).processSync(data).toString(),
})

const MARKDOWN_SCHEMA = yaml.Schema.create(MarkdownYamlType)

module.exports = doc => yaml.safeLoad(doc, { schema: MARKDOWN_SCHEMA })
// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        engines: { yaml: require("path/to/custom-yaml.js") },
      },
    }
  ]
}

Если я попробую этот метод, я получаю сообщение "Недопустимые параметры плагина для" gatsby-transformer-comment ":

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

Смежные вопросы

rossPatton picture rossPatton  ·  3Комментарии

ferMartz picture ferMartz  ·  3Комментарии

benstr picture benstr  ·  3Комментарии

dustinhorton picture dustinhorton  ·  3Комментарии

signalwerk picture signalwerk  ·  3Комментарии