Firebase + Create React App
Earlier this year my team built and shipped its first production Firebase app. We needed a web-based chat client where users could interact with market research bots in real time. Firebase was the perfect fit: the Realtime Database kept clients in sync, Cloud Functions processed messages, and Firebase Hosting served the app.
On the client side we chose Create React App for its simple, batteries-included tooling. Combining the two is straightforward, but getting local development right can be tricky. Here’s the recipe that worked for us.
Dev servers
If you plan to use Firebase Functions and Firebase Hosting, run the Create React App dev server alongside the Firebase emulator. That way you can emulate HTTP functions and hosting while your React app runs in dev mode.
Install npm-run-all to orchestrate both servers:
yarn add --dev npm-run-all
Add these scripts to package.json:
{
"scripts": {
"dev": "run-p --race dev:firebase dev:react",
"dev:firebase": "firebase serve -p 4000",
"dev:react": "react-scripts start"
}
}
Run yarn dev to start both. React stays on http://localhost:3000 while the Firebase project is emulated on port 4000. The --race flag ensures either process exiting will stop the other so you don’t end up with orphaned servers.
Implicit initialization
When deploying to Firebase Hosting, use implicit initialization. It removes the need to juggle environment-specific configs.
Instead of manually configuring each environment:
<script src="https://www.gstatic.com/firebasejs/5.3.0/firebase.js"></script>
<script>
firebase.initializeApp({
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
projectId: "<PROJECT_ID>",
storageBucket: "<BUCKET>.appspot.com",
messagingSenderId: "<SENDER_ID>",
})
</script>
Just load the auto-configured scripts from Firebase Hosting:
<script src="/__/firebase/5.3.0/firebase.js"></script>
<script src="/__/firebase/init.js"></script>
Once deployed, the app is automatically configured for its host project.
You might be wondering about that /__ directory. Because it only exists in the Firebase Hosting environment, tell the React dev server how to proxy those requests locally by adding this to package.json:
{
"proxy": "http://localhost:4000"
}
The proxy setting sends unknown requests to the target URL. Any request containing /__ now reaches the Firebase Hosting emulator running on port 4000.
Calling Firebase Functions from your app
If you call an HTTP Firebase Function from React, you might be tempted to store environment-specific URLs. A cleaner option is to configure a rewrite in firebase.json that exposes the function behind a friendly path:
{
"hosting": {
"public": "build",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "/myFunction", // Some URL to expose
"function": "myFunction" // Your HTTP function
},
{
"source": "**",
"destination": "/index.html"
}
]
}
}
Now your app can call /myFunction and Firebase Hosting will route it to the correct backend.
const myData = await fetch('/myFunction')
To make that rewrite work locally, expand the proxy entry in package.json:
"proxy": {
"/__": {
"target": "http://localhost:4000"
}
"/myFunction": {
"target": "http://localhost:4000"
}
}
This approach works, but if you plan to add more functions, a scalable version might look like this:
"proxy": {
"/__": {
"target": "http://localhost:4000"
}
"/functions": {
"target": "http://localhost:4000"
}
}
Any request starting with /functions now reaches the emulator, keeping local development predictable while matching production routing.
Discuss on Twitter • Edit on GitHub
Keep Reading
- Structured output was my LLM aha moment
11 Jun 2024 - Why Use a JavaScript Framework
13 Jul 2019 - Hacking Image Interpolation for Fun and Profit
13 Jan 2019 - The Perils of Jest Snapshot Testing
07 Jan 2019 - A Better Way to Test Your React-Redux App
01 Jan 2019 - Firebase + Create React App
01 Aug 2018 - Partial Application in Action
29 Sep 2017 - Using SVG to Shrink Your PNGs
07 Sep 2014 - Adaptive content everywhere
06 Feb 2013