From f1944cad8870dd51d556809d5f570d6b429bf0ef Mon Sep 17 00:00:00 2001 From: julianbenegas Date: Fri, 20 Mar 2020 17:38:28 -0300 Subject: [PATCH] With Firebase Client-Side example (#11053) * initialized example * Import from "firebase/app" to get only needed firebase modules * credentials as env variables Also, initialize app in a separate file. Much cleaner. * Update examples/with-firebase-client-side/package.json Co-Authored-By: Luis Alvarez D. * fixed environment variables and added .env.example * added dotenv * Updated readme * Renamed example in the readme * Renamed example files * Updated title Co-authored-by: Luis Alvarez D. --- examples/with-firebase/.env.example | 8 + examples/with-firebase/.gitignore | 25 +++ examples/with-firebase/README.md | 57 ++++++ examples/with-firebase/context/userContext.js | 40 ++++ examples/with-firebase/firebase/clientApp.js | 24 +++ examples/with-firebase/next.config.js | 14 ++ examples/with-firebase/now.json | 13 ++ examples/with-firebase/package.json | 18 ++ examples/with-firebase/pages/_app.js | 8 + examples/with-firebase/pages/index.js | 183 ++++++++++++++++++ examples/with-firebase/public/favicon.ico | Bin 0 -> 15086 bytes examples/with-firebase/public/zeit.svg | 10 + 12 files changed, 400 insertions(+) create mode 100644 examples/with-firebase/.env.example create mode 100644 examples/with-firebase/.gitignore create mode 100644 examples/with-firebase/README.md create mode 100644 examples/with-firebase/context/userContext.js create mode 100644 examples/with-firebase/firebase/clientApp.js create mode 100644 examples/with-firebase/next.config.js create mode 100644 examples/with-firebase/now.json create mode 100644 examples/with-firebase/package.json create mode 100644 examples/with-firebase/pages/_app.js create mode 100644 examples/with-firebase/pages/index.js create mode 100644 examples/with-firebase/public/favicon.ico create mode 100644 examples/with-firebase/public/zeit.svg diff --git a/examples/with-firebase/.env.example b/examples/with-firebase/.env.example new file mode 100644 index 000000000000000..266032b8b8e96e0 --- /dev/null +++ b/examples/with-firebase/.env.example @@ -0,0 +1,8 @@ +# TODO. Fill in with Firebase Config +FIREBASE_API_KEY= +FIREBASE_AUTH_DOMAIN= +FIREBASE_DATABASE_URL= +FIREBASE_PROJECT_ID= +FIREBASE_STORAGE_BUCKET= +FIREBASE_MESSAGING_SENDER_ID= +FIREBASE_APP_ID= \ No newline at end of file diff --git a/examples/with-firebase/.gitignore b/examples/with-firebase/.gitignore new file mode 100644 index 000000000000000..cea93e82af5325c --- /dev/null +++ b/examples/with-firebase/.gitignore @@ -0,0 +1,25 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +.env + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/examples/with-firebase/README.md b/examples/with-firebase/README.md new file mode 100644 index 000000000000000..da1dfeff9b41592 --- /dev/null +++ b/examples/with-firebase/README.md @@ -0,0 +1,57 @@ +# With Firebase + +This is a simple set up for Firebase for client side applications. + +The firebase app is initialized in `firebase/clientApp.js`, to use you just have to import it anywhere in the app + +The React Context API is used to provide user state. + +## Deploy your own + +Deploy the example using [ZEIT Now](https://zeit.co/now): + +[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-firebase) + +## How to use + +### Using `create-next-app` + +Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example with-firebase with-firebase-app +# or +yarn create next-app --example with-firebase with-firebase-app +``` + +### Download manually + +Download the example: + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-firebase +cd with-firebase +``` + +### Configuration + +1. [Create a Firebase project](https://console.firebase.google.com/u/0/) and add a new app to it. +2. Create a `.env` file and copy the contents of `.env.example` into it: + +```bash +cp .env.example .env +``` + +3. Set each variable on `.env` with your Firebase Configuration (found in "Project settings"). + +Install it and run: + +```bash +npm install +npm run dev +# or +yarn +yarn dev +``` + +Deploy it to the cloud with [ZEIT Now](https://zeit.co/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-firebase/context/userContext.js b/examples/with-firebase/context/userContext.js new file mode 100644 index 000000000000000..dd82753f87a072a --- /dev/null +++ b/examples/with-firebase/context/userContext.js @@ -0,0 +1,40 @@ +import { useState, useEffect, createContext, useContext } from 'react' +import firebase from '../firebase/clientApp' + +export const UserContext = createContext() + +export default ({ children }) => { + const [user, setUser] = useState(null) + const [loadingUser, setLoadingUser] = useState(true) // Helpful, to update the UI accordingly. + + useEffect(() => { + // Listen authenticated user + const unsubscriber = firebase.auth().onAuthStateChanged(async user => { + try { + if (user) { + // User is signed in. + const { uid, displayName, email, photoURL } = user + // You could also look for the user doc in your Firestore (if you have one): + // const userDoc = await firebase.firestore().doc(`users/${uid}`).get() + setUser({ uid, displayName, email, photoURL }) + } else setUser(null) + } catch (error) { + // Most probably a connection error. Handle appropiately. + } finally { + setLoadingUser(false) + } + }) + + // Unsubscribe auth listener on unmount + return () => unsubscriber() + }, []) + + return ( + + {children} + + ) +} + +// Custom hook that shorhands the context! +export const useUser = () => useContext(UserContext) diff --git a/examples/with-firebase/firebase/clientApp.js b/examples/with-firebase/firebase/clientApp.js new file mode 100644 index 000000000000000..32036c70c776076 --- /dev/null +++ b/examples/with-firebase/firebase/clientApp.js @@ -0,0 +1,24 @@ +import firebase from 'firebase/app' +import 'firebase/auth' // If you need it +import 'firebase/firestore' // If you need it +import 'firebase/storage' // If you need it +import 'firebase/analytics' // If you need it + +const clientCredentials = { + apiKey: process.env.FIREBASE_API_KEY, + authDomain: process.env.FIREBASE_AUTH_DOMAIN, + databaseURL: process.env.FIREBASE_DATABASE_URL, + projectId: process.env.FIREBASE_PROJECT_ID, + storageBucket: process.env.FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.FIREBASE_APP_ID, +} + +// Check that `window` is in scope for the analytics module! +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() +} + +export default firebase diff --git a/examples/with-firebase/next.config.js b/examples/with-firebase/next.config.js new file mode 100644 index 000000000000000..7bd8ac5a276545e --- /dev/null +++ b/examples/with-firebase/next.config.js @@ -0,0 +1,14 @@ +// On production, variables are set with `now secrets`. On development, they use the .env file +require('dotenv').config() + +module.exports = { + env: { + FIREBASE_API_KEY: process.env.FIREBASE_API_KEY, + FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN, + FIREBASE_DATABASE_URL: process.env.FIREBASE_DATABASE_URL, + FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID, + FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET, + FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID, + FIREBASE_APP_ID: process.env.FIREBASE_APP_ID, + }, +} diff --git a/examples/with-firebase/now.json b/examples/with-firebase/now.json new file mode 100644 index 000000000000000..8adcc56767429f3 --- /dev/null +++ b/examples/with-firebase/now.json @@ -0,0 +1,13 @@ +{ + "build": { + "env": { + "FIREBASE_API_KEY": "@firebase-api-key", + "FIREBASE_AUTH_DOMAIN": "@firebase-auth-domain", + "FIREBASE_DATABASE_URL": "@firebase-database-url", + "FIREBASE_PROJECT_ID": "@firebase-project-id", + "FIREBASE_STORAGE_BUCKET": "@firebase-storage-bucket", + "FIREBASE_MESSAGING_SENDER_ID": "@firebase-messaging-sender-id", + "FIREBASE_APP_ID": "@firebase-app-id" + } + } +} diff --git a/examples/with-firebase/package.json b/examples/with-firebase/package.json new file mode 100644 index 000000000000000..828fa643cbe29cc --- /dev/null +++ b/examples/with-firebase/package.json @@ -0,0 +1,18 @@ +{ + "name": "with-firebase", + "version": "0.1.0", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "firebase": "7.11.0", + "next": "latest", + "react": "^16.13.0", + "react-dom": "^16.13.0" + }, + "devDependencies": { + "dotenv": "8.2.0" + } +} diff --git a/examples/with-firebase/pages/_app.js b/examples/with-firebase/pages/_app.js new file mode 100644 index 000000000000000..c6985b38a61d555 --- /dev/null +++ b/examples/with-firebase/pages/_app.js @@ -0,0 +1,8 @@ +import UserProvider from '../context/userContext' + +// Custom App to wrap it with context provider +export default ({ Component, pageProps }) => ( + + + +) diff --git a/examples/with-firebase/pages/index.js b/examples/with-firebase/pages/index.js new file mode 100644 index 000000000000000..71d05d886cda673 --- /dev/null +++ b/examples/with-firebase/pages/index.js @@ -0,0 +1,183 @@ +import Head from 'next/head' +import { useEffect } from 'react' +import { useUser } from '../context/userContext' +import firebase from '../firebase/clientApp' + +export default () => { + // Our custom hook to get context values + const { loadingUser, user } = useUser() + + useEffect(() => { + if (!loadingUser) { + // You know that the user is loaded: either logged in or out! + console.log(user) + } + // You also have your firebase app initialized + console.log(firebase) + }, [loadingUser, user]) + + return ( +
+ + Next.js w/ Firebase Client-Side + + + +
+

Next.js w/ Firebase Client-Side

+

Fill in your credentials to get started

+
+ + + + + + +
+ ) +} diff --git a/examples/with-firebase/public/favicon.ico b/examples/with-firebase/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4965832f2c9b0605eaa189b7c7fb11124d24e48a GIT binary patch literal 15086 zcmeHOOH5Q(7(R0cc?bh2AT>N@1PWL!LLfZKyG5c!MTHoP7_p!sBz0k$?pjS;^lmgJ zU6^i~bWuZYHL)9$wuvEKm~qo~(5=Lvx5&Hv;?X#m}i|`yaGY4gX+&b>tew;gcnRQA1kp zBbm04SRuuE{Hn+&1wk%&g;?wja_Is#1gKoFlI7f`Gt}X*-nsMO30b_J@)EFNhzd1QM zdH&qFb9PVqQOx@clvc#KAu}^GrN`q5oP(8>m4UOcp`k&xwzkTio*p?kI4BPtIwX%B zJN69cGsm=x90<;Wmh-bs>43F}ro$}Of@8)4KHndLiR$nW?*{Rl72JPUqRr3ta6e#A z%DTEbi9N}+xPtd1juj8;(CJt3r9NOgb>KTuK|z7!JB_KsFW3(pBN4oh&M&}Nb$Ee2 z$-arA6a)CdsPj`M#1DS>fqj#KF%0q?w50GN4YbmMZIoF{e1yTR=4ablqXHBB2!`wM z1M1ke9+<);|AI;f=2^F1;G6Wfpql?1d5D4rMr?#f(=hkoH)U`6Gb)#xDLjoKjp)1;Js@2Iy5yk zMXUqj+gyk1i0yLjWS|3sM2-1ECc;MAz<4t0P53%7se$$+5Ex`L5TQO_MMXXi04UDIU+3*7Ez&X|mj9cFYBXqM{M;mw_ zpw>azP*qjMyNSD4hh)XZt$gqf8f?eRSFX8VQ4Y+H3jAtvyTrXr`qHAD6`m;aYmH2zOhJC~_*AuT} zvUxC38|JYN94i(05R)dVKgUQF$}#cxV7xZ4FULqFCNX*Forhgp*yr6;DsIk=ub0Hv zpk2L{9Q&|uI^b<6@i(Y+iSxeO_n**4nRLc`P!3ld5jL=nZRw6;DEJ*1z6Pvg+eW|$lnnjO zjd|8>6l{i~UxI244CGn2kK@cJ|#ecwgSyt&HKA2)z zrOO{op^o*- + + + + + + + + +