-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Multiple MDXs in a Single File #454
Comments
Would love to have some more options like this. Related to this, I attempted to create a plugin to handle this better in mdx-deck v2 by checking for the actual node type instead of using regex/string manipulation, and I ended up having to duplicate a lot of mdx's internals: https://github.com/jxnblk/mdx-deck/blob/1986c65eea267a5edbb51842fac3d126cb162413/packages/mdx-plugin/index.js |
This implements the basic idea of MDXs. Though we still need to figure out how to best handle the layout mechanism. cc/ @ChristopherBiscardi, @jxnblk, @timneutkens --- Related #454
This implements the basic idea of MDXs. Though we still need to figure out how to best handle the layout mechanism. cc/ @ChristopherBiscardi, @jxnblk, @timneutkens --- Related #454
I think this is a really cool idea, but it feels to me like the type of thing that belongs in an extension/plugin/etc rather than in the core. It's a specialized use case, and a dramatic break from normal markdown syntax, where |
This was my immediate first reaction too. That said, I wouldn’t be opposed to something like |
Also, neat thing about MDX is how we can use MD frontmatter. Would a MDX break allow for additional “frontmatter” for the next component? |
Frontmatter wouldn't be affected because in platforms that support it, it's a pre-process step on the input string before the MDX is processed by mdx-js/mdx, so the frontmatter won't hit the mdx parser. |
Interesting, but using |
Hello fellow devs! I have been working on something similar the last days. Allow me to introduce my approach here for discussion: The idea is to parse the MDX file before processing and splitting it into multiple parts that will later be stitched together in one single default export. A thinkable layout of such a file could be: {/* c:how-it-works.main */}
Some MDX here
...
{/* c:start */}
Some more MDX here
... We can then parse the file and split it at the comments, such that const res = {
"some.content.path": function() {
const {Fragment: _Fragment, jsx: _jsx} = arguments[0]
const no = 3.14
function _createMdxContent(props) { /* … */ }
function MDXContent(props = {}) { /* … */ }
return {no, default: MDXContent}
},
"some.other.content.path": function() {
//...
},
//...
};
export default res; For that, we need to enable I already have a working I would therefore like to propose another option on // ...
if (!process) {
process = createFormatAwareProcessors(config).process
map.set(hash, process)
}
if(options.execute) {
options.execute.call(this, value, process, callback)
} else {
process({value, path: this.resourcePath}).then(
(file) => {
callback(null, file.value, file.map)
},
(/** @type VFileMessage */ e) => {
const fpath = path.relative(this.context, this.resourcePath);
e.message = `${fpath}:${e.name}: ${e.message}`;
callback(e);
}
)
}
// ... My "execute" function that I pass to function execute(value, process, callback) {
const splittedFile = value.split(/{[\n\t ]*\/\*\s*c:[\w.\-\\[\d\]]+\s*\*\/[\n\t ]*}/)
splittedFile.shift()
const matchingComments = value.match(/(?<={[\n\t ]*\/\*\s*c:)[\w.\-\\[\d\]]+(?=\s*\*\/[\n\t ]*})/g)
if(splittedFile.length) {
Promise.all(splittedFile.map(async (v, i) => {
const file = await process({v, path: this.resourcePath})
return file
})).then((arr) => {
const objElements = arr.map((file, i) => {
return `"${matchingComments[i]}": function() {
${file.value}
},`
})
const result = `
const res = {
${objElements.join("")}
};
export default res;
`
callback(null, result, arr[0].map)
return result
}, callback)
} else {
process({value, path: this.resourcePath}).then((file) => {
const result = `
export default function() {
${file.value}
}
`
callback(null, result, file.map)
return result
}, callback)
}
} This code can probably be written in a more elegant manner... Looking forward to hearing what you think! |
Using comments is a smart idea. Regexing files and injecting JS-like things as strings seems like a fragile way to go about it though IMO.
If you want to continue discussing this, can you open a new discussion? |
Okey, perfect - here is the new discussion. For my purpose, sadly the For that I am already using an adapted mdx loader, as you can find here and here. |
So is there some way to do this? I am working on a project where there are many files with invididual events. The events have meta data like |
@levino Yes, there is... I implemented a plugin that does so already. https://github.com/frontline-hq/recma-sections |
multiple MDXs in a single file
The wider ecosystem seems to have a need for multiple MDX components sourced from a single file. Consider the following examples.
mdx-deck
mdx-deck uses multiple MDX components from a single file to render a slide deck.
small content
There is a common use case in websites to have multiple blobs of smaller content. I've used some mock content from the Gatsbyjs.org site here to illustrate the point, but pretty much all product sites do this somewhere including
Next
React
Terraform
"Storybook", Documentation sites, and other interesting use cases
MDX is a viable replacement for Storybook story files, but writing a new story example in a new file is a lot of overhead. Additionally, writing a set of examples with code blocks in a single file can result in documented dynamic examples.
Expected behaviour
The behavior I'm proposing is to define a way to load multiple MDX components from a single file. the following small example:
would (conceptually) result in an array of MDX components
This output can then be rendered directly in place of a normal MDX component
Extras
The full suite of MDX functionality should be supported, including layouts, props, exports, etc.
layout
layout is a default export. While it is possible to replace
wrapper
to achieve similar behavior, there are frameworks that don't fully support page-level wrapping components sowrapper
is hard to use on a per-component or page-level basis. For this reason, each component should come with it's own layout. This behaves the same as a regular MDX file.So we end up with the following:
Note that each "default" export is allocated to it's own MDX Component, just like a regular file would be. We can include an extension that allows setting the default layout for a group of MDX content by specially processing the first MDX "file" if it only includes imports and exports.
exports
Exports can exist at the global level as usual, but what happens to local exports? They would be set as properties on the MDX component
example output:
props
MDX components can take props. So can the multi-mdx. The difference is that props given to a multi-mdx component apply to all MDX content. This is clearly illustrated by the proposed result component:
The text was updated successfully, but these errors were encountered: