Created
March 18, 2023 03:22
-
-
Save kotsutsumi/354c42cf7dea33df2d792ba2cfad9dd0 to your computer and use it in GitHub Desktop.
Next.js Setup with PrimeReact and Firebase Authentication
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# オプション設定 | |
NO_AUTH=0 | |
NO_MYSQL=0 | |
function main() { | |
local appName=$1 | |
if [ -d $1 ]; then | |
printWarn "プロジェクトディレクトリが既に存在します。" | |
read -p "削除しますか? (y/N): " yn | |
case "$yn" in | |
[yY]*) rm -rf ${appName} && echo "" ;; | |
*) echo "" && echo "中断しました。" && exit 1 ;; | |
esac | |
fi | |
# プロジェクト作成 | |
createProject $appName | |
# プロジェクトディレクトリへ移動 | |
cd $1 | |
# .env作成 | |
createDotEnv | |
# パッケージ追加 | |
installPackages $appName | |
# NextAuth セットアップ | |
if [ $NO_AUTH -eq 0 ]; then | |
setupNextAuth | |
fi | |
# PrimeReact セットアップ | |
setupPrimeReact | |
} | |
# NextAuth セットアップ | |
function setupNextAuth() { | |
# firebase ディレクトリ作成 | |
mkdir -p firebase | |
# firebase/client.ts 作成 | |
cat <<EOS >firebase/client.ts | |
import { initializeApp, getApps } from 'firebase/app' | |
import { getAuth } from 'firebase/auth' | |
const firebaseConfig = { | |
apiKey: process.env.NEXT_PUBLIC_API_KEY, | |
authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN, | |
databaseURL: process.env.NEXT_PUBLIC_DATABASE_URL, | |
projectId: process.env.NEXT_PUBLIC_PROJECT_ID, | |
storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET, | |
messagingSenderId: process.env.NEXT_PUBLIC_MESSAGING_SENDER_ID, | |
appId: process.env.NEXT_PUBLIC_APP_ID, | |
measurementId: process.env.NEXT_PUBLIC_MEASUREMENT_ID | |
} | |
const app = getApps()?.length ? getApps()[0] : initializeApp(firebaseConfig) | |
export const auth = getAuth(app) | |
// EOF | |
EOS | |
# firebase/admin.ts 作成 | |
cat <<EOS >firebase/admin.ts | |
import { initializeApp, cert, getApps } from 'firebase-admin/app' | |
import { getAuth } from 'firebase-admin/auth' | |
const serviceAccount = require('/firebaseSecretKey.json') | |
export const firebaseAdmin = | |
getApps()[0] ?? | |
initializeApp({ | |
credential: cert(serviceAccount) | |
}) | |
export const auth = getAuth() | |
// EOF | |
EOS | |
# provider ディレクトリ作成 | |
mkdir -p provider | |
# provider/SessionProvider.tsx 作成 | |
cat <<EOS >provider/SessionProvider.tsx | |
'use client' | |
import { SessionProvider as NextAuthSessionProvider } from 'next-auth/react' | |
import React from 'react' | |
export interface SessionProviderProps { | |
children: React.ReactNode | |
} | |
const SessionProvider = ({ children }: SessionProviderProps) => { | |
return <NextAuthSessionProvider>{children}</NextAuthSessionProvider> | |
} | |
export default SessionProvider | |
// EOF | |
EOS | |
# pages/api/auth ディレクトリ作成 | |
mkdir -p pages/api/auth | |
# pages/api/auth/[...nextauth].ts 作成 | |
cat <<EOS >pages/api/auth/[...nextauth].ts | |
import NextAuth from 'next-auth' | |
import type { NextAuthOptions } from 'next-auth' | |
import CredentialsProvider from 'next-auth/providers/credentials' | |
import { auth } from '@/firebase/admin' | |
export const authOptions: NextAuthOptions = { | |
providers: [ | |
CredentialsProvider({ | |
credentials: {}, | |
authorize: async ({ idToken }: any, _req) => { | |
if (idToken) { | |
try { | |
const decoded = await auth.verifyIdToken(idToken) | |
return { ...decoded } | |
} catch (err) { | |
console.error(err) | |
} | |
} | |
return null as any | |
} | |
}) | |
], | |
session: { | |
strategy: 'jwt' | |
}, | |
callbacks: { | |
async jwt({ token, user }) { | |
return { ...token, ...user } as any | |
}, | |
// sessionにJWTトークンからのユーザ情報を格納 | |
async session({ session, token }) { | |
session.user.emailVerified = token.emailVerified | |
session.user.uid = token.uid | |
return session | |
} | |
} | |
} | |
export default NextAuth(authOptions) | |
// EOF | |
EOS | |
# components ディレクトリ作成 | |
mkdir -p components | |
# components/ClientComponent.tsx 作成 | |
cat <<EOS >components/ClientComponent.tsx | |
'use client' | |
import { useSession } from 'next-auth/react' | |
import React from 'react' | |
const ClientComponent = () => { | |
const { data: session } = useSession() | |
const user = session?.user | |
return <p>{JSON.stringify(user)}</p> | |
} | |
export default ClientComponent | |
// EOF | |
EOS | |
# components/ServerComponent.tsx 作成 | |
cat <<EOS >components/ServerComponent.tsx | |
import { getServerSession } from 'next-auth/next' | |
import React from 'react' | |
import { authOptions } from '../pages/api/auth/[...nextauth]' | |
const ServerComponent = async () => { | |
const session = await getServerSession(authOptions) | |
const user = session?.user | |
return <p>{JSON.stringify(user)}</p> | |
} | |
export default ServerComponent | |
// EOF | |
EOS | |
# @types ディレクトリ作成 | |
mkdir -p @types | |
# @types/next-auth.d.ts 作成 | |
cat <<EOS >@types/next-auth.d.ts | |
import NextAuth, { DefaultSession } from 'next-auth' | |
import { JWT } from 'next-auth/jwt' | |
declare module 'next-auth' { | |
interface Session { | |
user: { | |
// Firebaseの認証情報 | |
uid: string | |
emailVerified?: boolean | |
} & DefaultSession['user'] | |
} | |
} | |
declare module 'next-auth/jwt' { | |
interface JWT { | |
// Firebaseの認証情報 | |
uid: string | |
emailVerified: boolean | |
} | |
} | |
// EOF | |
EOS | |
# app/layout.tsx 作成 | |
cat <<EOS >app/layout.tsx | |
import SessionProvider from '../provider/SessionProvider' | |
export default function RootLayout({ | |
children | |
}: { | |
children: React.ReactNode | |
}) { | |
return ( | |
<SessionProvider> | |
<html lang="ja"> | |
<head /> | |
<body>{children}</body> | |
</html> | |
</SessionProvider> | |
) | |
} | |
// EOF | |
EOS | |
# app/signin ディレクトリ作成 | |
mkdir -p app/signin | |
# app/layout.tsx 作成 | |
cat <<EOS >app/layout.tsx | |
import SessionProvider from "../provider/SessionProvider"; | |
export default function RootLayout({ | |
children, | |
}: { | |
children: React.ReactNode; | |
}) { | |
return ( | |
<SessionProvider> | |
<html lang="ja"> | |
<head /> | |
<body>{children}</body> | |
</html> | |
</SessionProvider> | |
); | |
} | |
// EOF | |
EOS | |
# app/signin/page.tsx 作成 | |
cat <<EOS >app/signin/page.tsx | |
"use client"; | |
import styles from "./page.module.css"; | |
import { useState } from "react"; | |
import { signInWithEmailAndPassword } from "firebase/auth"; | |
import { auth } from "@/firebase/client"; | |
import { signIn as signInByNextAuth } from "next-auth/react"; | |
const SingIn = () => { | |
const [email, setEmail] = useState(""); | |
const [password, setPassword] = useState(""); | |
const signIn = async () => { | |
if (!email) return; | |
if (!password) return; | |
try { | |
const userCredential = await signInWithEmailAndPassword( | |
auth, | |
email, | |
password | |
); | |
const idToken = await userCredential.user.getIdToken(); | |
await signInByNextAuth("credentials", { | |
idToken, | |
callbackUrl: "/", | |
}); | |
} catch (e) { | |
console.error(e); | |
} | |
}; | |
return ( | |
<div> | |
<input | |
type="email" | |
value={email} | |
onChange={(event) => setEmail(event.target.value)} | |
placeholder="メールアドレス" | |
/> | |
<input | |
type="password" | |
value={password} | |
onChange={(event) => setPassword(event.target.value)} | |
placeholder="パスワード" | |
/> | |
<button | |
type="button" | |
onClick={() => { | |
signIn(); | |
}} | |
> | |
ログイン | |
</button> | |
</div> | |
); | |
}; | |
export default SingIn; | |
// EOF | |
EOS | |
# app/page.tsx | |
cat <<EOS >app/page.tsx | |
import ClientComponent from '@/components/ClientComponent' | |
import ServerComponent from '@/components/ServerComponent' | |
const Home = async () => { | |
return ( | |
<main> | |
<ClientComponent /> | |
{/* @ts-ignore */} | |
<ServerComponent /> | |
</main> | |
) | |
} | |
export default Home | |
// EOF | |
EOS | |
} | |
# PrimeReact セットアップ | |
function setupPrimeReact() { | |
local target="app/layout.tsx" | |
sed -i '1s/^/import "primeflex\/primeflex.css";\n/' ${target} | |
sed -i '1s/^/import "primeicons\/primeicons.css";\n/' ${target} | |
sed -i '1s/^/import "primereact\/resources\/primereact.min.css";\n/' ${target} | |
sed -i '1s/^/import "primereact\/resources\/themes\/saga-blue\/theme.css";\n/' ${target} | |
} | |
# パッケージインストール | |
function installPackages() { | |
# パッケージ | |
packages=( | |
"primereact" | |
"primeicons" | |
"primeflex" | |
) | |
# コマンド作成 | |
local cmd="npm i" | |
for package in "${packages[@]}"; do | |
cmd="${cmd} ${package}" | |
done | |
# Firebase Authentication 関連パッケージ | |
if [ $NO_AUTH -eq 0 ]; then | |
packages=( | |
"next-auth" | |
"firebase" | |
"firebase-admin" | |
) | |
fi | |
for package in "${packages[@]}"; do | |
cmd="${cmd} ${package}" | |
done | |
# MySQL 関連パッケージ | |
if [ $NO_MYSQL -eq 0 ]; then | |
packages=( | |
"serverless-mysql" | |
) | |
fi | |
for package in "${packages[@]}"; do | |
cmd="${cmd} ${package}" | |
done | |
# コマンド実行 | |
ret=$(${cmd}) | |
# 開発用パッケージ | |
packages=( | |
"prettier" | |
) | |
# コマンド作成 | |
local cmd="npm i -D" | |
for package in "${packages[@]}"; do | |
cmd="${cmd} ${package}" | |
done | |
# コマンド実行 | |
ret=$(${cmd}) | |
} | |
# .env作成 | |
function createDotEnv() { | |
# .env | |
cat <<EOS >.env.local | |
# [.env.local] | |
# 起動時に毎回読み込まれます | |
# EOF | |
EOS | |
# NEXTAUTH_SECRET 生成 | |
secret=$(openssl rand -base64 32) | |
# .env.development | |
cat <<EOS >.env.development | |
# [.env.development] | |
# next dev(npm run dev) 時に読み込まれます | |
# [Next Auth] | |
NEXTAUTH_SECRET=${secret} | |
# [Firebase Authentication 接続設定] | |
NEXT_PUBLIC_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_AUTH_DOMAIN=XXXXXXXXXXXXfXXXXXXXXXXXXXX | |
NEXT_PUBLIC_PROJECT_ID=XXXXXXXXXXX | |
NEXT_PUBLIC_STORAGE_BUCKET=XXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MESSAGIN_SENDER_ID=XXXXXXXXXXXXX | |
NEXT_PUBLIC_APP_ID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MEASUREMENT_ID=XXXXXXXXXXXX | |
# [MariaDB 接続設定] | |
NEXT_PUBLIC_MYSQL_HOST=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MYSQL_DATABASE=XXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MYSQL_USER=XXXXXXXXXX | |
NEXT_PUBLIC_MYSQL_PASSWORD=XXXXXXXXXXXXXX | |
# EOF | |
EOS | |
# NEXTAUTH_SECRET 生成 | |
secret=$(openssl rand -base64 32) | |
# .env.production | |
cat <<EOS >.env.production | |
# [.env.development] | |
# next start 時に読み込まれます | |
# [Next Auth] | |
NEXTAUTH_SECRET=${secret} | |
# [Firebase Authentication 接続設定] | |
NEXT_PUBLIC_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_AUTH_DOMAIN=XXXXXXXXXXXXfXXXXXXXXXXXXXX | |
NEXT_PUBLIC_PROJECT_ID=XXXXXXXXXXX | |
NEXT_PUBLIC_STORAGE_BUCKET=XXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MESSAGIN_SENDER_ID=XXXXXXXXXXXXX | |
NEXT_PUBLIC_APP_ID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MEASUREMENT_ID=XXXXXXXXXXXX | |
# [MariaDB 接続設定] | |
NEXT_PUBLIC_MYSQL_HOST=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MYSQL_DATABASE=XXXXXXXXXXXXXXXXX | |
NEXT_PUBLIC_MYSQL_USER=XXXXXXXXXX | |
NEXT_PUBLIC_MYSQL_PASSWORD=XXXXXXXXXXXXXX | |
# EOF | |
EOS | |
# .gitignore 追加 | |
echo "" >>.gitignore | |
echo "# env files" >>.gitignore | |
echo ".env.development" >>.gitignore | |
echo ".env.production" >>.gitignore | |
echo "" >>.gitignore | |
echo "# Firebase Authentication" >>.gitignore | |
echo "firebaseSecretKey.json" >>.gitignore | |
} | |
# Next.js プロジェクト作成 | |
function createProject() { | |
# オプション | |
opts=( | |
"--ts" | |
"--use-npm" | |
"--eslint" | |
"--no-src-dir" | |
"--experimental-app" | |
"--import-alias @/*" | |
) | |
# コマンド作成 | |
local cmd="npx create-next-app@latest $1" | |
for opt in "${opts[@]}"; do | |
cmd="${cmd} ${opt}" | |
done | |
# コマンド実行 | |
ret=$(${cmd}) | |
# .prettierrc 作成 | |
cat <<EOS >.prettierrc | |
{ | |
"tabWidth": 4, | |
"singleQuote": true, | |
"semi": false, | |
"trailingComma": "none" | |
} | |
EOS | |
} | |
# カラーメッセージ出力 | |
function colorMessage() { | |
local message="$1" | |
local color="$2" | |
# -nオプション:改行なし | |
# -eオプション:バックスラッシュによるエスケープシーケンスを解釈する。 | |
# \033[31m :文字色を赤に変更 | |
echo -n -e "\033[${color}m" | |
echo "${message}" | |
# \033[31m:文字色を元に戻す。 | |
echo -n -e "\033[m" | |
} | |
# Infoメッセージ出力 | |
function printInfo() { | |
colorMessage $1 34 | |
} | |
# Successメッセージ出力 | |
function printSuccess() { | |
colorMessage "✅ $1" 32 | |
} | |
# Warnメッセージ出力 | |
function printWarn() { | |
colorMessage "🚧 $1" 33 | |
} | |
# Errorメッセージ出力 | |
function printError() { | |
colorMessage "❌ $1" 31 | |
} | |
function usage() { | |
echo "[使用方法]" | |
echo " setup-nextjs13 <project-name> [-na|--no-auth]" | |
echo "" | |
echo "[オプション]" | |
echo " -na --no-auth Firebase Authenticationセットアップ無し" | |
echo " -nm --no-mysql Serverless MySQL セットアップ無し" | |
echo "" | |
exit 0 | |
} | |
# 実行 | |
echo "" | |
echo -n -e "\033[1;37m" | |
echo "🚀 Next.js Setup with PrimeReact and Firebase Authentication" | |
echo -n -e "\033[1;30m" | |
echo "" | |
echo " written by Kazuhiro Kotsutsumi <[email protected]>" | |
echo -n -e "\033[m" | |
echo "" | |
echo "" | |
if [ $# -eq 0 ]; then | |
printError "作成するプロジェクト名を指定してください。" | |
echo "" | |
echo -n -e "\033[34m" | |
echo "構文:" | |
echo -n -e "\033[m" | |
echo " setup-nextjs13 <ProjectName>" | |
echo "" | |
echo -n -e "\033[34m" | |
echo "例:" | |
echo -n -e "\033[m" | |
echo " setup-nextjs13 my-app" | |
exit 1 | |
fi | |
# ヘルプ表示 | |
if [ "$1" = "-h" -o "$1" = "--help" ]; then | |
usage | |
fi | |
for arg in "$@"; do | |
# --no-auth オプション設定 | |
if [ "${arg}" = "-na" -o "${arg}" = "--no-auth" ]; then | |
NO_AUTH=1 | |
fi | |
# --no-mysql オプション設定 | |
if [ "${arg}" = "-nm" -o "${arg}" = "--no-mysql" ]; then | |
NO_MYSQL=1 | |
fi | |
# | |
done | |
main $1 | |
# 完了メッセージ出力 | |
printSuccess "セットアップ完了" | |
echo "" | |
echo "" | |
if [ $NO_AUTH -eq 0 ]; then | |
echo -n -e "\033[34m" | |
echo "🌎 ステップ1: .envファイルを設定する" | |
echo -n -e "\033[m" | |
echo "" | |
echo "https://console.firebase.google.com/u/0/?hl=ja へ移動しプロジェクトを作成します。" | |
echo "「プロジェクトの設定」から .envに記載する情報を取得して、.env.development, .env.production の内容を書き換えます。" | |
echo "" | |
echo "" | |
echo -n -e "\033[34m" | |
echo "📜 ステップ2: firebaseSecretKey.json を置き換える" | |
echo -n -e "\033[m" | |
echo "" | |
echo "「プロジェクト設定」> 「サービス アカウント」で、「新しい秘密鍵の生成」ボタンを押してJSONファイルをダウンロードします。" | |
echo "ダウンロードしたJSONファイルを、firebaseSecretKey.json としてプロジェクトディレクトリに配置します。" | |
echo "" | |
echo "" | |
echo -n -e "\033[34m" | |
echo "🗄 ステップ3: MySQL接続設定" | |
echo -n -e "\033[m" | |
echo "" | |
echo "MySQLを利用する場合、.env.development, .env.production の接続設定を書き換えます。" | |
echo "" | |
echo "" | |
echo -n -e "\033[34m" | |
echo "🚀 ステップ4: プロジェクト開始する" | |
echo -n -e "\033[m" | |
echo "" | |
echo " cd $1" | |
echo " npm run dev" | |
echo "" | |
else | |
echo -n -e "\033[34m" | |
echo "🚀 プロジェクト開始する" | |
echo -n -e "\033[m" | |
echo "" | |
echo " cd $1" | |
echo " npm run dev" | |
echo "" | |
fi | |
# EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment