5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ClojureAdvent Calendar 2023

Day 17

shadow-cljsで自宅LAN向けのWebアプリ作った

Posted at

shadow-cljs使ってなんか作るRTAはっじまるよー

現在15日の金曜夜、計測スタート

スケルトンプロジェクトを作成

shadow-cljsは一から使った事ないのでさっとググって読んでみる
これ良さそうだな

最初のスケルトンプロジェクトはこれでいこう
なりお世話になったが、 shadow-cljs と reagent 入れた所でおわりか

reagentのアップグレード

ついでに GitHubのreagent を見ながら 1.2.0 の最新にしたらclojure-lspにより怒られが発生

Screenshot from 2023-12-16 14-40-58.png

そういや reagent.dom を使ってくださいみたいなのあった気がする。
Examplesを見るとこのような感じで紹介されている事を確認

(ns example
  (:require [reagent.core :as r]
            [reagent.dom :as rd]))

(defn mountit []
  (rd/render [childcaller]
            (.-body js/document)))

r/renderrd/renderに変更するだけだな。

よし通ったし画面も表示される。

Reactを17系にダウングレード

確かに画面は表示されるが、
デベロッパーツールを開くと「この書き方は18系としては古いので新しい書き方に変更してください」とか怒られる

reagentのREADME.mdを確認すると、18系は動かしてなさそう

or by adding Cljsjs React packages to your project:

[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]

Note: Reagent is tested against React 17, but should be compatible with other versions.

17系までしかテストしてません!そんなことある?
Issueを軽く覗いたら「React 18に早く対応してくれ!」みたいなのが複数あったからそのうち対応されそう。

  • tasks
    • GitHubでリポジトリを作る
    • shadow-cljsのプロジェクトを作る
    • reagentを入れる
    • ルーターを入れる
    • re-frameを入れる
    • 自宅サーバーに向けてAjaxを飛ばしてJSONを受け取る
    • Webアプリをガリガリ書く

ルーターを入れる

複数画面でページ遷移出来るものが作りたい
少し調べたら react-router-dom の機能を使って上手く書くサンプルが出てきた

(defn root []
  [:> Router
   [:div
    [:nav
     [:ul
      [:li
       [:> Link {:to "/"} "Home"]]
      [:li
       [:> Link {:to "/about/"} "About"]]
      [:li
       [:> Link {:to "/users/"} "Users"]]]]
    [:> Route {:path "/" :exact true :component Index}]
    [:> Route {:path "/about/" :component About}]
    [:> Route {:path "/users/" :component Users}]
    ]])

シンプルだがダサい、出来れば避けたいな
Next.jsとか流行るわけだ

職場のプロジェクトでスマートに解決してた気がする……
漁ったらaccountant + bidiを併用しているのを見つけた
記述量は増えるけどURLパラメータとかも使えるし頑張ってみるか

こうなった

src/core.cljs
Screenshot from 2023-12-17 11-37-03.png

src/view/views.cljs
Screenshot from 2023-12-17 11-34-22.png

結局の所は力技で全部書く部分があって、
誰が貧乏くじを引くかの違いでしかないようだ

setup-routesの部分はaccountantやbidiの威力が出ててよき
このままいこう

  • tasks
    • ルーターを入れる
    • re-frameを入れる
    • 自宅サーバーに向けてAjaxを飛ばしてJSONを受け取る
    • Webアプリをガリガリ書く

re-frame を入れる

前述で社内のプロジェクトを写経している間に re-frame をついでに入れてしまったが
全体的な流れとしてはほぼ同時に実装するしかなかった

全体的な流れとしてはカマイルカ氏の記事通りにすすめていけばOK
つか、社内のプロジェクトも中身はこの記事とほぼ一緒やんな……

  • event
    • dbファイルのinitialize-db周りは特にお世話になった
    • db値を上書きするeventの存在
  • sub
    • subを定義することでdb値をview内で使う事ができる

急いでいるのでテストやロジックは後でやろう!(死亡フラグ

  • tasks
    • re-frameを入れる
    • 自宅サーバーに向けてAjaxを飛ばしてJSONを受け取る
    • Webアプリをガリガリ書く

自宅サーバーに向けてAjaxを飛ばしてJSONを受け取る

既にWebAPIサーバーだけは用意してある

$ curl http://localhost:13000/novel/favorites | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1112  100  1112    0     0   361k      0 --:--:-- --:--:-- --:--:--  361k
[
  {
    "type": "kakuyomu",
    "id": "16817330662422093388",
    "title": "【第2章開始!】転生チートの空間魔法使いは正体隠して目立ちたい!~国でもトップレベルの美人・美少女パーティに探されてますが、それ俺ですとは言えません~",
    "page": 32,
    "read": 0,
    "novelupdated_at": "2023-11-05T11:03:20.000Z",
    "created_at": "2023-11-05T17:37:10.000Z",
    "updated_at": "2023-11-06T16:48:41.000Z"
  },
  ...以下省略
]

後はAjaxを発射するだけ、JavaScriptにはFetchAPIがあるけど、
それ準拠でシンプルな挙動してくれるライブラリないかなぁ?

これ良さそうやん
shadow-cljsにはjs-awaitってマクロが用意されてて、Promise値を待つという事は超簡単に実装出来るらしい。


あー、でもre-frameの作りが今すぐdb値を更新しろって感じだから、
イベント発行だけして、後はよしなにやってもらう作りと相性悪いんか
だから re-frame を使うならば re-frame-fetch-fxを使った方が良さそう


ん〜………どっちにするかなぁ
re-frame-fetch-fxはたらい回しにされて、
イベント宣言がアホ程増えるからあんま好きじゃないんよなぁ

今回はshadow-cljsのjs-await使ってみたいしそっちにするか
event関連は全てdispatch-syncで実装すればいいんじゃない?

Screenshot from 2023-12-17 22-16-51.png

clojure-lspがマクロを認識出来ずにresが宣言されてないよ!って怒ってるがまぁヨシ

こんな感じで準備しといて……

Screenshot from 2023-12-17 22-18-04.png

Screenshot from 2023-12-17 22-18-51.png

やったぜ

  • tasks
    • 自宅サーバーに向けてAjaxを飛ばしてJSONを受け取る
    • Webアプリをガリガリ書く

感想と懸念点

腰が重くなる理由の導入の箇所を全部何とか出来たので後は実装するだけ、気が楽になった
年内を目標に少しずつ作りこんで行こうかな

ファイルは一応公開しているけど、Ajaxの送信先が非公開のオレオレAPIだから何の参考にもならない気がする……

懸念点としてはこんな感じ

  • CSSのスマートな実装方法を検討・導入
    • SASSを見張って即反映する (leiningenなしで実現出来るのだろうか?)
    • CSS in JSならぬ「CSS in CLJS」 (検索したら結構出てきた)
    • 面倒だから:styleでよくね?
  • ページ遷移
    • 頑張って accountant / bidi を導入したらから多分楽勝でしょう (楽観視)
    • ああ、URLパラメータの取得方法確認してない
  • 同期処理・値変更時の反映
    • dispatch-syncで値を更新しているから、複数のPOSTのAjaxを飛ばして値を更新する所がちと不安
    • re-frameのsubscribeを使っているので問題ないと信じたい

参考資料達

shadow-cljs ユーザーズガイド
https://t-cool.github.io/shadow-cljs-users-guide-ja/docs/UsersGuide.pdf

経緯

ミーティングで「もう12月っすね」「今年のClojureのアドベントカレンダースカスカですね」「みやびさんどうですか?」という話の流れになって

アドベントカレンダーの存在すら忘れ、4年間もサボっていた事に気付く私
「じゃあなんか書きますか」って事で動きはじめた

うーん、Rustで自鯖の強化しようと思ってたんだけどな
同じものを2言語で作ってもしょうがないし別の何かを考えますか


折角Clojureを全社的に使っている会社に勤めているので
ミーティングで相談してみる

自分「やっぱりNode.jsの人間なんで、ClojureScriptでなんか作りたいですね」
自分「まだ shadow-cljs + reagent + re-frame がメジャーなんですかね?」
同僚A「そうみたい、これを超える程の構成は見てないなぁ」
同僚B「ClojureScript や shadow-cljs はトランスパイル後のJSファイルが重いから、もっとネイティブなJSに近いものを生成してくれるものも色々と登場はしているけどね」
自分「へー、とりあえず shadow-cljs でなんか作ってアドベントカレンダーに備えます」

このネイティブに近いJSファイル吐き出してくれるものも
ちらっと気になったのでググってみたものの出てこないのでもういいや

この話題を出した時点でもう12/11、名前とちょっとした使い方くらいしか知らない shadow-cljs の勉強をしないとアドベントカレンダーにはもう間に合わない


でも動機だ、動機が無いと私は何も作れない
12/15の金曜日までは動機の捻出に力を注いできた

最近 BOOX Palma というE Inkのスマホサイズのタブレットを買った
夜寝る時に布団の中へ飛び込んでスマホを眺めるとブルーライトで眠れなくなっちゃうからね
そこで問題が発生したのを思い出した

いつもスマホで読んでいる小説ブラウザとの同期が取れない
これでは布団の中でなろう小説を読んで、いつ異世界転生しても良いようにとの予習が出来ないではないか

なので最近 BOOX Palma は布団の側で転がっているだけになっている
なんとかしようと早数ヶ月、なんとかする日がついにやって来たのだ

そうだ、小説ブラウザを再現すればいいじゃん
これはNext.jsでささっと作ろうと思っていたが
獲物のLiveScriptがすっかりオワコンで言語難民生活してた所だったんだ
これをshadow-cljsでやればいいじゃん。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?