with-firebase example for SSR (#16070)
I couldn't find an example when creating an SSR page using firebase's firestore data, so I improved the example based on the actual app I created My sample app: https://github.com/mikan3rd/commitly
This commit is contained in:
parent
af5b8ceb7a
commit
9ca1f39f75
8 changed files with 99 additions and 4 deletions
|
@ -5,4 +5,8 @@ NEXT_PUBLIC_FIREBASE_DATABASE_URL=
|
|||
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
|
||||
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
|
||||
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
|
||||
NEXT_PUBLIC_FIREBASE_APP_ID=
|
||||
NEXT_PUBLIC_FIREBASE_APP_ID=
|
||||
|
||||
# for firebase-admin
|
||||
FIREBASE_CLIENT_EMAIL=
|
||||
FIREBASE_PRIVATE_KEY=
|
||||
|
|
|
@ -33,6 +33,8 @@ cp .env.local.example .env.local
|
|||
|
||||
3. Set each variable on `.env.local` with your Firebase Configuration (found in "Project settings").
|
||||
|
||||
4. If you want to check the SSR page, get your account credentials from the Firebase console at _Project settings > Service accounts_, where you can click on _Generate new private key_ and download the credentials as a json file. Then set `FIREBASE_CLIENT_EMAIL` and `FIREBASE_PRIVATE_KEY` in `.env.local`
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
|
||||
|
|
13
examples/with-firebase/fetchData/getProfileData.js
Normal file
13
examples/with-firebase/fetchData/getProfileData.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import admin from '../firebase/nodeApp'
|
||||
|
||||
export const getProfileData = async (username) => {
|
||||
const db = admin.firestore()
|
||||
const profileCollection = db.collection('profile')
|
||||
const profileDoc = await profileCollection.doc(username).get()
|
||||
|
||||
if (!profileDoc.exists) {
|
||||
return null
|
||||
}
|
||||
|
||||
return profileDoc.data()
|
||||
}
|
|
@ -18,7 +18,10 @@ const clientCredentials = {
|
|||
if (typeof window !== 'undefined' && !firebase.apps.length) {
|
||||
firebase.initializeApp(clientCredentials)
|
||||
// To enable analytics. https://firebase.google.com/docs/analytics/get-started
|
||||
if ('measurementId' in clientCredentials) firebase.analytics()
|
||||
if ('measurementId' in clientCredentials) {
|
||||
firebase.analytics()
|
||||
firebase.performance()
|
||||
}
|
||||
}
|
||||
|
||||
export default firebase
|
||||
|
|
14
examples/with-firebase/firebase/nodeApp.js
Normal file
14
examples/with-firebase/firebase/nodeApp.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import * as admin from 'firebase-admin'
|
||||
|
||||
if (!admin.apps.length) {
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert({
|
||||
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
||||
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
|
||||
privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'),
|
||||
}),
|
||||
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
|
||||
})
|
||||
}
|
||||
|
||||
export default admin
|
|
@ -8,6 +8,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"firebase": "7.17.0",
|
||||
"firebase-admin": "9.0.0",
|
||||
"next": "latest",
|
||||
"react": "^16.13.0",
|
||||
"react-dom": "^16.13.0"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Head from 'next/head'
|
||||
import Link from 'next/link'
|
||||
import { useEffect } from 'react'
|
||||
import { useUser } from '../context/userContext'
|
||||
import firebase from '../firebase/clientApp'
|
||||
|
@ -7,6 +8,8 @@ export default function Home() {
|
|||
// Our custom hook to get context values
|
||||
const { loadingUser, user } = useUser()
|
||||
|
||||
const profile = { username: 'nextjs_user', message: 'Awesome!!' }
|
||||
|
||||
useEffect(() => {
|
||||
if (!loadingUser) {
|
||||
// You know that the user is loaded: either logged in or out!
|
||||
|
@ -16,6 +19,12 @@ export default function Home() {
|
|||
console.log(firebase)
|
||||
}, [loadingUser, user])
|
||||
|
||||
const createUser = async () => {
|
||||
const db = firebase.firestore()
|
||||
await db.collection('profile').doc(profile.username).set(profile)
|
||||
alert('User created!!')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<Head>
|
||||
|
@ -26,6 +35,19 @@ export default function Home() {
|
|||
<main>
|
||||
<h1 className="title">Next.js w/ Firebase Client-Side</h1>
|
||||
<p className="description">Fill in your credentials to get started</p>
|
||||
|
||||
<p className="description">
|
||||
Cloud Firestore Security Rules write permissions are required for
|
||||
adding users
|
||||
</p>
|
||||
<button onClick={createUser}>Create 'nextjs_user'</button>
|
||||
|
||||
<p className="description">
|
||||
Please press the link below after adding the user
|
||||
</p>
|
||||
<Link href={`/profile/${profile.username}`} passHref>
|
||||
<a>Go to SSR Page</a>
|
||||
</Link>
|
||||
</main>
|
||||
|
||||
<style jsx>{`
|
||||
|
@ -66,9 +88,14 @@ export default function Home() {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: 1.5em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.title a {
|
||||
|
|
31
examples/with-firebase/pages/profile/[username].js
Normal file
31
examples/with-firebase/pages/profile/[username].js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import Head from 'next/head'
|
||||
|
||||
import { getProfileData } from '../../fetchData/getProfileData'
|
||||
|
||||
export default function SSRPage({ data }) {
|
||||
const { username, profile } = data
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<Head>
|
||||
<title>Next.js w/ Firebase Client-Side</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<main>
|
||||
<h1 className="title">Next.js w/ Firebase Server-Side</h1>
|
||||
<h2>{username}</h2>
|
||||
<p>{profile.message}</p>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = async ({ params }) => {
|
||||
const { username } = params
|
||||
const profile = await getProfileData(username)
|
||||
if (!profile) {
|
||||
return { notFound: true }
|
||||
}
|
||||
return { props: { data: { username, profile } } }
|
||||
}
|
Loading…
Reference in a new issue