GitHubのようにMarkdownが書けるようなサイトが増えています。僕の働いているソニックガーデンが使っているオフィスツールRemottyでもMarkdownのような記法を一部サポートしています。
WebでMarkdownを扱うにはMarkdown形式の文字列をサーバーサイドなりクライアントサイドでHTML化して表示するだけなのでとても簡単です。また、 ただのHTMLなのでCSSにより見た目もかなり柔軟に変えることができます。
ではReact Nativeアプリではどうしたらいいだろうか、というのが最近の課題です。実はRemottyのモバイルアプリでちょっとしたマークダウン的なものをどのように表示すべきなのかというのは悩んでいて、現状では開発した当時一番マシかなと思ったものを使っています。
Markdownを表示するためにライブラリ(または標準コンポーネント)を使います。使い方には大きく2通りあって、Markdown文字列のまま処理してくれるものと一度HTMLに変換してHTMLをレンダリングするものとがあります。さらに内部実装でHTMLを表示できるWebViewを使っているのかMarkdownからHTMLにして、そのHTMLの構文解析をしてコンポーネント化しているのか、という分類もできそうです。
ライブラリはこのあたりで検索します。また、Googleでも色々と検索してヒットしたものを使ってみました。
今日は以下の6種類を比較してみます。と言ってもメンテされていなくて最新のRNでは動かないものもあります。一部手元で手直しすれば動いたものもあるので補足しつつ書いてみます。
- Markdownで渡す系
- HTMLで渡す系
前提
Markdownのサンプルとして、いくつかの要素を含んだ次のようなものを考えます。
const markdown = `
# 見出し
- 箇条書き
- 入れ子
- 入れ子
- 箇条書き
- 箇条書き
[Google](https://www.google.co.jp/)
> 引用
**太字太字**
![画像](https://blog.piyo.tech/images/prof.png)
`;
せめてこのぐらいはちゃんと表示してほしいなという気持ちで例文を作りました。
また、HTMLを受け取るコンポーネントがあるため、このMarkdown文字列をmarkedライブラリに食わせてHTML化します。
const html = marked(markdown);
ライブラリの使い方は全部シンプルなのでドキュメントをみてくれれば大丈夫です。特に紹介しません。
また、各ライブラリはそれぞれスタイルの調整はある程度できそうですが、一旦は何も指定しない状態で試しています。
Markdownで渡す系
react-native-simple-markdown
コードが古いせいか使えませんでした。残念。
react-native-showdown
こちらは実はそのままでは警告により正しく描画されません。内部的にReact NativeのWebViewが使われています。最近のWebViewはHTML文字列を使う際にはoriginWhitelist={\\\['\\\*'\\\]}
というプロパティが必要になったため、警告が出ていました。
その箇所を(行儀が悪いですが)ローカルで修正し実行したのがこちらです。
react-native-markdown-renderer
こちらはMarkdownを一度HTMLにパースした後、HTMLのツリー構造を解釈して適切なReact Nativeコンポーネントに置き換えるようなことを(どうやら)やってくれているように見えます。
例えばこのようなコードがあり、link
はスタイル付きのテキストのようなルール付がされています。
// a
link: (node, children, parent, styles) => {
return (
<Text key={node.key} style={styles.link} onPress={() => openUrl(node.attributes.href)}>
{children}
</Text>
);
},
HTMLで渡す系
react-native-htmlview
こちらが現状のRemottyで使っているライブラリです。MarkdownをHTMLにしたあとでReactNativeコンポーネントにするというのは変わらないですが、li
の入れ子などが考慮されていないため残念な見た目になります。
react-native-autoheight-webview
こちらは内部でWebViewを使っており、react-native-showdown
と同様originWhitelist={\\\['\\\*'\\\]}
が必要でした。画像がはみ出るものの比較的いい感じで表示できました。高さを開発者が指定しなくていいのが良いです。
WebView
標準のコンポーネントでも試しました。高さ指定が必要で無指定だと何もヒョ時されません。コンテンツが色々動的に変わるんだとしたら実際に使うのはなかなかに大変そうです。
結論
ここまで比較してみて、今使っているreact-native-htmlview
は相当イケてないなということがわかりましたので、早急に対応すべきな気がしてきましたw
React Nativeのコンポーネントに直してくれるreact-native-markdown-renderer
が良さそうだなという感覚がありますね。うまくコンポーネントにしてくれるならレイアウトが楽になりそうです。
それで難しいのであれば、次点はreact-native-autoheight-webview
でしょうか。MarkdownがHTMLを書くための記法だと思えばWebViewに表示を任せるのは悪くない選択肢かと思います。こちらは速度に課題があるかもしれません。
今回試すにあたり作ったサンプルアプリをGitHubに上げておきました。