T3 Stack でアプリを構築して実行してみた
はじめに
こんにちは、クラウドエースの伊藝です。
最近、T3 Stack というワードが話題になっています。
以下で紹介されているように、簡潔さ、モジュール性、フルスタックの型安全を重視した技術スタックです。
T3 Stack は以下のパッケージで構成されています。
今回は T3 Stack アプリを実際に構築して、実行してみます。
環境
- Ubuntu 22.04.1 LTS (WSL)
- yarn 1.22.15
- node v16.16.0
アプリの雛形を生成する
以下のコマンドで T3 Stack アプリの雛形を生成します。
npm
npx create-t3-app@latest
yarn
yarn create t3-app
pnpm
pnpm dlx create-t3-app@latest
今回は yarn
を使いました。
アプリの雛形を生成するコマンドを実行すると、いくつかの質問が表示されます。
括弧 (my-t3-app)
の中はデフォルト値となっており、何も入力せずに Enter を押すとその値が使われます。
$ yarn create t3-app
yarn create v1.22.15
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@2.3.2: The platform "linux" is incompatible with this module.
info "fsevents@2.3.2" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Installed "create-t3-app@5.11.0" with binaries:
- create-t3-app
___ ___ ___ __ _____ ___ _____ ____ __ ___ ___
/ __| _ \ __| / \_ _| __| |_ _|__ / / \ | _ \ _ \
| (__| / _| / /\ \| | | _| | | |_ \ / /\ \| _/ _/
\___|_|_\___|_/‾‾\_\_| |___| |_| |___/ /_/‾‾\_\_| |_|
? What will your project be called? (my-t3-app)
TypeScript と JavaScript のどちらを使うかを問われます。上下の矢印キーで選択することができます。
今回は TypeScript を選択しました。
? Will you be using JavaScript or TypeScript? (Use arrow keys)
❯ TypeScript
JavaScript
アプリにインストールするパッケージを問われます。矢印キーで選択して、スペースキーで有効化/無効化を切り替えることができます。丸の中に黒丸が表示されたら有効化となります。
今回は欲張って全て有効化しました。
? Which packages would you like to enable? (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
❯◉ nextAuth
◉ prisma
◯ tailwind
◯ trpc
アプリの雛形のディレクトリを git リポジトリとして初期化するかを問われます。(git init
)
今回は初期化をします。
? Initialize a new git repository? (Y/n)
yarn install
を実行して依存関係を解決するかを問われます。
どちらでもいいですが、今回は実行することを選びました。
? Would you like us to run yarn install? (Y/n)
質問が終わり、アプリの雛形の生成が行われます。
Using: yarn
✔ my-t3-app scaffolded successfully!
Installing packages...
✔ Successfully installed nextAuth
✔ Successfully installed prisma
✔ Successfully installed tailwind
✔ Successfully installed trpc
✔ Successfully installed envVariables
Initializing Git...
⠋ Creating a new git repo...
✔ Successfully initialized git
Next steps:
cd my-t3-app
yarn prisma db push
yarn dev
Done in 515.51s.
アプリの雛形を眺める
アプリの雛形の生成が終わった時点では cd が行われていないため、手動でディレクトリを移動します。
cd my-t3-app
ディレクトリ内のファイルを見ると、T3 Stack を構成するライブラリに必要なファイルが生成されていることがわかります。
$ tree -a
.
├── .env
├── .eslintrc.json
├── .git
~~~~
~~~~
├── .gitignore
├── README.md
├── next-env.d.ts
├── next.config.mjs
├── node_modules
~~~~
~~~~
├── package.json
├── postcss.config.cjs
├── prisma
│ └── schema.prisma
├── public
│ └── favicon.ico
├── src
│ ├── env
│ │ ├── client.mjs
│ │ ├── schema.mjs
│ │ └── server.mjs
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── api
│ │ │ ├── auth
│ │ │ │ └── [...nextauth].ts
│ │ │ ├── examples.ts
│ │ │ ├── restricted.ts
│ │ │ └── trpc
│ │ │ └── [trpc].ts
│ │ └── index.tsx
│ ├── server
│ │ ├── common
│ │ │ └── get-server-auth-session.ts
│ │ ├── db
│ │ │ └── client.ts
│ │ └── router
│ │ ├── context.ts
│ │ ├── example.ts
│ │ ├── index.ts
│ │ └── protected-example-router.ts
│ ├── styles
│ │ └── globals.css
│ ├── types
│ │ └── next-auth.d.ts
│ └── utils
│ └── trpc.ts
├── tailwind.config.cjs
├── tree.txt
├── treea.txt
├── tsconfig.json
└── yarn.lock
1838 directories, 16284 files
.env
も生成されており、ライブラリに必要な環境変数をすぐに設定することができるようになっています。
生成段階で NextAuth.js の Discord の環境変数が用意されているのは Discord 推しだからなんですかねw
T3 Stack の Discord サーバーがあるので、興味がある人は参加するといいかもしれないです。
# Note that not all variables here might be in use for your selected configuration
# When adding additional env variables, the schema in /env/schema.mjs should be updated accordingly
# Prisma
DATABASE_URL=file:./db.sqlite
# Next Auth
NEXTAUTH_SECRET=
NEXTAUTH_URL=http://localhost:3000
# Next Auth Discord Provider
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
Prisma の設定ファイルの schema.prisma
を見ると、NextAuth.js
の連携の設定がされています。
こういう設定は面倒なので、生成段階で行われるのは非常に助かります。
生成段階では Git のコミットが行われていないため、手動で行います。
$ git add . && git commit -m 'Create T3 App'
実行する
NextAuth.js に必要なシークレットキーを生成します。
openssl rand -base64 32
qi0hKVuMPBrgxJezil8L9wdpl3ZYjqCVYKizzURQCdU=
出力されたランダムな文字列を .env
の NEXTAUTH_SECRET=
の右辺に入力します。
# Next Auth
NEXTAUTH_SECRET=qi0hKVuMPBrgxJezil8L9wdpl3ZYjqCVYKizzURQCdU=
以下コマンドでアプリを起動します。
$ yarn dev
http://localhost:3000/ にアクセスすると、初期画面が表示されます。
T3 Stack を構成するパッケージのドキュメントが紹介されています。
画面下に表示されている Hello from tRPC
は tRPC の通信のレスポンスです。
tRPC の通信はデベロッパーツールのコンソールから確認することができます。
終了するために Ctrl + C を押す。
認証機能を有効にする
NextAuth.js の認証機能を有効にするために、認証プロバイダを選ぶ必要があります。
NextAuth.js は多くの認証プロバイダをサポートしており、それぞれの設定方法が丁寧に公式ドキュメントで紹介されています。
Google OAuth の設定
今回は Google OAuth を認証プロバイダとして利用するが、好きな認証プロバイダがある場合はそちらを利用して問題ないです。
Google Cloud で Google OAuth を利用するための設定を行います。
OAuth 同意画面
以下の URL から「OAuth 同意画面」の設定を行います。
「OAuth 同意画面」の User Type で外部を選択し、作成ボタンを押します。
アプリ名と自分のメールアドレスを画像のように入力します。
「スコープを追加または削除」ボタンを押して、「範囲」が openid
の列にチェックを付けて選択します。
テストユーザーの設定は何も入力しません。
概要を確認して「OAuth 同意画面」の設定を完了します。
認証情報
以下の URL から認証情報「OAuth クライアント ID」を作成します。
「アプリケーションの種類」を ウェブアプリケーション
に設定します。
「名前」にアプリの名前を入力します。
「承認済みの JavaScript 生成元」に http://localhost:3000
を入力します。
「承認済みのリダイレクト URI」に http://localhost:3000/api/auth/callback/google
を入力します。
OAuth クライアントの ID とクライアントシークレットが表示されます。
値をコピーして、.env
に入力します。
今回は Discord ではなく Google OAuth を認証プロバイダとして利用するため、環境変数のキーを GOOGLE_CLIENT_ID
と GOOGLE_CLIENT_SECRET
に変更します。
...
# Next Auth Discord Provider
GOOGLE_CLIENT_ID=************-********************************.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-****************************
schema.mjs
src/env/schema.mjs
で Zod により環境変数の型が定義されています。
.env
で環境変数のキーを変更したため、それに合わせてキーの名前を変更します。
変更前
export const serverSchema = z.object({
...
DISCORD_CLIENT_ID: z.string(),
DISCORD_CLIENT_SECRET: z.string(),
});
変更後
export const serverSchema = z.object({
...
GOOGLE_CLIENT_ID: z.string(),
GOOGLE_CLIENT_SECRET: z.string(),
});
[...nextauth].ts
src/pages/api/auth/[...nextauth].ts
の一部を編集して、Google OAuth を認証プロバイダとして利用する設定をします。
変更前
import DiscordProvider from "next-auth/providers/discord";
...
providers: [
DiscordProvider({
clientId: env.DISCORD_CLIENT_ID,
clientSecret: env.DISCORD_CLIENT_SECRET,
}),
// ...add more providers here
],
...
変更後
import GoogleProvider from "next-auth/providers/google";
...
providers: [
GoogleProvider({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
}),
// ...add more providers here
],
...
index.ts
src/pages/index.tsx
を以下のように変更し、追記して認証ボタンを作成します。
ボタンは Tailwind でスタイルを適用します。
- 関数を使うための
import
を追加します - 認証情報を使うための
useSession()
を追加します -
trpc.useQuery
で投げるパラメータを変更します -
main
タグ内の一番下にsession
があるかないかで切り替わる認証のためのボタンを追加します
import { signIn, signOut, useSession } from "next-auth/react";
...
const Home: NextPage = () => {
const { data: session } = useSession();
const hello = trpc.useQuery(["example.hello", { text: `from tRPC by ${session?.user?.email}` }]);
...
<div>
{session ? (
<button
onClick={() => signOut()}
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded"
>
Sign out
</button>
) : (
<button
onClick={() => signIn()}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Sign in
</button>
)}
</div>
</main>
...
Prisma のマイグレーション
認証情報をデータベース (sqlite) に格納するために、マイグレーションを行います。
$ yarn prisma migrate dev --name init
実行する
認証の準備ができたのでアプリを起動します。
$ yarn dev
Hello from tRPC by undefined
と表示されている下の Sign in
をクリックします。
Sign in with Google
をクリックして Google アカウントでログインします。
トップ画面に戻り、自分のメールアドレスが表示されます。
おわりに
T3 Stack を構成するパッケージらはどれも設定が必要で、組み合わせて使うとなるとより多くの設定が必要となります。
しかし、create-t3-app
コマンドを使うことで、簡単にそれらを含んだフルスタック Web アプリを構築することができました。
また、NextAuth.js と Prisma の連携が雛形生成時点でされていたり、Zod で環境変数の型安全を実現したり、tRPC で superjson を使う設定になっていたりと、細かい部分でも型安全とパッケージ同士の連携に気を使っていることがわかりました。
T3 Stack のパッケージを参考にして自分でアプリを構築するより、create-t3-app
を使ってアプリを構築するほうが快適に開発を進めることができると考えられます。
Discussion