はじめに
こんにちは、フロントエンドエンジニアの森茂です。
microCMSにはMarkdown専用のエディターは用意されていないため、Markdownの情報を入稿したい場合はMarkdown記法が利用できるリッチエディターを利用する必要があります。ただし登録したデータはリッチエディターの形式に変換されてしまうため、Markdownのまま入稿データの管理を行うことはできませんでした。
しかしながらmicroCMSには拡張フィールド(旧iframeフィールド)というものがあり、自身で用意する必要はありますがオリジナルのアプリケーションを拡張フィールド内で開き、各種データを共有することが可能になっています。
今回はMarkdownでデータを管理したい方向けに、microCMSの拡張フィールドを利用したMarkdownエディターの利用例をご紹介します。
拡張フィールドについて
拡張フィールドの活用方法の例としては、Google MapsやAmazonの書籍データと連携した例などが公式ブログにも掲載されています。拡張フィールドの仕様などについてはこちらも参照ください。
拡張フィールドから利用するMarkdownエディターを用意する
拡張フィールドはiframeを経由してローカル環境またはWeb上のアプリケーションとデータを連携する仕組みになっています。まずはMarkdownエディターをローカルの開発環境で用意し、microCMSの管理画面からローカル環境を利用するよう準備をします。
今回はNext.jsと実装方法もシンプルでNext.jsに対応しているMarkdownライブラリであるMarkdown Editor for Reactを利用してMarkdownエディターアプリケーションを用意します。
Next.js v13のインストール
$ npx create-next-app@latest --ts
必要なライブラリのインストール
Next.jsでMarkdown Editorを動かすにはライブラリ@uiw/react-md-editor
の他にnext-remove-imports
のインストールと設定の追加が必要となります。公式のドキュメントを参考に実装します。
$ npm install next-remove-imports @uiw/react-md-editor
next-remove-imports
の設定をnext.config.js
に追記します。
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
};
const removeImports = require("next-remove-imports")();
module.exports = removeImports({
...nextConfig,
});
あわせてmicroCMSの拡張フィールドを手軽に利用できるmicrocms-field-extension-react
をインストールしておきましょう。
$ npm install microcms-field-extension-react
これで事前の準備は完了です。
Next.jsでMarkdownエディターを実装する
Next.jsでMarkdown Editor for Reactを利用するにはDynamic importを利用する必要があります。またmicrocms-field-extension-react
を利用してmicroCMSの拡張フィールドとデータの連携ができるようにします。
// pages/index.tsx
import { useEffect, useState } from "react";
import dynamic from "next/dynamic";
import { useFieldExtension } from "microcms-field-extension-react";
import "@uiw/react-md-editor/markdown-editor.css";
import styles from "../styles/Home.module.css";
// Markdown Editor for ReactはSSRで利用できないためdynamic importで読み込む必要がある
const MDEditor = dynamic(import("@uiw/react-md-editor"), {
ssr: false,
loading: () => <div>initializing...</div>,
});
// 利用しているmicroCMSのURLを設定
const origin = "https://xxxxxx.microcms.io";
const IndexPage = () => {
const [markdown, setMarkdown] = useState<string | undefined>();
// microCMSのフィールド拡張を利用するためのhook
const { data, sendMessage } = useFieldExtension("", {
origin,
height: 540,
});
useEffect(() => {
if (!markdown) {
setMarkdown(data);
}
}, [data, markdown]);
return (
<div data-color-mode="light" className={styles.container}>
<MDEditor
value={markdown}
onChange={(value) => {
setMarkdown(value);
sendMessage({
data: value,
});
}}
height={540}
textareaProps={{
placeholder: "Please enter Markdown text",
}}
/>
</div>
);
};
export default IndexPage;
動作の確認
これで準備は完了です。ローカル環境で開発サーバーを起動します。Next.jsのデフォルト設定ではhttp://localhost:3000
でサーバーが起動します、この設定がmicroCMSのAPIスキーマと同じ値になっているかをあらかじめ確認しておいてください。
$ npm run dev
開発サーバーが問題なく起動できたらmicroCMSからコンテンツ投稿画面を開いて確認してみましょう。左側にMarkdown記法で記載すると右側にリアルタイムでプレビューが表示されるはずです。
もし、下記のような画面になってしまった場合はmicroCMSの管理画面とローカルサーバーとうまく通信ができていない状態です。起動状況やポート番号など確認してみてください。
これでMarkdownで投稿、編集ができるようになりました。API取得側でもそのままMarkdownのデータが取得できるので好きなようにスタイルを調整して利用してみてください。
Cloudflare R2を利用した画像の投稿
Markdownでの入稿環境ができたところで、どうせなら画像もドラッグ・アンド・ドロップで投稿したいですよね。AWS S3と互換性のありさらに通信量が無料なCloudflare R2へアップロードできるように拡張していきます。なお、事前にCloudflareのアカウント作成が必要となります。
Cloudflare R2の無料枠
- 10GB/月
- 書き込み 100万リクエスト/月
- 読み取り 1000万リクエスト/月
Cloudflare R2バケットの準備
CloudflareのダッシュボードからR2のバケットを新規に作成します。
バケットは外部から閲覧可能な状態にする必要があるのでパブリックアクセスを許可し公開バケットURLを取得する必要があります。またNext.jsからAWS-SDKを利用してR2バケットへファイルをアップロードするためS3 APIもメモしておいてください。
アクセスを許可を押下すると公開バケットURLを取得することができます。
Cloudflare R2 APIトークンの取得
さらにAPIへ接続するためのトークンを取得する必要があります。
アプリケーションから書き込む必要があるため編集権限を設定します。
作成完了後アクセスキーIDとシークレットアクセスキーが表示されるので忘れずにメモしておいてください。この画面を閉じると再表示することはできません。
これでR2バケットの準備は完了です。次にアプリケーションを拡張していきます。
画像アップロード機能の実装
必要なライブラリのインストール
R2バケットへのアップロードへaws-sdk
を利用します。また画像ファイルのパース処理のためにformidable
を、画像ファイルをユニーク名に変更するためにcuid
を利用します。
npm install @aws-sdk/client-s3 formidable cuid
npm i --save-dev @types/formidable
環境変数の用意
Cloudflare R2バケット名やAPI、トークンなど各種シークレットを.env.local
ファイルに記載しておきます。
NEXT_PUBLIC_MICROCMS_ORIGIN=https://xxxx.microcms.io
# Cloudflare R2
NEXT_PUBLIC_R2_BUCKET_URL=https://xxxxxxxxxxxxxxxxx.r2.dev
NEXT_PUBLIC_BUCKET_NAME=xxxxxxxxxxxxxxxx
R2_ENDPOINT=https://xxxxxxxxxxxxxxxxxx.r2.cloudflarestorage.com
R2_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
R2_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Next.jsアプリケーションへの実装
R2へのアップロードにはMarkdownエディタへ画像ファイルをドラッグ・アンド・ドロップした際にNext.jsのAPI routeへアクセスし画像ファイルをアップロードするよう実装を行います。pages/index.tsx
、pages/api/upload.ts
、utils/fileUploader.ts
、utils/insertToTextArea.ts
、utils/onImagePasted.ts
に作成して実装を行っています。
MDEditorコンポーネントにonDrop
を追加しファイルの処理を行っています。その他詳細についてはソースコードのサンプルをご確認ください。
// pages/index.tsx
onDrop={async (event) => {
event.preventDefault();
await onImagePasted(event.dataTransfer, setMarkdown);
}}
サンプルコード
https://github.com/himorishige/microcms-iframe-markdown-example
動作の確認
管理画面から画像ファイルをドラッグ・アンド・ドロップで配置してみるとカーソルの位置に画像を挿入することができるようになります。また画像のURLにはR2の公開URLが設定されており、画像ファイルも公開できるようになりました。なおファイル名はcuid
を利用したユニークな名称となるため常に新しい画像としてアップロードされます。一度アップロードした画像はパブリックに公開されるため削除したい場合はR2のダッシュボードから削除する必要があります。
APIのレスポンス
microCMSのコンテンツAPIからのレスポンスは下記のようになります。今回ですとmarkdown
というフィールド名にしているので少々紛らわしいですがmarkdown
の値にmarkdown形式がテキストとしてそのまま入ります。これらをフロント側では好きなように処理して活用できると思います。
{
"contents": [
{
"id": "ak_5p9k1s",
"createdAt": "2022-11-22T07:43:31.569Z",
"updatedAt": "2022-11-22T09:50:59.981Z",
"publishedAt": "2022-11-22T07:43:31.569Z",
"revisedAt": "2022-11-22T09:50:59.981Z",
"title": "Markdown",
"markdown": "# test\n\n- list\n- list\n\n![](https://pub-de421d74e6014b45aadb354a19610d9e.r2.dev/images/clas0us8c00003b6q43xhqml3.webp)\n"
}
],
"totalCount": 1,
"offset": 0,
"limit": 10
}
さいごに
いかがでしたでしょうか、拡張フィールドの活用方法の1つの例としてMarkdownの入稿環境をご紹介しました。
今回の実装では個人環境で利用することを想定しているためこのままでは誰でも画像が投稿できてしまったり、ファイル容量の制限などバリデーションもほとんどありません。ただ外部サーバーへ公開をしなくても投稿する関係者にはDockerコンテナとして配布し運用するといった方法なども考えられると思います。microCMSの拡張フィールドを利用した1つの運用アイデアとしてぜひ活用してみてください。