📚

【T3 Stack】技術記事をストックして学びの記録を残せるアプリを個人開発しました!

2024/09/29に公開
1

はじめに

ZennやQiitaの記事、後で読もうと思ってつい忘れてしまうことはありませんか?
今回、技術記事を保存して進捗管理ができ、学びの記録を残せるアプリを個人開発しました!
https://tech-stock-app-six.vercel.app/

背景

最近、T3 Stackに関する記事をたくさん投稿してきましたが、応用として実際にアプリを作ってみたいと思っていました。
モチベーションを保ちながら、簡単にできるものを探している中で、「後で読もうと思った技術記事を管理できるアプリがあったら便利」というアイデアをいただき、確かに自分でも欲しいし簡単に作れそう!と思ったのでこのアプリを開発することにしました!

私自身、後で読もうと記事をストックしても結局読まなかったり、内容を忘れてしまうことがよくあるため、感想やメモを残せる機能も追加しました。

サービス紹介

このアプリでは、技術記事やブログ、公式ドキュメントなどのURLを入力して保存できます。
また、todoアプリのように「読みたい」「進行中」「読んだ」のステータスに分類し、進捗管理が可能です。記事ごとに感想やメモを記入でき、後で見返す際に役立ちます。
保存した記事はステータス別に一覧表示され、リンクをクリックすると記事をすぐに読みに行くことができます。読み終わった後はステータスを更新したり、メモを更新することができます。

使い方

まずはGoogleでログインします。

記事のURLを追加します。

ステータスと任意でメモを追加して保存します。

一覧に表示されます。「記事を読む」で保存した記事のページに遷移します。

一覧の切り替えやページネーションの様子です。

「メモを追加」でステータスの更新、メモの更新ができます。

技術スタック

このアプリは、T3 Stackを使って開発しました。
T3 Stackとはsimplicity(簡潔さ)、modularity(モジュール性)、full-stack type safety(フルスタックの型安全)を追求した思想に焦点を当てています。
そしてそれらを実現するために以下6つの技術スタックが採用されています。
✅ Next.js
✅ tRPC
✅ NextAuth.js
✅ Prisma
✅ Tailwind CSS
✅ Typescript

T3 Stackを利用したプロジェクトを作成するためのCLIツールcreate-t3-appが用意されており、簡単に雛形プロジェクトが作れるため、こちらを利用しました。

https://github.com/t3-oss/create-t3-app
https://create.t3.gg/en/introduction

tRPC

tRPCは、TypeScript向けのRPCフレームワークで、TypeScriptの型システムを活用してクライアントとサーバー間の通信を簡単かつ型安全に行うことができます。
バックエンドのAPIで定義された型がフロントエンドで自動的に適用され、開発速度が向上しました。
https://trpc.io/

NextAuth.js

NextAuth.jsを使って、Google認証を簡単に実装しました。認証機能を自分でゼロから作る手間が省け、セキュリティ面も安心できます。
https://next-auth.js.org/

Prisma

Prismaは、データベースに対するORMです。SQLを書く代わりにTypeScriptのコードでデータベース操作ができ、開発の生産性が上がりました。
https://www.prisma.io/

Tailwind CSS

私はCSSがそれほど得意ではないのですが、Tailwind CSSとAIの組み合わせが非常に相性が良く、簡単にモダンなUIが作れました。
プロンプトに「もっとモダンなデザインボタンに修正して!」のようにしつこく「モダンに」を付け加えていたらいい感じのデザインに近づきました(笑)
Tailwind CSSはスタイルと構造が一体となっており、AIに一括で指示しやすいためデザインに時間をかけたくない場合に非常におすすめです。
https://tailwindcss.com/

今まで投稿した関連記事

考えたところ

記事の取得の仕方をどうするか

「すべて」、「読んだ」、「進行中」、「読みたい」のフィルタリングがある中でどのように記事の取得をするのがいいのか考えました。具体的には
①ステータスを切り替えるごとに毎回サーバーサイドにリクエストして記事を取得する
②サーバーから全ての記事を取得してクライアントサイドでフィルタリングする

この2パターンで迷いましたが②を採用しました。
理由としては記事の量が膨大ではないためです。
初期ロード時に記事を全て取得したあとに追加のサーバーリクエストが不要で、クライアントサイドでのフィルタリングの方が高速だからです。

SQLiteからPostgreSQLへの移行

アプリのデプロイはvercel、データベースをホスティングするにあたってはSupabaseの無料枠を使用することにしました。(後々調べたらvercelでもデータベースのホスティングができるっぽかったですが今回はSupabaseにしました。)
データベースは最初create-t3-appのデフォルトのSQLiteを使用していたのですが、SupabaseがSQLiteをサポートしていなかったため、PostgreSQLに移行しました。

移行は割と簡単でSupabase上での登録操作とPrismaのスキーマファイルをsqliteからpostgresqlに書き換えてコマンドを実行するだけでいけました。
https://supabase.com/

その他個人開発関連で投稿した記事

課題・改善

まだまだ改善点はたくさんあるので気になるところから解決していこうと思います。

動作が遅い

現在、アプリケーションの動作が非常に遅く、原因がはっきりしていません。
原因の追求からですがパフォーマンスの勉強をして改善したいと思います。

記事を削除した後リロードしないと更新されない

記事を削除した後、ページを手動でリロードしないと一覧が更新されません。記事削除後にrouter.refresh()を試したり、記事取得のエンドポイントのキャッシュを削除してみたりいろいろ試したのですがうまくいかず...調査中です。

OGPが設定されていないURLでは情報が出ない

このアプリは、保存されたURLからOGPの情報を取得し表示するしくみになっています。
そのため、OGPのdescriptionやimageが設定されていないURLでは、ダミー情報が表示されます。また、タイトルすら設定されていない場合、何も表示されません。今後は、OGPが設定されていない場合でも、何らかの情報を取得して表示できるように改善していきたいと考えています。(例えば、XのツイートなどのURL対応など...)

10/7追記 YoutubeとXのポストも溜められるようになりました!

OGPとXのポストとYoutubeはそれぞれ全く別のAPIを使用しています。
それぞれTwitter OEmbed APIYouTube OEmbed APIです。

OEmbedとは、ウェブ上のコンテンツを埋め込むための標準的なフォーマットで、特定のURLを指定することで、そのコンテンツを他のウェブページに簡単に埋め込むことができる仕組みです。主に、画像、動画、ツイート、音楽などのメディアコンテンツを埋め込むために使用されます。

OGP情報は取得してきて独自のUIで表示しているのに対してXポストとYoutubeはカード埋め込みをしています。

HTMLを表示するのにはhtml-react-parserライブラリを使用しています。
https://www.npmjs.com/package/html-react-parser
記事一覧に全く違う型のデータが入ってくるためTypescriptの型ガードを使用したりしました。
https://typescriptbook.jp/reference/functions/type-guard-functions

さいごに

アプリの開発期間は大まかに2〜3日で、そこから少しずつ修正を加えた結果、公開までに約2-3週間ほどかかってしまいました。今回、データベースのホスティングまで含めてアプリを公開するのは初めてだったので、無事に公開できて嬉しいです!飽きるまではメンテナンスを続けていこうと思います。

T3 Stackは、フロントエンドもバックエンドもTypeScriptで統一して書けるため、Typescriptユーザーとしては開発効率が非常に高く、爆速で個人開発を進めたい方には最適な技術スタックだと実感しています!

まだ至らぬ点はあるかと思いますが、ぜひ使ってみてください!感想などあれば嬉しいです!
https://tech-stock-app-six.vercel.app/

技術書典17にて「T3 Stack」に関する書籍を共同著書で出版するので気になる方はぜひ読んでみてください!
https://techbookfest.org/event/tbf17

Discussion

西川信行西川信行

動作が遅い原因は、恐らく Vercel の Settings > Functions のFunction Regionが原因かと思われます!
Tokyo,Japan(Northeast) - hnd1 に変更すると、改善されるかと思うので試してみて下さい!