The problem is quite similar to what has been described in the #8857 issue. I want to use the front-matter in my markdown files to export any meta data. Currently we can export a variable from mdx files e.g.
export const meta = {}
In this post we will ....
and it will work. But that is more of a tech heavy solution. Writing that meta data in frontmatter would be much helpful for non-techy people to write blogs. That is the first part.
Next, what I want is to add some custom properties like short info, time to read, formatted published date to each markdown based on it's content i.e. assume that we have following markdown file
---
title: 'My Blog'
date: '2020-12-12'
---
In this post we will ....
Expected output (input for @mdx-js/loader after processing with my custom logic) after formatting date, calculating time to read based on content, adding a description like so
export const meta = {
title: 'My Blog',
displayDate: 'December 12, 2020',
description: 'In this pos',
timeToRead: '2 min read'
}
In this post we will ....
And the blog writer doesn't need to care about it.
This can be easily accomplished if we can just provide a plugin option to take loaders for webpack i.e.
module.exports = (pluginOptions = {}) => (nextConfig = {}) => {
const extension = pluginOptions.extension || /\.mdx$/
+ const loaders = plugionOptions.loaders || []
return Object.assign({}, nextConfig, {
webpack(config, options) {
config.module.rules.push({
test: extension,
use: [
options.defaultLoaders.babel,
{
loader: '@mdx-js/loader',
options: pluginOptions.options,
},
+ ...loaders
],
})
and when using the @next/mdx plugin, on will just have to pass the loaders (optional)
module.exports = require("@next/mdx")({
+ loaders: [],
})( .... )
Currently I am using the above code snippet loaded via a custom nextjs plugin. see here
module.exports = require("@next/mdx")()( .... )
module.exports = require("./my-plugin")()( .... )
I can create a PR if this feature may be useful to the community.
Adding this would conflict with future plans, so it's unlikely we'll add it.
Alright. Thank you.
Do you think we can add a loader to the webpack for the /.mdx?$/ extension and it would work. i.e.
modules.exports = require("@next/mdx")()({
webpack() {
config.module.rules.push({
test: /\.mdx?$/,
use: [
path.join(__dirname, './frontmatter-loader'),
],
})
}
})
I have no idea.
you can create a custom implementation, but you could also write a MDX plugin that converts frontmatter to export const meta
Oh.. okay. Then I'll do that only and pass my plugin to the @next/mdx's pluginOptions. Hope it's is not too tough to write a mdx plugin 馃槃
Thank you again.
I could not found any library that would fit my need out of box, so here is the custom plugin that I wrote. It may be useful to anybody else stumbling over this issue.
I figured out even a bit shorter solution using remark-frontmatter (note: you have to use version 2):
// next.config.js
const yaml = require('yaml');
const frontmatter = require('remark-frontmatter');
const exportFrontMatter = () => (tree) => {
if (tree.children[0].type === 'yaml') {
tree.children.push({
type: 'export',
value: `export const frontMatter = ${JSON.stringify(
yaml.parse(tree.children[0].value)
)}`,
});
}
};
const withMDX = require('@next/mdx')({
extension: /\.mdx?$/,
options: {
remarkPlugins: [frontmatter, exportFrontMatter],
},
});
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'md', 'mdx'],
});
Actually I came up with a way how to read the front matter from parent component (e.g. layout), working for me so far:
// next.config.js
const yaml = require('yaml');
const remarkFrontmatter = require('remark-frontmatter');
const exportFrontMatter = () => (tree) => {
if (tree.children[0].type === 'yaml') {
tree.children.push({
type: 'export',
value: `export const frontMatter = ${JSON.stringify(
yaml.parse(tree.children[0].value)
)}`,
});
}
};
const appendFrontMatter = () => (tree) => {
if (tree.children[0].type === 'yaml') {
tree.children.push({
type: 'export',
value: `MDXContent.frontMatter = frontMatter;`,
});
}
};
const withMDX = require('@next/mdx')({
extension: /\.mdx?$/,
options: {
remarkPlugins: [remarkFrontmatter, exportFrontMatter, appendFrontMatter],
},
});
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'md', 'mdx'],
});
After that, you can just read the value in _app.js for example:
const { title } = Component.frontMatter;
Most helpful comment
I could not found any library that would fit my need out of box, so here is the custom plugin that I wrote. It may be useful to anybody else stumbling over this issue.