DEV Community

JokeNeverSoke
JokeNeverSoke

Posted on • Originally published at jokens.me on

Adding relative img paths to mdx

I was migrating my blog from Gatsby to Nextjs today (which just migrated from Hexo), and I found that I had problems using relative paths for images.

My stack for MDX rendering was @mdx-js/loader + @next/mdx

My directory structure was as follows:

pages
├── 404.tsx
├── _app.tsx
├── _document.tsx
├── about.tsx
├── api
│   └── atom.xml.tsx
├── friends.tsx
├── index.tsx
├── posts
│   ├── 2020
│   │   ├── 06
│   │   │   ├── build-blog
│   │   │   │   ├── ahei-wechat.png
│   │   │   │   └── index.mdx
│   │   │   └── hello-blogging.mdx
│   │   └── 07
│   │   └── new-short-domain.mdx
│   └── 2021
│   ├── 01
│   │   └── zinit-selective-loading
│   │   ├── index.mdx
│   │   └── pipenv.png
│   └── 07
│   └── mdx-relative-img-import.mdx
├── projects.tsx
└── tags
    ├── [tag].tsx
    └── index.tsx

11 directories, 17 files

Enter fullscreen mode Exit fullscreen mode

I've decided that I would not give up either markdown image syntax nor relative imports in next.js.

So, after a morning of testing, this was what I came up with.

A custom loader to translate markdown syntax:

const replaceAll = require("string.prototype.replaceall");

module.exports = function (content, map, meta) {
  return replaceAll(
    map
    content,
    /\!\[(.*)\]\((.+)\)/g,
    `<NextImage alt="$1" src={require('$2').default} />`
  );
};

Enter fullscreen mode Exit fullscreen mode

and a component to render:

const components = {
  NextImage: (props: any) => {
    return <Image alt={props.alt || "Image"} {...props} />;
  },
};

Enter fullscreen mode Exit fullscreen mode

The fundamental magic here is that the <NextImage /> component actually runs in-place of the mdx file, giving it access to the require().default syntax.

Top comments (1)

Collapse
 
illustrova profile image
Irina Illustrova

Thank you for this solution! It's the only one that worked for me.