カートに入れました

mdxと画像ファイルを同じディレクトリに置きたい[Nextjs]

ルートディレクトリにnext.config.jsを作る このファイルは通常の Node.js モジュールであり JSON ファイルではありません。 Next.js サーバーとビルドフェーズで使用され、ブラウザのビルドには含まれません。 next.config.js

const fs = require('fs');
const path = require('path');

module.exports = (phase, { defaultConfig }) => {
  const POSTS_PATH = path.join(process.cwd(), 'posts');
  const PUBLIC_PATH = path.join(process.cwd(), 'public');
  // 同階層内の画像を取得
  const files = fs.readdirSync(POSTS_PATH);
  // filesから画像だけ抽出
  const images = files.filter((f) => (f.match(/^\w+\.(jpeg|jpg|png|gif|webp)/)))
  // 画像をpublicフォルダにコピー
  images.forEach(image => (fs.copyFileSync(path.join(POSTS_PATH, image), path.join(PUBLIC_PATH, image))))

  return {
    /* ここにオプション設定を書きます */
  };
};

このようにすることによってビルド時にpostsディレクトリの画像がpublicにコピーされる

mdxファイルで画像を呼び出す時

![mdx-image](/1.png#100_100)

のようにすることができる

このままだとposts以下にディレクトリを作った時、その中のファイルは読み込まれない。そこを読み込むようにしたい。

const fs = require('fs')
const path = require('path')

module.exports = (phase, { defaultConfig }) => {
  const POSTS_PATH = path.join(process.cwd(), 'posts')
  const PUBLIC_PATH = path.join(process.cwd(), 'public')
  // コメントアウト↓
  // // 同階層内の画像を取得
  // const files = fs.readdirSync(POSTS_PATH)
  // // filesから画像だけ抽出
  // const images = files.filter((f) => (f.match(/^\w+\.(jpeg|jpg|png|gif|webp)/)))
  // // 画像をpublicフォルダにコピー
  // images.forEach(image => (fs.copyFileSync(path.join(POSTS_PATH, image), path.join(PUBLIC_PATH, image))))

  // 追加↓
  // 再帰的に画像をpublicフォルダにコピー
  CopyFilesRecursively(POSTS_PATH, PUBLIC_PATH)

  return {
    /* ここにオプション設定を書きます */
  }
}

// 追加↓

/**---------------------------------------
 * ・サブフォルダ下位すべての画像ファイル列挙
 *----------------------------------------
 * @param {string} srcpath コピー元のパス
 * ・同期
 * ・戻り値にはposts/以下のパスが入る
 * @return 取得したファイル、ディレクトリの{path:相対パス, isDir:ディレクトリか}を配列で返す
 */
const readSubDirSync = (srcPath) => {
  let result = [];
  const readTopDirSync = ((srcPath) => {
    let items = fs.readdirSync(srcPath)
    items = items.map((itemName) => (path.join(srcPath, itemName)))
    items.forEach((itemPath) => {
      // posts/以下のフォルダ、ファイル名だけ
      const relativePath = itemPath.match(/.+\/posts\/(.+)/)
      result.push({path: relativePath[1], isDir: fs.statSync(itemPath).isDirectory()})
      //再帰処理
      if (fs.statSync(itemPath).isDirectory()) readTopDirSync(itemPath)
    })
  })
  readTopDirSync(srcPath)
  // resultからディレクトリ、画像だけ抽出
  const output = result?.filter((obj) => {
    return obj.path.match(/^\S+\.(jpeg|jpg|png|gif|webp)/) || obj.isDir === true
  })
  return output
}
/**
 * 指定したパス配下のフォルダ、ファイルを同じ構造で再帰的にコピーします。
 * コピー先のディレクトリが存在しない場合、フォルダが作成され、その中にコピーします。
 * 権限不足や容量不足の場合、例外を検知し停止します。
 * @param {string} srcPath コピー元のパス
 * @param {string} destPath コピー先のパス
 */
const CopyFilesRecursively = ((srcPath, destPath) => {
  if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true })
  let targetList = readSubDirSync(srcPath)
  targetList.forEach(node => {
    let newPath = `${destPath}/${node.path}`
    if (node.isDir) {
      if (!fs.existsSync(newPath)) fs.mkdirSync(newPath)
    } else {
      fs.copyFileSync(`${srcPath}/${node.path}`, newPath)
    }
  })
})

これでフォルダもコピーできるようになった

参考