简体   繁体   中英

Import markdown files as strings in Next.js

How can I import markdown files as strings in Next.js to work on client and server side?

You can configure your Next.js webpack loaders to load markdown files and return them as strings, for example:

docs/home.md

# Home

This is my **awesome** home!

pages/index.js

import React from 'react';
import markdown from '../docs/home.md';

export default () => {
  return (
    <div>
      <pre>{markdown}</pre>
      <small><i>Import and render markdown using Next.js</i></small>
    </div>
  );
};

package.json

{
  "name": "example",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "file-loader": "^1.1.6",
    "next": "^4.2.1",
    "raw-loader": "^0.5.1",
    "react": "^16.2.0",
    "react-dom": "^16.2.0"
  }
}

next.config.js

module.exports = {
  webpack: (config) => {
    return Object.assign({}, config, {
      externals: Object.assign({}, config.externals, {
        fs: 'fs',
      }),
      module: Object.assign({}, config.module, {
        rules: config.module.rules.concat([
          {
            test: /\.md$/,
            loader: 'emit-file-loader',
            options: {
              name: 'dist/[path][name].[ext]',
            },
          },
          {
            test: /\.md$/,
            loader: 'raw-loader',
          }
        ]),
      }),
    });
  }
};

When running:

$ npm run dev

Something like this would appear:

示例预览

With the markdown string you can do whatever you would like. For example, process it with marksy .

Just install raw-loader

npm install --save raw-loader

then edit your next.config.js

webpack: (config) => {
  config.module.rules.push({
    test: /\.md$/,
    use: 'raw-loader',
  });
  return config;
},

Quicker and "Next.js way" is to use plugin next-mdx

Documentation: https://github.com/zeit/next-plugins/blob/master/packages/next-mdx/readme.md

// next.config.js
const withMDX = require('@zeit/next-mdx')({
  extension: /\.mdx?$/
})
module.exports = withMDX({
  pageExtensions: ['js', 'jsx', 'mdx']
})

Updates: emit-file-loader not strictly required, raw-loader deprecated in favor of asset modules

Some updates to https://stackoverflow.com/a/47954368/895245 possibly due to newer developments:

  • asset modules superseded raw-loader : https://stackoverflow.com/a/47954368/895245 No need to install any extra packages for that anyomore
  • emit-file-loader does not seem necessary anymore, not sure if it was needed, or if it is for something more specialized

so we can simplify things slightly to:

pages/index.js

import world from '../world.md'

export default function IndexPage() {
  return <div>hello {world}</div>
}

next.config.js

module.exports = {
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    config.module.rules.push(
      {
        test: /\.md$/,
        // This is the asset module.
        type: 'asset/source',
      }
    )
    return config
  },
}

package.json

{
  "name": "test",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "12.2.0",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  }
}

world.md

my md world

Getting it to work from Typescript

Unfortunately boch raw-loader and asset modules require a bit more work from typescript: https://github.com/webpack-contrib/raw-loader/issues/56#issuecomment-423640398 You have to create a file:

global.d.ts

declare module '*.md'

Otherwise the import will fail with:

Type error: Cannot find module '../world.md' or its corresponding type declarations.

Full example:

global.d.ts

declare module '*.md'

pages/index.tsx

import world from '../world.md'

export default function IndexPage() {
  const what: string = 'my'
  // Would fail on build as desired.
  // const what2: int = 'world2'
  return <div>hello {what} {world}</div>
}

next.config.js

module.exports = {
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    config.module.rules.push(
      {
        test: /\.md$/,
        type: 'asset/source',
      }
    )
    return config
  },
}

package.json

{
  "private": true,
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "type-check": "tsc"
  },
  "dependencies": {
    "next": "v12.2.0",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@types/node": "12.12.21",
    "@types/react": "17.0.2",
    "@types/react-dom": "17.0.1",
    "typescript": "4.0"
  }
}

world.md

my md world

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM