4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js14でプレイリストアプリ作ってみた話

Last updated at Posted at 2024-02-19

はじめに

色々と忙しくてNext14のキャッチアップができていなかったのでそれを兼ねてちょっとしたアプリを作ってみようと作りました。
最初にハッカソンで原型を作ったためアーキテクチャはこうしたほうがよかったななどの思い入れもありますがその辺りはご愛嬌。
サイト: https://scp-log.vercel.app/
GitHub: https://github.com/yoshi-non/scp-log

image.png
image.png

アプリ概要

Youtubeの動画を検索してその動画をプレイリストに追加して再生できる一般的な再生アプリ。
オフライン環境への音声ダウンロードも可。
※プレイリストのデータは全てローカルストレージに保存されます。

環境

Next.js: 14.1.0
Node: 18.17.0

フォルダ構成

├ api // Next.js環境で作成できなかったapi
├ src
│ ├ app // Next.jsのルーティング
│ ├ components // コンポーネント
│ │ ├ features // 特定の機能を実現するコンポーネント
│ │ │ ├ sample // サンプルコンポーネント
│ │ │ │ ├ hooks // サンプルコンポーネントのみで使用するhook(不要な場合もある)
│ │ │ │ ├ logics // サンプルコンポーネントのみで使用するロジック(不要な場合もある)
│ │ │ │ ├ tests // テスト専用
│ │ │ │ ├ index.tsx // エントリーポイント
│ │ ├ functions // UIとして表示されないコンポーネント
│ │ ├ ui // UIコンポーネント,shadcn/uiで使用
│ ├ constants // 全体に共通の定数ファイルを配置する
│ ├ libs // ライブラリのラッパーや使いまわしやすいようにする
│ ├ types // 全体に共通の型定義ファイルを配置する
│ ├ utils // 使い回すロジックなど

理想としてはsrc配下にapi層のapiフォルダを作成したかったのだがデプロイするvercelの環境と使用するapiの性質からsrcと同じディレクトリに存在する。
app下のAPI Routeのフォルダ名をapiにしてしまうとvercelで使用するapiと名前が重複しまい、API Routeは動かなくなります。ルートのapiフォルダはフォルダ名をapi以外にするとvercelで動かないです。
ここではAPI Routeをapisというフォルダ名にして回避しています。
※api(apis)フォルダが複数存在するかの詳細は関連動画検索で説明

shadcn/ui

shadcn/uiは使ってみたかったので導入した。
MUIみたいな「らしさ」がないのとカラーテーマの設定や作るのが面倒なResizableを簡単に実装できたりするところには感動した。ライト・ダークではデフォルトでローカルストレージにデータを保存までやってくれるのでかなり助かる。
一方でDialogは若干コードが煩雑になってしまうところだったり最近できたDrawerは部分的な幅で使えるものがあったらいいなと感じた。

今回話すこと

Google Analytics

基本的に上記のサイトを使えば簡単に導入できたが開発当初はNext14.0.4であったが14.1.0にバージョンを上げる時にビルドエラーでuseSearchParams() should be wrapped in a suspense boundaryのように出てしまうので以下のようにGoogleAnalyticsタグをSuspenseタグで囲えばエラーは消える。

layout.tsx
<head>
    <Suspense>
        <GoogleAnalytics />
    </Suspense>
</head>

導入も手軽で以下の画像のように初心者でもわかりやすくデータが見える。

image.png

image.png

ドラッグアンドドロップ

640x400画面収録

React 18に対応していることと現在伸びてることを加味して@dnd-kit/coreを採用

image (2).png

細かい使い方は省くが簡単に言えばDndContextWrapperでドラッグ&ドロップを反映させたい箱を用意してSortableItemWrapperで移動させたいものをラッピングして使用する。

関連動画検索

動画を検索して追加する分には簡単なのだがYoutube Data APIには関連動画の検索APIなるものは存在しないので自作する必要があった。

処理の流れ

  1. プレイリストに存在する動画タイトルを形態素解析して頻繁に使われている単語を検索する
  2. 頻繁に使われている単語を繋げて検索APIにかける

日本語の形態素解析には代表的にMeCabKuromojiがあるが今回はNext.jsで作っている観点からNodeの資料が多いKuromojiを採用。

ぶちあたった問題

APIを作る段階でNext.jsのAPI Routeで./node_modules/kuromoji/dictというパスがvercelでは認識されないというエラーに遭遇した。調べてみるとvercelはNext.jsを用いたgzipファイルをサポートしていないということらしいのでsrcと同ディレクトリにapiフォルダを作成して無理やり動かすことにした。
ただしこれはvercel環境でしか動かないためローカル環境は別で作る必要があるためapiファイルを2つ作る必要がある。

npm run dev or npm run buildで動くapiファイル

vercel dev or 本番環境で動くapiファイル

オフラインダウンロード

やっぱりオフラインでも使えたらいいなという思いがあったのでオフラインダウンロードにも挑戦。

しかしながら以下の流れで音声だけのダウンロードしかできなかった。

  1. YoutubeのダウンロードAPIには高画質(1080p)の動画と音声が合成しているファイルをダウンロードするものが存在せず動画と音声を別々でダウンロードして合成する必要がある
  2. 合成にはffmpegというライブラリがあるのだが、vercel環境ではerrorType":"Error","errorMessage":"spawn /var/task/node_modules/ffmpeg-static/ffmpeg ENOENT","code"というエラー、わかりやすくいえばそんなファイル見つかんないよ。と言われる※ローカル環境は動く
  3. 画質を下げればffmpegをしようせずともいけると考えたがvercelの無料枠のServerless Functionは10sでタイムアウトを起こすためそもそも無理っぽい
  4. 高画質(1080p)動画ダウンロードは関連動画のようにapiフォルダに記載して実行すれば本番環境でも動くようになりましたが3のタイムアウトでサービスとしては機能してない

image.png

vercel devで動くapiファイル

おわりに

普段ハッカソンはその場で作って終わることが多いですが今回は継続開発含めいろいろと学ぶことも多くありNext.jsの理解を深めながら触ったことのない新しいライブラリや処理を模索できて楽しかったです。ぜひ参考になったら嬉しいです。
※テストコードを書く用の設計をしましたがめんどくて書いてないです。懺悔...

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?