はじめに
都内のスタートアップでエンジニアをしています。
この度、絵のSNS的なWebアプリ「画HACK」を開発したので紹介させてください。
このサービスは、私が未経験の頃にRails / Reactで初めて作成したアプリをベースに、3年ほどかけてRuby on Rails / Next.jsで作り直したものです。
当時パフォーマンスが悪すぎて、技術記事を書く前にサービス自体を閉じちゃいました。
ずっと心残りだったのでエンジニアになってから作り直しました(笑)
周りからはまだ作ってるの?と言われ続けてはや3年...機能はミニマムですが最低限形になったので、今回技術記事として紹介しようと思います。
サービスURL
リポジトリ
現状リポジトリ名はサービスには関係ない名称になっています...
追って修正する予定です ![]()
画HACKとは
お題に沿って絵を描き投稿、SNSに共有することでテーマを当ててもらうサービスです。
どんな絵でも額縁に入れて表示されるので、たとえ落書きのような絵でも意外と映えます!
使い方
| 手順 | 内容 |
|---|---|
| 1. テーマを決めて絵を描く | テーマを入力して絵を描けば投稿できます。
|
| 2. SNSに投稿する | メニューからシェアボタンを押すとXに投稿できます。 初回OGPカードの反映には少し時間がかかります🙏
|
| 3. OGP画像からテーマを当てる | 投稿リンクを開くとクイズのモーダルが表示されます。
|
そのほか絵に対していいねをしたりコメントしたりできますが、一部プロフィール設定に関する機能(退会機能など)はまだ機能しませんのでご注意ください ![]()
作成の経緯
きっかけはネットのお絵描き掲示板
平成初期生まれの皆さん、ネットにある絵の掲示板的なWebサービス触ったことありますか?
私も小学生の頃に家のPCでコソコソ1回だけ描いてみたことがあります(笑)
当時の私は親の教育方針から受験勉強に集中せざるを得ない環境で、「絵なんて描いてる暇があったら勉強しろ」という家庭でした。
ただ、小学校の図工の授業で描いた絵は意外と評価が良くて、試しにWebでも描いてみようと思ったら、そのサイトでも上手な絵を描いているユーザーさんにコメントをいただいたんですね。
それが私にとってはとても嬉しく今でも覚えています。
絵を描かなくなった学生〜社会人時代
それからは中学受験も本格化して、また絵を描こうとはならず中学校以降は部活に没頭する普通の学生になります。
高校・大学、社会に出ても芸術の道に挑む勇気なんてあるわけもなく、当時気持ちが昂ったことは見ないようにして過ごしていました。
エンジニア転職を目指す中で思い出した
私大学卒業後は公務員だったんですが7年くらいいてエンジニアを目指します。
エンジニア転職のためにプログラミングを勉強していた時、ポートフォリオ案を考える中でふと当時のことを思い出すわけです。
「どんな絵にも価値がある」と思った
今では絵が特別上手いわけでもなく(むしろ下手という)、芸術の道に進もうとも思っていません。
ただ、環境や進路の都合で本当は好きだったものをどこかに置いてきた感覚を持っている人は意外と多いんじゃない?と思ったりしました。
そんな大人が童心に返って絵を描いてみたら意外と楽しいかもしれない?
そして、どんな下手くそな絵で落書きみたいな出鱈目な絵でも、額縁に入れて飾ると意外と映えるかも。
そんな体験を形にしたくてこのサービスを作りました。
未経験時代に作ったアプリの問題点
今回紹介するサービスも全然高速ではないですが、未経験時代に作ったアプリには大きく2つの問題がありました。
一覧画面のパフォーマンス問題
当時絵の一覧画面の表示速度、めっちゃ遅かったです...
投稿数が100件を超えたあたりから極端に重くなり、ローディングが10秒以上続くこともあるという。
理由は明確でページネーションをAPIで全件取得してからフロント側で分割表示することで対応していました。
当時ページネーションはUI上の表示切り替えくらいの認識しかなかったですが、取得データ量を制御して一定のパフォーマンスを維持する仕組みでもあるなと痛感しております。
Canvasのメモリ問題
もう1つはお絵描き画面でクラッシュが頻発していました。
描画機能はCanvasAPIを利用して実装していましたが、Redo/Undo機能を実装したあたりから不安定になり、ブラウザがよくクラッシュするようになりました。
多分履歴データをlocalStorageに全部保持していたため、メモリ使用量が肥大化したんだと思います(笑)
技術構成
技術記事なので構成も記載します。
構成概要
- フロントエンド: Next.js(App Router)
- バックエンド: Ruby on Rails(API mode)
- デプロイ: Heroku・Vercel
- UI: shadcn/ui
- オブジェクトストレージ: Cloudflare R2
- データフェッチ: TanStack Query(React Query)
フロントエンドは知見が少なかったため、実装時にはbulletproof-reactの構成を参考に実装しました。
UI
UIにはshadcn/uiを使用しています。
コンポーネント単位で直接コピーする設計なので、必要最低限のUIコンポーネントをインストールするという手法を取ればバンドルサイズを抑えられるかなと思いました。
額縁部分はCSSで実装しており、CodePenなどで参考になるデザインを探しながら調整しています。
まだ2種類しか用意できていないので、今後はもう少しバリエーションを増やしたいです...!
認証
認証はGoogleログインのみ対応しています。
メールアドレス認証も検討しましたが、
- 実装コスト
- パスワード管理
- セキュリティリスク
- 運用負荷
などを考慮し、認証方式を増やすよりGoogle認証に一本化する方がシンプルだと判断してそうしました。
画像ストレージ
画像ファイルの保存にはCloudflare R2を利用しています。
無料枠が広く、個人開発規模ではAWS S3よりコストメリットが大きいと感じて推しです🫶
動的OGP画像生成
OGP画像は@vercel/ogを使って動的に生成しています。
個人的にはここが沼りポイントで、OGPカードに表示する絵のURLを取得する処理時間が長く、初回しばらくするまでカードがXにうまく反映・表示されない状態が未だに続きます。
最初は絵のURLをDBから取得してセット、カード専用のCSSを都度生成する方式にしていましたのをやめて、OGP画像を絵の投稿と同時に生成して、OGPのURLをセットするために絵のモデルに専用のカラムを追加しました。
ただ初回はどうしてもうまく表示されず...鋭意改善中です ![]()
これ何が正解か、ほんまわからんす...(誰かいい方法あれば教えてください
)
CI/CD
CI/CDはGitHub Actionsで構築しています。
バックエンド側では、RuboCop・RSpecを自動実行して、デプロイ用ブランチにマージしたらHerokuへ自動デプロイが走るようにしています。
フロントエンド側は現状ESLint・Prettierのみで、テストコードはまだ書けていません。
今後に備えて整備しないとなと思っております...
最後に
数年越しに作り直した思い入れのあるアプリをようやく技術記事として紹介できてよかったです!やっと自分の心残りの一つを供養できた気がします
もし少しでも興味を持っていただけたら、ぜひ触って遊んでもらえると嬉しいです。
そしてもし仲良くなってくださるエンジニアの方いた時のためにXのアカウント置いておきます!
ここまで読んでいただいて本当にありがとうございました! ![]()



