bon now

ありのままの現実を書き殴る吐き溜め。底辺SEの備忘録。
Written by bon who just a foolish IT Engineer.

ブログの投稿にCloudinaryとDecap CMSを導入した

Created Date: 2025/03/07 00:49

はじめに、このブログはMiddleman出できていて、Vercelにデプロイしている。
そしてソースコードはBitbucketで管理している。

背景

バイクや日常のことを書こうと思うとわりと画像をアップロードを使うことが多くなると思う。MiddlemanをVSCodeで開いてマークダウン記法で書いていた自分にとって、画像をアップロードして加工してpublicフォルダに入れてURLリンクを書いて……という手間がとても煩わしかった。

また、Vercelにデプロイしている都合上合計の静的ファイルサイズは10MB以下にする必要がある。こうなると適当に画像をアップロードするわけにはいかないため、今まで画像を使った記事を書くことはあまりなかった。

AIに相談

最初は「自分で作るか」と思ったのだが、最近では賢いAIが手元にいるわけで、早速すでに同じような状況の解決策を提案している事例がないか相談してみた。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
質問:
静的サイトジェネレーターでWeb二公開するのは簡単なのですが、記事を作るのにもう少しリッチなエディタがあると嬉しいんです。
例えば画像を添付したら勝手にS3やCloudflareR2にアップロードしてURLを取得してくれるみたいな。
そういうツールなにかありますか?

----------------------------------------------------------
AIの回答:

静的サイトジェネレーターと連携して使えるリッチなエディタをお探しですね。特に画像アップロード機能があり、S3やCloudflare R2に自動的にアップロードしてくれるようなツールについてご紹介します。

以下のようなツールがあります:

Netlify CMS - 静的サイトジェネレーター(Hugo、Gatsby、Jekyll等)と連携でき、画像アップロードをNetlifyのCDNやお好みのストレージプロバイダーに設定可能です。
Forestry.io (現在はTinaに移行) - GitベースのCMSで、S3などへの画像アップロードをサポートしています。
Tina CMS - Forestryの後継で、Reactベースの直感的なエディタとS3連携機能があります。
Decap CMS (旧Netlify CMS) - オープンソースで継続開発されており、様々なストレージバックエンドをサポート。
Strapi - ヘッドレスCMSとして人気で、S3やCloudflare R2などの画像アップロード先をプラグインで柔軟に設定できます。
Contentful - 大規模プロジェクト向けで、画像管理が充実しています。
Cloudinary + 任意のエディタ - 既存のエディタと組み合わせて使用することも可能です。
これらのツールは静的サイトジェネレーターと連携して、記事執筆とメディア管理をよりスムーズにしてくれます。具体的にどのような静的サイトジェネレーターをお使いか、他に必要な機能があれば、さらに絞り込んだ提案ができます。

期待通り、素晴らしい数の案を出してくれた。

とりあえずブログを運営するうえで、(大変恐縮だが)1円もサービスにお金払わずに済む方法を検討し、今回の「Cloudinary」 + Decap CMS を選択した。
というのもDecap CMSはデフォルトでCloudinaryの画像アップロードと、Middlemanでのローカルサーバーに対応していたからだ。

やり方

公式マニュアルにも書いているとおりに作業する。

Decap CMS Middleman
Decap CMS Cloudinary

  1. 既存のmiddlemanの source ディレクトリに admin ディレクトリを追加し、index.htmlとconfig.ymlを作成
  2. Cloudinaryに登録しAPIキーやオプション設定を admin/config.yml 二追記
  3. 編集時は2つターミナルを開き、片方で bundle exec middleman server 、もう一方で npx decap-server を実行
  4. http://localhost:4567/admin/#/collections/blog にアクセス
  5. これだけである。以下に自分の場合の設定について記述しておく。

    admin/index.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    <!doctype html>
    <html>
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Content Manager</title>
        <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
      </head>
      <body>
        <script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
      </body>
    </html>
    

    admin/config.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    
    backend:
      name: git-gateway
      branch: materialize
    
    # ローカル開発用の設定
    local_backend: true
    
    media_folder: "source/images/uploads"
    public_folder: "/images/uploads"
    
    # 画像のアップロード先
    media_library:
      name: cloudinary
      config:
        cloud_name: <Cloudinaryのプロジェクト名>
        api_key: <CloudinaryのAPIキー>
        default_transformations:
          - - fetch_format: auto
              width: 300
              crop: fill
              quality: auto
    
    collections:
      - name: "blog"
        label: "bon10 now"
        folder: "source/post/"
        extension: .html.markdown # 既存のファイル拡張子に合わせる
        format: frontmatter
        create: true
        slug: "{{year}}/{{month}}/{{slug}}" # 既存の記事のディレクトリ形式に合わせる
        path: "{{year}}/{{month}}/{{slug}}"
        fields: # 既存のフィールドに対応させる。config.rbをAIに貼り付けて聞くとOK
          - { label: "タイトル", name: "title", widget: "string" }
          - {
              label: "日付",
              name: "date",
              widget: "datetime",
              format: "YYYY-MM-DD HH:mm",
              date_format: "YYYY-MM-DD",
              time_format: "HH:mm",
              picker_utc: false,
            }
          - {
              label: "カテゴリー",
              name: "category",
              widget: "string",
              required: false,
            }
          - { label: "タグ", name: "tags", widget: "list", required: false }
          - {
              label: "アイキャッチ画像",
              name: "image",
              widget: "image",
              required: false,
            }
          - { label: "本文", name: "body", widget: "markdown" }
          - { label: "公開", name: "published", widget: "boolean", default: true }
    

    これでとても記事の編集が楽になった。今後は画像を使った記事も作っていきたいと思う。手始めに、新たにバイクを買ったのでそれの話を書いていきたい。

local_offer
folder blog