Skip to content

Instantly share code, notes, and snippets.

@kotsutsumi
Created March 18, 2023 03:22
Show Gist options
  • Save kotsutsumi/354c42cf7dea33df2d792ba2cfad9dd0 to your computer and use it in GitHub Desktop.
Save kotsutsumi/354c42cf7dea33df2d792ba2cfad9dd0 to your computer and use it in GitHub Desktop.
Next.js Setup with PrimeReact and Firebase Authentication
#!/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