Create personal blog with MDX
Install
npm install @next/mdx @mdx-js/loader @mdx-js/react --save-dev
npm install remark-frontmatter remark-mdx-frontmatter --save-dev
npm install to-vfile vfile-matter --save-dev
npm install remark-sectionize --save-dev
npm install remark-prism
# CodeBlock.jsx
npm install prism-react-renderer --save-dev
next.config.mjs
Beside adding multiple plugins for MDX, this file also sets MDXContent.isMDXComponent = true;
so that you can check if the component is an MDX component or not using Component.isMDXComponent
in your _app.jsx
file.
// next.config.mjs
import createMDX from '@next/mdx';
import remarkFrontmatter from 'remark-frontmatter';
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
import remarkSectionize from 'remark-sectionize';
import remarkPrism from 'remark-prism';
// *** START: Export a DEFAULT object, i.e nextConfig
const nextConfig = {}
// Produce standalone output (For docker)
// -----------------------------------------------------------------------------
// "next start" doesn't generate standalone output.
// Generate standalone output if BUILD_STANDALONE=true.
nextConfig.output = process.env.BUILD_STANDALONE === "true" ? "standalone" : undefined;
// Produce standalone output (For docker)
// -----------------------------------------------------------------------------
// Don't generate map files in production. Generate only if ENABLE_SOURCE_MAP=true.
nextConfig.productionBrowserSourceMaps =process.env.ENABLE_SOURCE_MAP === "true" ? true : undefined;
// Configure pageExtensions to also include *.mdx
// -----------------------------------------------------------------------------
nextConfig.pageExtensions = ['js', 'jsx', 'mdx', 'ts', 'tsx'];
const withMDX = createMDX({
extension: /\.mdx?$/,
options: {
// If you use remark-gfm, you'll need to use next.config.mjs
// as the package is ESM only
// https://github.com/remarkjs/remark-gfm#install
remarkPlugins: [remarkFrontmatter, remarkMdxFrontmatter, remarkSectionize, remarkPrism],
// If you use `MDXProvider`, uncomment the following line.
// providerImportSource: "@mdx-js/react",
recmaPlugins: [() => function transformer(ast) {
// add property isMDXComponent to MDXContent
ast.body.unshift({
type: 'ExpressionStatement',
expression: {
type: 'AssignmentExpression',
operator: '=',
left: {
type: 'MemberExpression',
object: { type: 'Identifier', name: 'MDXContent' },
property: { type: 'Identifier', name: 'isMDXComponent' },
computed: false,
optional: false
},
right: { type: 'Literal', value: true }
}
})
}]
},
})
// *** END: Export
// Merge MDX config with Next.js config
export default withMDX(nextConfig)
Import CSS files in _app.jsx for MDX files
-
Copy ./public/postx/ folder too.
//_app.jsx import { Header } from "@/landing51/Header"; import { Footer } from "@/landing51/Footer"; export default function MyApp({ Component, pageProps, router }) { /** * Show navigation bar everywhere except uri listed in excludeUris. * @param {*} pathname * @param {*} excludeUris e.g. ["/ythumb", "/ssd"]; * @returns */ function showNavigationBar(pathname, excludeUris) { for(const uri of excludeUris) { if(pathname.includes(uri)) return false; } return true; } const excludeUris = [ "/templates/d/", ]; return ( <> { showNavigationBar(router.pathname, excludeUris) && <Header /> } { Component.isMDXComponent ? <> <link rel="stylesheet" href="/postx/_css/markdown7.css" /> <link rel="stylesheet" href="/postx/_css/my-markdown.css" /> <link rel="stylesheet" href="/postx/_css/remark-sectionize.css" /> <Component {...pageProps} /> </> : <Component {...pageProps} /> } { showNavigationBar(router.pathname, excludeUris) && <Footer /> } </> ); }
Import prism CSS style in _document.jsx
//_document.jsx
<link rel="stylesheet" href="https://unpkg.com/prism-themes@1.6.0/themes/prism-coy-without-shadows.css"></link>
Copy custom react components
-
nextjs/components/postx
# Needed for CodeBlock.jsx npm install --save prism-react-renderer npm install --save raw-loader
Copy ./postx to ./pages/
Add "./components/*
, so that you can import components like import { CodeBlock } from "@/code/CodeBlock.jsx";
in your MDX files.
// jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*",
"./components/*"
]
}
}
}
TODOs
- Title not working when building from standalone.
- https://github.com/vercel/next.js/issues/14984#issuecomment-730709331