TinyMCEクラウドがマンスリー固定プランだったのだが、2024/5/14から従量課金制に変わったので無料のエディタに切り替えた。そのログを残しておく🦆🦆🦆🦆🦆
詳しく言えないが、従量課金制に変わったことでより高額なプランに移らないといけない状況になったが、そこまでしてTinyMCEを使いたくなかった。
困っている人が海外にもいた
https://iwasherefirst2.medium.com/how-to-selfhost-tinymce-in-vue-270bb53cb4d8
TinyMCE has recently updated their policy. The free cloud version is now only free for the first 1,000 page loads, starting from May 14, 2024. Below is the email I received:
Xにも同様のポスト
TinyMCE 突然の有料化。しかも価格がエグい。
— ミクスローグの人 from キグルミタヌキ (@mixlogue) April 15, 2024
代替エディタ候補
- Quill
- Lexical
- Froala
- Editor.js
- Toast.ui
移行要件
- TinyMCE同等の機能がある
- テーブル
- 画像アップロード
- ソースコード編集
- undo, redo
- etc
- 無料で上記機能が使える
- メンテされてる
検討
- Quill
- テーブルが使えん
- あるけど5年以上メンテされてなくてvu3でバグ起こして使えない
- テーブルが使えん
- Lexical
- オプション機能の実装ハードルが高い
- Froala
- 高い
- Editor.js
- ブロックエディタスタイルなので違う
- Toast.ui
- あくまでマークダウンエディタなので左右中央寄せができない
ということで。全然見つからなかったのだが、1つ探し出した。Jodit
https://xdsoft.net/jodit/
全然聞いたことなかったがFreeプランで一通りやりたいことできるし、定期的にリリースされているので大丈夫そう。
全然ドキュメント充実してないけど笑
実装
vue3にSFCで書いています。あと、jodit v3でやってます。v4だとテーブルのポップアップツールが表示されなかった。
<script setup lang="ts">
import { Jodit } from "jodit";
import { ref, onMounted } from "vue";
import "jodit/build/jodit.min.css";
const editor = ref("editor");
const body = computed({
get: () => props.modelValue,
set: (value) => emit("update:model-value", value),
});
const s3Endpoint = runtimeConfig.public.S3_ENDPOINT;
const joditConfig = {
uploader: {
insertImageAsBase64URI: false,
imagesExtensions: ["jpg", "JPG", "jpeg", "JPEG", "png", "PNG", "webp", "WEBP"],
url: <s3Endpoint>,
method: "POST",
credentials: "include",
buildData: function (formData: FormData) {
return new Promise((resolve, reject) => {
(async function () {
try {
const file = formData.get("files[0]") as File;
if (!file) {
throw new Error("ファイルが選択されていません");
}
const contentType = file.type;
Object.assign(presignedInput, await fetchPresignedURL(contentType.split("/")[1]));
const fields = presignedInput.fields;
// 不要なパラメータを削除
formData.delete("files[0]");
formData.delete("path");
formData.delete("source");
// 署名情報を追加
Object.keys(fields).forEach((key) => {
formData.append(key, fields[key]);
});
formData.append("Content-Type", contentType);
// 最後にファイルを追加
formData.append("file", file);
resolve(formData);
} catch (error) {
reject(error);
}
})();
});
},
isSuccess: function () {
return true;
},
process: function () {
const res = getPostInput();
return {
files: [`/${res.fields.key}`],
isImages: [true],
baseurl: s3Endpoint,
};
},
},
};
onMounted(() => {
const joditInstance = Jodit.make(editor.value, joditConfig);
});
</script>
<template>
<div class="container">
<label for="editor"></label>
<textarea ref="editor"></textarea>
</div>
</template>
- fetchPresignedURL
- s3の署名付きpostするためのurlをとるやつ。自分で実装してね
- https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-s3-presigned-post/
- buildDataで送信用のデータを用意してる
- isSuccessで成功判定してる
- 署名付きpostだとコンテンツ返ってこないからとりあえずなんでも成功にしてる
- ほんとはもっといい方法あるかも
- processでエディタに表示する画像を返してる
あとは作ったコンポーネントをほかで参照してあげるだけ
出来上がりはこんな感じ。
ええやんええやん
細かいoptionはここを参照しておくれやんす
https://xdsoft.net/jodit/docs/options.html
以上。