この記事は 広島大学ITエンジニア Advent Calendar 2020の5日目です。
去年もアドベントカレンダー用に記事を書いたのですが、半年に一度サイトをリニューアルしたい症候群にかかっているため、去年のブログサイトは残念ながらお亡くなりになりました。つまりブログが必要不可欠になったという訳です。そういうことでサイトを新たに作ることを決意しました。
技術選定と仕様
まずどのような技術や仕様にするか決めることにし、以下の基準を満たしたいと決めました。先に書いておきますが、JavaScriptがあまり好きではないです。
- 記事を書く際にコードやデザインをあまり意識したくない
- なるべく様々なことができる技術
- 記事を簡単に移行したい
- お気に入りの言語で(JavaScript以外)
使用技術
以下の技術を使用させていただくことにしました。
自分は音声処理をRustで書いたりしており、それをサイトにも応用できたらなという理由で、Rustを主に使用していきます。
- Tailwind CSS : 自由度と使いやすさが適度であったから
- Yew : Rustであるから
- Actix Web : Rustであるため
仕様
記事の生成方法
- Markdownでmetaデータや内容を記述する
- constでMarkdownの情報を持たせる
- 記事のurlに来た時、Markdownからhtmlを生成して表示
つまり記事が見られた瞬間リアルタイムで、記事が生成されます。
環境構築
開発からデプロイまでの効率や使いやすさを求めて、ずっと環境構築しています。つまり、現在進行形で完成しそうにもないので、今回は割愛します。
開発
情報が少なくいろいろ試行錯誤した場面はあったのですが、今回は特に詰まった部分を共有していきます。
まず、pulldown-cmark
クレートでMarkdownの内容部分(content)を、パースして、HTMLに変換します。
// Markdownの内容部分
let content: &str = markdown.content;
// Markdownをパース
let parser = Parser::new(content);
// 出力結果の型
let mut html_output: String = String::with_capacity(content.len() * 3);
// htmlに変換
html::push_html(&mut html_output, parser);
変換後の型はString
となっています。自分の知る限りYewでは、Virtual DOMのVNodeという列挙型(用途によってはtype Html
の方が望ましい)でなければ、Elementとして認識してくれません。そのため、VNode::VRef(Node)
という型に変更する必要があります。
もう一度書いときますが、javascriptが苦手です。これまで、なるべくjavascriptのフロントは使わずにサーバーサイドやCSSやHTMLで代用し、何とか生きていました。しかしこれが仇となり、とても苦戦することとなりました。
docs.rsでドキュメントを読んでいくと、Node
はweb_sys
クレートの型であり、Node
型に変換するにはElement
型にする必要があり、Element
型を生成するには...
という感じになってしまいました。JavaScriptを使用する人にとっては簡単なのかもしれませんが、Docment
型とか知らない自分にとっては未知の領域で右に行ったり左に行ったりと彷徨いました。最終的にjavascript様の例を参考にさせていただくことで、実装することができました。
// div elementの生成
let markdown_div = web_sys::window()?.document()?.create_element("div")?;
// 生成したdivの内部にMarkdownの内容部分をセット
markdown_div.set_inner_html(&html_output);
VNode::VRef(Node::from(markdown_div))
終わりに
JavaScript様がこんなに面白い操作をすることができる言語だったと知り、偉大だと感じました。あまり好きではないと書いてすみません。
一応この通り基準を満たすサイトを公開することはできたのですが、開発し始めてから数日しか経っていないため、まだまだデザインや他の機能が乏しいです。これから、これ以降の(アドベントカレンダーの)記事や他の機能も追加するので、是非またご覧ください。
最後まで読んでくださり、ありがとうございました。