MDX 渲染器 - Gatsby 站点 - <li>、<pre> 和 <code> 标签未渲染
MDX renderer - Gatsby Site - <li>, <pre> and <code> tags not rendering
我想弄清楚为什么我必须在 gatsby-browser.js 中指定所有 HTML 标签,以便 MDXrenderer 了解如何设置 HTML 标签的样式.
内容来自 GraphCMS 通过 GraphQL 查询。
我一直在研究其他未设置规范的 gatsby 项目,但它们正确呈现 HTML 标签。
我能够定位大多数 HTML 标签,但我无法弄清楚我的“ul”和“li”标签是如何呈现的。例如,我能够定位它们并应用颜色,但在查看时它仍然看起来像页面上的“p”标签。尽管如果您检查该元素,它确实会显示“ul”和“li”标签。
参见下面的示例:
Webpage with inspection
这是我的 gatsby-node.js 文件:
const path = require("path")
exports.createPages = async ({ actions: { createPage }, graphql }) => {
const { data } = await graphql(
`
{
pages: allGraphCmsPage {
nodes {
id
content {
markdownNode {
childMdx {
body
}
}
}
seo {
description
image {
url
}
keywords
title
}
slug
subtitle
title
}
}
posts: allGraphCmsPost(sort: { fields: date, order: ASC }) {
edges {
nextPost: next {
slug
title
}
page: node {
id
author {
id
name
title
}
content {
markdownNode {
childMdx {
body
}
}
}
date: formattedDate
excerpt
seo {
description
image {
url
}
keywords
title
}
slug
title
}
previousPost: previous {
slug
title
}
}
}
}
`
)
if (data.errors) throw data.errors
data.posts.edges.forEach(({ nextPost, page, previousPost }) => {
createPage({
component: path.resolve("./src/templates/article-post.tsx"),
context: {
id: page.id,
page,
previousPost,
nextPost,
},
path: `/articles/${page.slug}`,
})
})
data.pages.nodes.forEach(page => {
createPage({
component: path.resolve("./src/templates/default-page.tsx"),
context: {
page,
},
path: `/${page.slug}`,
})
})
}
exports.createResolvers = ({ createResolvers }) => {
const resolvers = {
GraphCMS_Post: {
formattedDate: {
type: "String",
resolve: source => {
const date = new Date(source.date)
return new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
}).format(date)
},
},
},
}
createResolvers(resolvers)
}
这是我的 gatsby-config.js 文件:
require("dotenv").config()
const path = require("path")
module.exports = {
siteMetadata: {
title: `Code Shape`,
description: `Learn to create great things.`,
author: `@codeshape`,
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/icons`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/logos`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/profiles`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts/`,
},
},
{
resolve: "gatsby-plugin-page-creator",
options: {
path: `${__dirname}/src/posts`,
},
},
`gatsby-plugin-mdx`,
{
resolve: "gatsby-source-graphcms",
options: {
endpoint: process.env.GRAPHCMS_ENDPOINT,
token: process.env.GRAPHCMS_TOKEN,
buildMarkdownNodes: true,
downloadLocalImages: true,
},
},
`gatsby-plugin-styled-components`,
`gatsby-plugin-react-helmet`,
"gatsby-transformer-sharp",
"gatsby-plugin-sharp",
],
}
这是我的 gatsby-browser.js 文件:
import React from "react"
import { MDXProvider } from "@mdx-js/react"
import Layout from "./src/components/layout/layout"
/* eslint-disable */
const components = {
wrapper: ({ children }) => <>{children}</>,
h1: props => (
<h1 style={{ fontSize: "60px", fontWeight: "bold" }} {...props} />
),
h2: props => (
<h2 style={{ fontSize: "40px", fontWeight: "bold" }} {...props} />
),
h3: props => (
<h3 style={{ fontSize: "30px", fontWeight: "bold" }} {...props} />
),
h4: props => (
<h4 style={{ fontSize: "20px", fontWeight: "bold" }} {...props} />
),
p: props => <p style={{ fontSize: "16px", lineHeight: 1.6 }} {...props} />,
strong: props => (
<strong style={{ fontWeight: "900", lineHeight: 1.6 }} {...props} />
),
img: props => <img style={{ width: "100%" }} {...props} />,
pre: props => {
const className = props.children.props.className || ""
const matches = className.match(/language-(?<lang>.*)/)
return (
<Highlight
{...defaultProps}
code={props.children.props.children}
language={
matches && matches.groups && matches.groups.lang
? matches.groups.lang
: ""
}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={style}>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
},
}
const wrapPageElement = ({ element, props }) => (
<Layout {...props}>{element}</Layout>
)
const wrapRootElement = ({ element }) => (
<MDXProvider components={components}>{element}</MDXProvider>
)
export { wrapPageElement, wrapRootElement }
这是我文章的模板-post.tsx 文件:
import React from "react"
import { graphql, Link } from "gatsby"
import Img from "gatsby-image"
import { MDXRenderer } from "gatsby-plugin-mdx"
import styled from "styled-components"
import {
BodyMain,
Caption,
H1,
MediumText,
} from "../components/styles/TextStyles"
import ReactDisqusComments from "react-disqus-comments"
import LazyLoad from "react-lazy-load"
export const pageQuery = graphql`
fragment AssetFields on GraphCMS_Asset {
id
localFile {
childImageSharp {
fluid(maxWidth: 600) {
...GatsbyImageSharpFluid
}
}
}
}
query ArticlePostQuery($id: String!) {
authorImage: graphCmsAsset(
authorAvatar: {
elemMatch: { posts: { elemMatch: { id: { in: [$id] } } } }
}
) {
...AssetFields
}
coverImage: graphCmsAsset(
coverImagePost: { elemMatch: { id: { eq: $id } } }
) {
...AssetFields
}
}
`
export default function ArticlePostTemplate({
data: { authorImage, coverImage },
pageContext: { nextPost, page, previousPost },
}) {
return (
<Wrapper>
<Header>
<PublishDate>{page.date}</PublishDate>
<PageTitle>{page.title}</PageTitle>
</Header>
<InformationWrapper>
<AuthorWrapper>
<AuthorAvatar>
<Img
fluid={authorImage.localFile.childImageSharp.fluid}
fadeIn={false}
className="Image"
/>
</AuthorAvatar>
<AuthorTextWrapper>
<AuthorName>{page.author.name}</AuthorName>
<AuthorTitle>{page.author.title}</AuthorTitle>
</AuthorTextWrapper>
</AuthorWrapper>
</InformationWrapper>
<ContentWrapper>
<Img
fluid={coverImage.localFile.childImageSharp.fluid}
fadeIn={false}
className="CoverImage"
/>
<MDXRenderer>{page.content.markdownNode.childMdx.body}</MDXRenderer>
</ContentWrapper>
<Navigation>
{(nextPost || previousPost) && (
<div>
<hr className="Divider" />
{nextPost && (
<div>
<h2>Next Post</h2>
<div>
<Link to={`/articles/${nextPost.slug}`}>
{nextPost.title}
</Link>
</div>
<hr className="Divider" />
</div>
)}
{previousPost && (
<div>
<h2>Previous Post</h2>
<div>
<Link to={`/articles/${previousPost.slug}`}>
{previousPost.title}
</Link>
</div>
<hr className="Divider" />
</div>
)}
</div>
)}
<div>
<Link to="/articles/" className="">
← Back to the blog
</Link>
</div>
</Navigation>
<LazyLoad offsetTop={400}>
<ReactDisqusComments
shortname="codeshape"
identifier={page.id}
title={page.title}
url={page.url}
category_id={page.category_id}
/>
</LazyLoad>
</Wrapper>
)
}
const Wrapper = styled.div`
margin: 1.875rem;
display: grid;
grid-gap: 1.875rem;
`
const Header = styled.div`
text-align: center;
margin: 0 auto;
`
const PublishDate = styled(BodyMain)`
color: #757372;
`
const PageTitle = styled(H1)``
const InformationWrapper = styled.div`
display: grid;
align-items: center;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
`
const ContentWrapper = styled.div`
display: grid;
grid-gap: 1rem;
margin: 0 auto;
max-width: 80rem;
.CoverImage {
border-radius: 1.25rem;
object-fit: cover;
}
`
const AuthorWrapper = styled.div`
margin: 0 auto;
padding: 1rem;
display: grid;
grid-gap: 1rem;
grid-template-columns: auto auto;
width: 20rem;
justify-content: center;
align-content: center;
`
const AuthorAvatar = styled.div`
.Image {
border-radius: 50%;
border: 3px solid white;
width: 4rem;
}
`
const AuthorTextWrapper = styled.div`
display: grid;
justify-content: center;
align-content: center;
`
const AuthorName = styled(MediumText)`
font-weight: 900;
`
const AuthorTitle = styled(Caption)`
color: #757372;
`
const Navigation = styled.div`
margin: 0 auto;
text-align: center;
padding: 1.875rem;
display: grid;
grid-gap: 1rem;
width: 18rem;
.Divider {
color: #757372;
line-height: 3rem;
}
`
package.json 文件中的依赖项:
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@types/react-helmet": "^6.1.0",
"@types/styled-components": "^5.1.4",
"autoprefixer": "^10.2.3",
"babel-plugin-styled-components": "^1.12.0",
"gatsby": "^2.28.0",
"gatsby-image": "^2.10.0",
"gatsby-plugin-manifest": "^2.8.0",
"gatsby-plugin-mdx": "^1.9.0",
"gatsby-plugin-offline": "^3.6.0",
"gatsby-plugin-react-helmet": "^3.6.0",
"gatsby-plugin-sharp": "^2.13.4",
"gatsby-plugin-styled-components": "^3.9.0",
"gatsby-source-filesystem": "^2.7.0",
"gatsby-source-graphcms": "^2.2.0",
"gatsby-transformer-sharp": "^2.11.0",
"prop-types": "^15.7.2",
"react": "^16.14.0",
"react-disqus-comments": "^1.4.0",
"react-dom": "^16.14.0",
"react-helmet": "^6.1.0",
"react-lazy-load": "^3.1.13",
"styled-components": "^5.2.1"
},
你能帮我解决我需要做些什么才能让 MDXrenderer 工作吗?我仍然需要弄清楚列表和代码块是如何呈现的。
你把这个问题完全矫枉过正了。您不需要在 gatsby-browser.js
中创建一个实例来“让 MDX 理解”。您的 MDX 运行良好,因为您正在渲染 <ul>
和 <li>
。您只是缺少样式。
在您分享的截图中,可以看到如下内容:
Inherited from ul
ol, ul {
list-style: none;
}
这会使您的列表“看起来像 <p>
”。
您只需要为它们添加正确的样式或删除重置样式。默认情况下,<ul>
有:
display: block;
list-style-type: disc;
margin-top: 1em;
margin-bottom: 1 em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
而 <li>
:
display: list-item;
恢复默认样式后,您的列表标签将保持原样。
我想弄清楚为什么我必须在 gatsby-browser.js 中指定所有 HTML 标签,以便 MDXrenderer 了解如何设置 HTML 标签的样式.
内容来自 GraphCMS 通过 GraphQL 查询。
我一直在研究其他未设置规范的 gatsby 项目,但它们正确呈现 HTML 标签。
我能够定位大多数 HTML 标签,但我无法弄清楚我的“ul”和“li”标签是如何呈现的。例如,我能够定位它们并应用颜色,但在查看时它仍然看起来像页面上的“p”标签。尽管如果您检查该元素,它确实会显示“ul”和“li”标签。
参见下面的示例:
Webpage with inspection
这是我的 gatsby-node.js 文件:
const path = require("path")
exports.createPages = async ({ actions: { createPage }, graphql }) => {
const { data } = await graphql(
`
{
pages: allGraphCmsPage {
nodes {
id
content {
markdownNode {
childMdx {
body
}
}
}
seo {
description
image {
url
}
keywords
title
}
slug
subtitle
title
}
}
posts: allGraphCmsPost(sort: { fields: date, order: ASC }) {
edges {
nextPost: next {
slug
title
}
page: node {
id
author {
id
name
title
}
content {
markdownNode {
childMdx {
body
}
}
}
date: formattedDate
excerpt
seo {
description
image {
url
}
keywords
title
}
slug
title
}
previousPost: previous {
slug
title
}
}
}
}
`
)
if (data.errors) throw data.errors
data.posts.edges.forEach(({ nextPost, page, previousPost }) => {
createPage({
component: path.resolve("./src/templates/article-post.tsx"),
context: {
id: page.id,
page,
previousPost,
nextPost,
},
path: `/articles/${page.slug}`,
})
})
data.pages.nodes.forEach(page => {
createPage({
component: path.resolve("./src/templates/default-page.tsx"),
context: {
page,
},
path: `/${page.slug}`,
})
})
}
exports.createResolvers = ({ createResolvers }) => {
const resolvers = {
GraphCMS_Post: {
formattedDate: {
type: "String",
resolve: source => {
const date = new Date(source.date)
return new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
}).format(date)
},
},
},
}
createResolvers(resolvers)
}
这是我的 gatsby-config.js 文件:
require("dotenv").config()
const path = require("path")
module.exports = {
siteMetadata: {
title: `Code Shape`,
description: `Learn to create great things.`,
author: `@codeshape`,
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/icons`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/logos`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/profiles`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts/`,
},
},
{
resolve: "gatsby-plugin-page-creator",
options: {
path: `${__dirname}/src/posts`,
},
},
`gatsby-plugin-mdx`,
{
resolve: "gatsby-source-graphcms",
options: {
endpoint: process.env.GRAPHCMS_ENDPOINT,
token: process.env.GRAPHCMS_TOKEN,
buildMarkdownNodes: true,
downloadLocalImages: true,
},
},
`gatsby-plugin-styled-components`,
`gatsby-plugin-react-helmet`,
"gatsby-transformer-sharp",
"gatsby-plugin-sharp",
],
}
这是我的 gatsby-browser.js 文件:
import React from "react"
import { MDXProvider } from "@mdx-js/react"
import Layout from "./src/components/layout/layout"
/* eslint-disable */
const components = {
wrapper: ({ children }) => <>{children}</>,
h1: props => (
<h1 style={{ fontSize: "60px", fontWeight: "bold" }} {...props} />
),
h2: props => (
<h2 style={{ fontSize: "40px", fontWeight: "bold" }} {...props} />
),
h3: props => (
<h3 style={{ fontSize: "30px", fontWeight: "bold" }} {...props} />
),
h4: props => (
<h4 style={{ fontSize: "20px", fontWeight: "bold" }} {...props} />
),
p: props => <p style={{ fontSize: "16px", lineHeight: 1.6 }} {...props} />,
strong: props => (
<strong style={{ fontWeight: "900", lineHeight: 1.6 }} {...props} />
),
img: props => <img style={{ width: "100%" }} {...props} />,
pre: props => {
const className = props.children.props.className || ""
const matches = className.match(/language-(?<lang>.*)/)
return (
<Highlight
{...defaultProps}
code={props.children.props.children}
language={
matches && matches.groups && matches.groups.lang
? matches.groups.lang
: ""
}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={style}>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
},
}
const wrapPageElement = ({ element, props }) => (
<Layout {...props}>{element}</Layout>
)
const wrapRootElement = ({ element }) => (
<MDXProvider components={components}>{element}</MDXProvider>
)
export { wrapPageElement, wrapRootElement }
这是我文章的模板-post.tsx 文件:
import React from "react"
import { graphql, Link } from "gatsby"
import Img from "gatsby-image"
import { MDXRenderer } from "gatsby-plugin-mdx"
import styled from "styled-components"
import {
BodyMain,
Caption,
H1,
MediumText,
} from "../components/styles/TextStyles"
import ReactDisqusComments from "react-disqus-comments"
import LazyLoad from "react-lazy-load"
export const pageQuery = graphql`
fragment AssetFields on GraphCMS_Asset {
id
localFile {
childImageSharp {
fluid(maxWidth: 600) {
...GatsbyImageSharpFluid
}
}
}
}
query ArticlePostQuery($id: String!) {
authorImage: graphCmsAsset(
authorAvatar: {
elemMatch: { posts: { elemMatch: { id: { in: [$id] } } } }
}
) {
...AssetFields
}
coverImage: graphCmsAsset(
coverImagePost: { elemMatch: { id: { eq: $id } } }
) {
...AssetFields
}
}
`
export default function ArticlePostTemplate({
data: { authorImage, coverImage },
pageContext: { nextPost, page, previousPost },
}) {
return (
<Wrapper>
<Header>
<PublishDate>{page.date}</PublishDate>
<PageTitle>{page.title}</PageTitle>
</Header>
<InformationWrapper>
<AuthorWrapper>
<AuthorAvatar>
<Img
fluid={authorImage.localFile.childImageSharp.fluid}
fadeIn={false}
className="Image"
/>
</AuthorAvatar>
<AuthorTextWrapper>
<AuthorName>{page.author.name}</AuthorName>
<AuthorTitle>{page.author.title}</AuthorTitle>
</AuthorTextWrapper>
</AuthorWrapper>
</InformationWrapper>
<ContentWrapper>
<Img
fluid={coverImage.localFile.childImageSharp.fluid}
fadeIn={false}
className="CoverImage"
/>
<MDXRenderer>{page.content.markdownNode.childMdx.body}</MDXRenderer>
</ContentWrapper>
<Navigation>
{(nextPost || previousPost) && (
<div>
<hr className="Divider" />
{nextPost && (
<div>
<h2>Next Post</h2>
<div>
<Link to={`/articles/${nextPost.slug}`}>
{nextPost.title}
</Link>
</div>
<hr className="Divider" />
</div>
)}
{previousPost && (
<div>
<h2>Previous Post</h2>
<div>
<Link to={`/articles/${previousPost.slug}`}>
{previousPost.title}
</Link>
</div>
<hr className="Divider" />
</div>
)}
</div>
)}
<div>
<Link to="/articles/" className="">
← Back to the blog
</Link>
</div>
</Navigation>
<LazyLoad offsetTop={400}>
<ReactDisqusComments
shortname="codeshape"
identifier={page.id}
title={page.title}
url={page.url}
category_id={page.category_id}
/>
</LazyLoad>
</Wrapper>
)
}
const Wrapper = styled.div`
margin: 1.875rem;
display: grid;
grid-gap: 1.875rem;
`
const Header = styled.div`
text-align: center;
margin: 0 auto;
`
const PublishDate = styled(BodyMain)`
color: #757372;
`
const PageTitle = styled(H1)``
const InformationWrapper = styled.div`
display: grid;
align-items: center;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
`
const ContentWrapper = styled.div`
display: grid;
grid-gap: 1rem;
margin: 0 auto;
max-width: 80rem;
.CoverImage {
border-radius: 1.25rem;
object-fit: cover;
}
`
const AuthorWrapper = styled.div`
margin: 0 auto;
padding: 1rem;
display: grid;
grid-gap: 1rem;
grid-template-columns: auto auto;
width: 20rem;
justify-content: center;
align-content: center;
`
const AuthorAvatar = styled.div`
.Image {
border-radius: 50%;
border: 3px solid white;
width: 4rem;
}
`
const AuthorTextWrapper = styled.div`
display: grid;
justify-content: center;
align-content: center;
`
const AuthorName = styled(MediumText)`
font-weight: 900;
`
const AuthorTitle = styled(Caption)`
color: #757372;
`
const Navigation = styled.div`
margin: 0 auto;
text-align: center;
padding: 1.875rem;
display: grid;
grid-gap: 1rem;
width: 18rem;
.Divider {
color: #757372;
line-height: 3rem;
}
`
package.json 文件中的依赖项:
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@types/react-helmet": "^6.1.0",
"@types/styled-components": "^5.1.4",
"autoprefixer": "^10.2.3",
"babel-plugin-styled-components": "^1.12.0",
"gatsby": "^2.28.0",
"gatsby-image": "^2.10.0",
"gatsby-plugin-manifest": "^2.8.0",
"gatsby-plugin-mdx": "^1.9.0",
"gatsby-plugin-offline": "^3.6.0",
"gatsby-plugin-react-helmet": "^3.6.0",
"gatsby-plugin-sharp": "^2.13.4",
"gatsby-plugin-styled-components": "^3.9.0",
"gatsby-source-filesystem": "^2.7.0",
"gatsby-source-graphcms": "^2.2.0",
"gatsby-transformer-sharp": "^2.11.0",
"prop-types": "^15.7.2",
"react": "^16.14.0",
"react-disqus-comments": "^1.4.0",
"react-dom": "^16.14.0",
"react-helmet": "^6.1.0",
"react-lazy-load": "^3.1.13",
"styled-components": "^5.2.1"
},
你能帮我解决我需要做些什么才能让 MDXrenderer 工作吗?我仍然需要弄清楚列表和代码块是如何呈现的。
你把这个问题完全矫枉过正了。您不需要在 gatsby-browser.js
中创建一个实例来“让 MDX 理解”。您的 MDX 运行良好,因为您正在渲染 <ul>
和 <li>
。您只是缺少样式。
在您分享的截图中,可以看到如下内容:
Inherited from ul
ol, ul {
list-style: none;
}
这会使您的列表“看起来像 <p>
”。
您只需要为它们添加正确的样式或删除重置样式。默认情况下,<ul>
有:
display: block;
list-style-type: disc;
margin-top: 1em;
margin-bottom: 1 em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
而 <li>
:
display: list-item;
恢复默认样式后,您的列表标签将保持原样。