Nondeterministic Programming Methodology

    @stefanprobst/remark-mdx-next-images
    TypeScript icon, indicating that this package has built-in type declarations

    1.2.0 • Public • Published

    remark-mdx-next-images

    This is a remark plugin to transform local Markdown images into next/image components.

    It basically does what next-image-loader does, but outside of Webpack.

    The following Markdown images

    Will be transformed: ![local example image](./images/image.png 'local example')
    
    Will _not_ be transformed: ![remote example image](https://example.com/image.png 'remote example')

    are converted to

    <Image src={{ src: "/image.12345678.png", width: 200, height: 200 }} alt="local example image" title="local example" />
    
    <img src="https://example.com/image.png" alt="remote example image" title="remote example" />

    How to install

    npm i @stefanprobst/remark-mdx-next-images sharp

    How to use

    Add the plugin to the MDX processor, and make sure to pass in both file path (path) and file content (value) (see vfile). For further details on how to render MDX with Next.js, please see the offical guide.

    // ./pages/index.js
    
    import { compile, run } from '@mdx-js/mdx'
    import withNextImages from '@stefanprobst/remark-mdx-next-images'
    import Image from 'next/image'
    import { useState, useEffect } from 'react'
    import * as runtime from 'react/jsx-runtime'
    
    const markdown = `
    Look at *this*!
    ![local example image](../assets/image.png)
    `
    
    export async function getStaticProps() {
      const result = await compile(
        {
          // Usually, you would pass in the path to the local MDX file here.
          path: import.meta.url,
          value: markdown,
        },
        { outputFormat: 'function-body', remarkPlugins: [withNextImages] },
      )
    
      return {
        props: {
          code: String(result),
          data: result.data,
        },
      }
    }
    
    export default function Page(props) {
      const { code, data } = props
    
      const { default: Content, ...exported } = useMdx(code)
    
      return (
        <main>
          <Content components={{ Image }} />
          <pre>{JSON.stringify(data, null, 2)}</pre>
          <pre>{JSON.stringify(exported, null, 2)}</pre>
        </main>
      )
    }
    
    function useMdx(code) {
      const [mdxModule, setMdxModule] = useState({ default: () => null })
    
      useEffect(() => {
        run(code, runtime).then(setMdxModule)
      }, [code])
    
      return mdxModule
    }
    
    // function useMdxSync(code) {
    //   const mdxModule = useMemo(() => {
    //     return runSync(code, runtime);
    //   }, [code]);
    
    //   return mdxModule;
    // }

    Additional props for next/image, like placeholder can be set by passing a custom Image component via components:

    export default function Page(props) {
      const { default: Content } = useMdx(props.code)
      return <Content components={{ Image: CustomImage }} />
    }
    
    function CustomImage(props) {
      return <Image {...props} placeholder="blur" />
    }

    Images will be copied to a the Next.js public folder. In most cases you will want to specify a specific subfolder with the publicDirectory option, so it can safely by added to .gitignore.

    Cache headers for images served from that directory can be set via Next.js config.

    Frontmatter images

    With the images option it is possible to process additional image file paths which have been added to vfile.data. This is useful to e.g. process a featuredImage frontmatter field:

    import { read } from 'to-vfile'
    import { matter } from 'vfile-matter'
    
    const vfile = read('./post.md')
    /** There are different approaches to parsing frontmatter. `vfile-matter` makes parsed frontmatter accessible on `vfile.data.matter`. */
    matter(vfile)
    const result = await compile(vfile, {
      outputFormat: 'function-body',
      remarkPlugins: [
        [
          withNextImages,
          {
            images(data) {
              return [{ key: 'featuredImage', filePath: data.matter.featuredImage }]
            },
          },
        ],
      ],
    })
    
    expect(result.data.images).toEqual({
      featuredImage: { src: '/image.0a4b47fd.png', width: 200, heigh: 200, blurDataURL: '...' },
    })

    The resulting data shape matches Next.js StaticImageData.

    Other options

    • images (optional): provide additional image file paths
    • publicDirectory (optional): output folder path relative to the Next.js public folder, defaults to /
    • name (optional): component name, defaults to Image
    • assetPrefix (optional): same as Next.js assetPrefix

    Keywords

    none

    Install

    npm i @stefanprobst/remark-mdx-next-images

    DownloadsWeekly Downloads

    4

    Version

    1.2.0

    License

    MIT

    Unpacked Size

    14.8 kB

    Total Files

    5

    Last publish

    Collaborators

    • stefanprobst