Closed kripod closed 3 years ago
Heya! 👋
The frontmatter guide shows several ways to do it. Plus it links to a plugin that does what you want I believe!
I’ve followed that guide but haven’t been successful, unfortunately. I cannot even read a simple named export from BlogPostLayout.jsx
, e.g. the title
from the file below:
// BlogPost.mdx
export const title = "Hello, world!";
# Hello, world!
This is my first post.
Then it sounds like something else is going on. This seems next related, or related to your setup. Can you provide more info?
Sure, I’ll set up a reproduction case soon, thank you for helping.
I’ve just set up a minimalistic reproduction case over here.
Following the official Next.js docs, I’ve bootstrapped the application using npx create-next-app
. After that, I’ve made a commit with the following changes:
npm install xdm
next.config.js
file, as suggested by xdm’s readme. Adding "mdx"
to pageExtensions
was also necessary, although it isn’t yet documented here.BlogPostLayout
component with an accompanying hello-world.mdx
filenpm run dev
and then see console outputs on the client and the server when navigating to http://localhost:3000/blog/hello-world.Ah. Your question is about how to pass things to the layout. I missed that.
Here’s how I’d solve that:
import { BlogPostLayout } from "../components/BlogPostLayout"
export const title = "Hello, world!"
export default function Layout(props) {
return <BlogPostLayout {...props} title={title} />
}
...
This makes a lot of sense to me. Should it be different?
Oh I see, thank you!
I’m not sure if it should be any different, but then I cannot use the frontmatter data exported directly, e.g.:
---
title: Hello, world!
---
// Doesn’t get `title` (or `meta.title`)
export { BlogPostLayout as default } from "./BlogPostLayout";
# Hello, world!
This is my first post.
That’s what remark-mdx-frontmatter
does. You can configure it to put everything in a frontmatter
variable or so. and then pass it through just like how I proposed passing title
through
I don’t think xdm should do anything here. It’s how JavaScript works:
// example.js:
var someData = 'whatever'
import SomeComponent from './somecomponent.js'
<SomeComponent />
// somecomponent.js:
export default function SomeComponent(props) {
console.log(props.someData) // undefined
}
I already used remark-mdx-frontmatter
, thanks for the suggestion.
Should I pass meta
as follows when the name: "meta"
option is set with remark-mdx-frontmatter, then?
---
title: Hello, world
---
import { BlogPostLayout } from "../components/BlogPostLayout"
export default function Layout(props) {
return <BlogPostLayout {...props} meta={meta} />
}
# Hello, world!
…
Yep! Or spread it in if you want the top-level keys: {...meta}
. And maybe invert the two just to prefer given props over meta {...meta} {...props}
, if that’s what you want.
Sorry to bump a closed thread but this seems like at least something which should be called out in the docs as a difference from @mdx-js
. The expected behavior is that frontmatter is collected as a local layoutProps
which in turn is passed as spread props to the layout/wrapper component.
If @wooorm believes this behavior is out of scope for xdm
, I can understand (there are a bunch of other differences) but I do think it should be documented. In scope or not, I spent the last couple days implementing it (some ambiguous-to-me estree corner cases notwithstanding). It’s not quite ready for general use but I wanted to get an idea of whether this belongs in xdm
or as a plugin before going much further.
Just to state my perspective on where it belongs: the unified
ecosystem is generally very BYO*, but the MDX ecosystem is much more high level/opinionated/batteries-included, and documented as such.
To the extent that becomes fractured it’s a pretty heavy burden both on documentation and end users trying to discover it. Ideally for my usage, xdm
‘s incompatibilities with @mdx-js
would be limited by technical necessity or with contrib/clear instructions where there’s philosophical/scope differences.
I’m especially sensitive to this because I’m working on a contract where I’ll be handing over maintenance to other devs, and the big elephant in the room for me in this role is whether I can vouch for the maintainability of an xdm
integration when there are unknown discrepancies with the base spec.
I also know that’s a lot to ask of any open source maintainer. To the extent level of effort/time investment is a deciding factor, I’d be happy to offer my help.
as a difference from
@mdx-js
What is the difference here? mdx-js/mdx
doesn’t handle frontmatter.
It doesn’t handle frontmatter, but it does pass your exports to your wrapper:
You’ll also notice that
layoutProps
is created based on your exports and then passed to the wrapper. This allows for the wrapper to use those props automatically for handling things like adding an author bio to the wrapped document.
The relevance of frontmatter is that it typically gets converted to exports in MDX (via plugin), which in turn are passed as props to the component.
@eyelidlessness https://github.com/mdx-js/mdx/issues/742
Well that’s news to me, and a little baffling to say the least. This means anyone importing a given MDX module will have to know about its exports and apply them manually to a default wrapper
, which is not a great authoring experience.
It hasn’t landed in the current release, it looks like it’s targeted for 2.x. I can understand not wanting to implement something that’s essentially deprecated, but maybe a note in the docs would be helpful for others expecting the current/documented behavior? And I’ll plan on open sourcing my solution as a plugin.
Well that’s news to me, and a little baffling to say the least
You might raise a new issue there about it. I don’t know exactly what the reason for the change is.
This means anyone importing a given MDX module will have to know about its exports and apply them manually to a default wrapper, which is not a great authoring experience.
How about this?
import * as AllTheThings from './some-mdx-file.mdx'
import {MyFancyLayout} from './layout.jsx'
var {default: MDXContent, ...props} = AllTheThings
<MDXContent {...props} components={{wrapper: MyFancyLayout}} />
Well that’s news to me, and a little baffling to say the least
You might raise a new issue there about it. I don’t know exactly what the reason for the change is.
Good point, I’ll ask there.
This means anyone importing a given MDX module will have to know about its exports and apply them manually to a default wrapper, which is not a great authoring experience.
How about this?
import * as AllTheThings from './some-mdx-file.mdx' import {MyFancyLayout} from './layout.jsx' var {default: MDXContent, ...props} = AllTheThings <MDXContent {...props} components={{wrapper: MyFancyLayout}} />
🤦♂️ Well that’s a heck of a lot simpler than my convoluted plugin. I don’t know why I keep forgetting namespace imports exist. Thanks! I’ll give that a try soon as I’m back at my desk.
Thank you for creating this library!
I would like to know how to access named (non-default) exports of MDX files via webpack (Next.js) from the rendering component. My main use-case is loading metadata, e.g. title for blog posts and then embedding the latter inside a
<title>
element: