Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Tiptapで実現する堅牢で柔軟なエディター開発
Search
kirik
July 22, 2025
Technology
500
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Tiptapで実現する堅牢で柔軟なエディター開発
2025/7/22 に行われたエディター勉強会の発表資料
https://prtimes.connpass.com/event/358977/
kirik
July 22, 2025
More Decks by kirik
See All by kirik
Tiptapで校正機能を作った時に考えたこと
kirik
0
99
Recoil脱却の現状と挑戦
kirik
2
930
Recoilを剥がしている話
kirik
5
12k
Other Decks in Technology
See All in Technology
株式会社シーエーシー エンジニア向け会社紹介資料
cac
0
57k
DEFCON34-Write-up_HYCu-MYCu
daikiokazaki
0
160
AIエージェントを最高のパートナーに育てる方法|評価と判断軸を育てる5つのステップ
koichiaoki
1
150
負債のメタファと2026年 / Debt Metaphor in Agentic Engineering Age 202609 Edition
twada
PRO
9
3.8k
生成AIエージェントを用いた、 手動テスト手順書から自動テストへの 変換手法の検討
magicpod
0
160
絵ではじめるKubernetesセキュリティ
aoi1
4
640
AIを活用するために決めた "やらないこと" - 価値に注目する / Not betting on AI
soudai
PRO
2
540
Slack上でインフラをトラブルシュートする! Agentic Platform Engineeringの第一歩
teru0x1
5
1.8k
Goodbye ShellScript, Hello File-based App
shunsock
0
140
あけおめLINE 傾向とその対策
nasa9084
0
110
10Xに技術的負債をもたらした「2つの境界の歪み」その構造と解消への営み
10xinc
0
2k
SREは、MCPとAutopilotをこう使え!
kazumax55
3
860
Featured
See All Featured
How to Talk to Developers About Accessibility
jct
2
550
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
Abbi's Birthday
coloredviolet
4
10k
Unsuck your backbone
ammeep
672
58k
Documentation Writing (for coders)
carmenintech
77
5.5k
Discover your Explorer Soul
emna__ayadi
2
1.3k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
660
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
450
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
440
Transcript
Tiptapで実現する堅牢で柔軟なエディター開発 2024/7/22 PR TIMES.DEV エディター勉強会 #1 株式会社PR TIMES 桐澤 康平
@kiririLee
ProseMirrorのスキーマを活用したHTMLの正規化 Reactコンポーネントの組み込みと プラグインによる機能拡張 Tiptap の Extension 単位での単体テスト 今日話すこと
ProseMirrorのスキーマを活用した HTMLの正規化
ProseMirror ?? Tiptapの話じゃないの?
TiptapはProseMirrorのラッパー ・ProseMirrorはTypeScriptで実装された WYSIWYGエディターライブラリ ・Tiptapはヘッドレスで React、Vue、Svelte などの モダンなUIフレームワークとの統合を実現している ・TiptapはProseMirrorの概念を一部抽象化しているが、 ProseMirrorの哲学は知っておく必要がある。スキーマもその一つ
Tiptapによる抽象化の例
ProseMirror Tiptap https://tiptap.dev/docs/editor/core-concepts/schema
エディタで最も基本的な機能である 段落機能(p要素)のスキーマ定義 👉 スキーマの定義をしないと段落すら 扱えない エディタで使用するHTMLは 全てスキーマを定義する TiptapはスキーマをExtensionという 概念で抽象化している Paragraph
Extension
contentで子要素に持てるコンテンツを指定 parseHTMLで読み込むHTMLを指定 renderHTMLで出力するHTMLを指定 重要な点 ・ content 指定に違反するコンテンツは破棄される (子要素のタグ消去) ・ 読み込んだHTMLと出力するHTMLを変えることができる
Extensionの概要
実務での適用例
CKEditor から Tiptap へリプレイス ・ jQuery+CKEditorのレガシー実装でバグ修正・機能追加が困難 ・ Tiptapへのリプレイス目的は機能追加であったため、 UIと機能を保ったまま PR
TIMESにおけるエディタの歴史
Tiptapでリプレイス後、リニューアル ・ UIのアップデートに加え、新機能が追加された PR TIMESにおけるエディターの歴史
一 jQuery+CKEditor のエディターを v1 として Tiptapでリプレイスしたエディターを v2 リニューアルにより新機能追加したエディターを v3 3つのエディタが出てきたので整理
Tiptapで2つのHTML構造を扱う必要性 V1 V2 V3 HTMLは同じ 機能アップデートにより HTMLが変わる jQuery+CKEditor Tiptap+React Tiptap+React
v1からv2へのリプレイス時のHTML v2からv3へのリニューアル時のHTML
CKEditor から Tiptap へのリプレイス 前提として、エディターから出力されるHTMLはそのままDBに保存され、 他システム用に加工される CKEditorのHTML メール用のコンテンツ RSS用のコンテンツ
ブラウザ用のコンテンツ
CKEditor から Tiptap へのリプレイス バックエンドの工数削減のためリプレイス後のTiptapから 出力されるHTMLは保つ必要がある CKEditorのHTML メール用のコンテンツ RSS用のコンテンツ
ブラウザ用のコンテンツ バックエンドの実装は変えない TiptapのHTML
CKEditorとTiptapの統合
CKEditorから出力された画像機能のHTML構造
https://prtimes.jp/main/html/rd/p/000001300.000000112.html 公開されたプレスリリースのHTML
https://prtimes.jp/main/html/rd/p/000001300.000000112.html 公開されたプレスリリースのHTML
公開されるプレスリリースのHTMLでは必要ない属性は 消されている ブラウザ用に加工されている
例えば、「data-nheight」属性はメールに必要な情報で欠落すると メールが壊れる。 このようにほかシステムとの依存関係を持った情報が HTMLにはたくさん埋め込まれている。 重要なのは、、、
このHTMLをどうやって読み込み、壊さずにそのまま出力するか?
まずは parseHTML で読み込み CSSセレクタで指定 priorityで 通常の段落機能(pタグ) 読み込みとの競合を 避ける
tagでパースした Elementの子要素が 全て参照できる getAttrs の働き pタグの子要素である imgタグの属性を 取得する
取得した属性は オブジェクトで return getAttrs の働き
そして renderHTML で出力 HTMLAttributesで パースした属性が 受け取れる 元々のHTMLと 辻褄を合わせるために 属性の値を加工する
画像機能で出力するHTML構造を 配列で定義 ちなみにTiptap v3からJSXで定義できる!! span、imgは他のExtensionで 読み込まれていない このExtensionでもパースしてないが 最終的な出力には含められる 細かいけど重要
CKEditor と Tiptap の統合は以上
リプレイス後、リニューアルによる新機能追加
リプレイス後、リニューアルによる新機能追加 ・ v2をβ版としてリリースし、v1を完全廃止してから リニューアルプロジェクト開始 ・ 画像機能に大幅なアップデート ・ メールなど他システムで扱いやすいようにこのタイミングで 画像機能で出力するHTML構造も大幅に変更
画像機能に大幅なアップデート 1種類のみだった画像機能が 7種類に増えた 画像機能で出力するHTMLも 大幅に変える CKEditorで出力していた HTMLとの統合が必要 https://prtimes.jp/main/html/rd/p/000001357.000000112.html
v2とv3で画像機能を統合する ・ v1 から v2 は機能差がなくHTMLを保つだけで廃止が完了 ・ v2 から v3
は機能差があったため、v2 と v3 を同時に 運用する並行期間を設けていた ・ お客様は v2 から v3 へと編集中のプレスリリースを 切り替えることができる ・ よって、画像機能を例にすると v2 の画像機能のHTML構造をv3で 読み込んだ時に v3 の大画像もしくは中画像機能のHTML構造に する必要がある ※ 現在、v2エディターは廃止されており、v3のみ利用可能
v3 の大画像と中画像 大画像 中画像
大画像のHTML構造 ※ 例として src の URL は placeholder を指定
中画像のHTML構造 figure class 属性の --large を --medium に切り替えて区別 ※ 例として
src の URL は placeholder を指定
再掲: v2の画像機能のHTML構造
v2 -> v3 でもスキーマを活用しよう
まずは parseHTML を定義 配列で読み込むHTMLを 複数指定できる v3で出力した画像と v2で出力した画像をどちらも指定 getFigureNodeAttrsFromV2で v3用に属性を統合する
getFigureNodeAttrsFromV2 v2の画像機能で お馴染みの data-nheight属性 などを取得
getFigureNodeAttrsFromV2 v2で取得した属性値によって v3の大画像にするか中画像に するかを決定する --large or --medium を 切り替える
そして renderHTML する このExtensionではfigureの パースのみ行なっている img 要素のパースは他の Extensionで行なっている 0 は
hole といって子要素のパースを 他のExtensionに委ねられる 重要
小要素の img のパースとレンダー
画像機能は全部で4つのExtensionを 組み合わせている div, figure, img, figcaption の4つ ※ 例として src
の URL は placeholder を指定
・ Extensionはそれぞれの単一のタグのみパースしている ・ HTML構造を強制したい! div.pr_img の小要素のみで必ず figure.pr-img__item-large が存在するようにしたい ・ メールなど他システムでも決まったHTML構造を期待しているため
この↓HTML構造を強制したい
スキーマをより堅牢にする
Extensionの Content と Group が役に立つ Content 子要素に持つことができる HTML(Extension)を 定義できる Group
自分がどのExtensionに所属 するかを定義できる
大画像で扱う Extension の Content と Group を定義する
・ SingleImageExtensionは block要素の内側にしか 存在できない ・ 子要素に pr_figure の Extension しか存在
させない (blockの指定は結構広め、トップレベルのDocExtension配下に存在できる 一番外側の div 要素
・ pr_single_image の内側に しか存在できない ・ 子要素に pr_figure_imageと pr_figure_captionしか 存在させない div
要素の子要素である figure 要素
・ pr_figure の内側にしか存在 できない figure 要素の子要素であるimg要素
・ pr_figure の内側にしか存在 できない ・ (Tips) inline* 指定と hole 指定でカーソル入力を
設置できる figure 要素の子要素である figcaption 要素
各Extensionの定義によってHTML構造を強制できる!!
Reactコンポーネントの組み込みと プラグインによる機能拡張
ブログ書きました 📝 プレスリリースのエディターでTiptapを 使って新機能開発をした話 https://developers.prtimes.jp/2024/09/05/developing-new-features-in-editor-using-tiptap-react-typescript/ 詳しくはWEBで、
Tiptap の Extension 単位での単体テスト
ブログ書きました 📝 Tiptapエディターのテスト戦略:Playwright、Vitest Browser Mode、Editorインスタンスを用いたテスト https://developers.prtimes.jp/2025/02/20/press-release-editor-frontend-testing-tips/ 詳しくはWEBで、