chibaqn /
Posts
2022-07-31 01:10:19

Next.js 製ブログで public 以外の場所に画像を配置する

はじめに

Next.js では、静的ファイルを配信する際は public 配下を参照する仕様となっている。

Static File Serving

記事を管理する上ではこれだと不便。Markdown ファイルと同じ階層に画像ファイルを配置したい。

そこで、下記のように Markdown ファイルと同じ階層に画像を配置できるようにした。

_posts
├── hello-world/
│   └── index.md  # 記事
│   └── image.png # 記事に埋め込む画像

実現方法

Next.js製マークダウンブログの画像をMDファイルと同じ階層に置く を参照。

※「build 時に静的ファイルを別のディレクトリへコピーできるプラグイン」を利用して、public 配下に画像をコピーする。

手順メモ

build 時に画像を public ディレクトリにコピーするための設定を追加

プラグインをインストールする。

npm install -S copy-webpack-plugin write-file-webpack-plugin

build 時に「jpn, png」ファイルを public 配下の指定のディレクトリ(public/assets/images/posts)にコピーする設定を追加する。

diff --git a/next.config.js b/next.config.js
index ae88795..04cb118 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,7 +1,26 @@
 /** @type {import('next').NextConfig} */
+const { resolve } = require('path')
+const CopyFilePlugin = require('copy-webpack-plugin')
+const WriteFilePlugin = require('write-file-webpack-plugin')
+
 const nextConfig = {
   reactStrictMode: true,
   swcMinify: true,
+  webpack(config) {
+    config.plugins.push(
+      new CopyFilePlugin({
+        patterns: [
+          {
+            context: '_posts',
+            from: '**/*.{jpg,png}',
+            to: resolve(__dirname, 'public/assets/images/posts'),
+          },
+        ],
+      }),
+      new WriteFilePlugin()
+    )
+    return config
+  },
 }

画像の参照先をコピー先のディレクトリに変更する処理を追加

Markdown ファイル内の「@@imageUrl@@」の文字列をコピー先のディレクトリのパスに置換する処理を記述する。

diff --git a/lib/markdownToHtml.ts b/lib/markdownToHtml.ts
index 1976c7d..6f35c04 100644
--- a/lib/markdownToHtml.ts
+++ b/lib/markdownToHtml.ts
@@ -1,7 +1,8 @@
 import { remark } from 'remark'
 import html from 'remark-html'

-export default async function markdownToHtml(markdown: string) {
-  const result = await remark().use(html).process(markdown)
+export default async function markdownToHtml(markdown: string, slug?: string) {
+  const markdownReplacedImgPath = markdown.replace(/@@imageUrl@@/g, `/assets/images/posts/${slug}`)
+  const result = await remark().use(html).process(markdownReplacedImgPath)
   return result.toString()
 }

呼び出し元も修正する。

diff --git a/pages/posts/[slug].tsx b/pages/posts/[slug].tsx
index d8d47f8..0bbc784 100644
--- a/pages/posts/[slug].tsx
+++ b/pages/posts/[slug].tsx
@@ -37,7 +37,7 @@ export async function getStaticProps({ params }: Params) {
         'tags',
         'content',
     ])
-    const content = await markdownToHtml(post.content || '')
+    const content = await markdownToHtml(post.content || '', post.slug)
     return {
         props: {
           post: {

以上👍

Markdown ファイルでの画像パスの指定方法

下記のように記述することで、画像を参照できる。

![](@@imageUrl@@/image.jpg)

おわりに

「画像ファイルを build 時に public 配下にコピーする」という発想はなかったので、こちら のサイトには感謝したい。

今後運用していく中で下記の問題が発生したら、ローカル画像はやめてリモートの画像サーバーを移行するなどの対策を打つ。

  • 画像の数が増えていけば、それだけコピーにかかる時間も増えるので、build 時間が増加する(はず)。