Firebase team just announced, at Google I/O 2024, a new product to deploy fullstack web app: Firebase App Hosting.
Previously we had Firebase Hosting which was only suitable for frontend apps:
- Types : Static Site, SPA Single Page App
- Frameworks : Vue.js, React.js, Svelte, Flutter web.
But we couldn't deploy fullstack apps (using SSR, ISR) with Firebase Hosting. It was possible to workaround this limitation using Firebase Functions. I tried it and it was not easy nor pleasant:
- There was a latency due to warm-up functions
- You have to configure the functions to serve the content (which is an additional step specific to Firebase Hosting)
Today, with Firebase App Hosting, this became a lot more easier.
Since Firebase team didn't explicitly tell if it was possible to deploy applications other than Angular and Next.js, I took the journey to deploy a Nuxt app using SSR.
TL;DR: It's working!
I'll assume that you have the necessary toolings to develop a Nuxt app. You need:
- Node.js installed - v18.0.0 or newer
- A terminal: in order to run Nuxt & Firebase commands
- A Text editor: like VSCode
- Git and a GitHub account (create an account if you don't already have one)
I'm using macOS with Node.js v20.13.1 (lts/iron), VSCode with the official Vue extension, bun v1.1.8.
I'll name the project nuxt-firebase. Feel free to replace that name with your your own.
Create a Nuxt app
Let's create a Nuxt app with minimal code and SSR configuration. Than we will deploy it on the cloud.
Initialize the repository
(You can follow the official Nuxt documentation there).
First, initialize a repository with Nuxt:
# initialize your nuxt app
npx nuxi@latest init nuxt-firebase
We then navigate into the created directory:
# move into your project directory
cd nuxt-firebase
Run the app to check that everything is okay:
# in your nuxt project directory
npm run dev -- -o
Add pages and routes
We're going to edit the app.vue file and add two pages inside the /pages/ directory which does not exist yet.
Replace the content of app.vue with this one:
// app.vue
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
<footer>
<div class="link-bar">
<NuxtLink to="/">Home</NuxtLink>
<NuxtLink to="/about">About</NuxtLink>
</div>
</footer>
</template>
<style>
footer {
position: fixed;
bottom: 24px;
display: flex;
justify-content: center;
align-items: center;
left: 0;
right: 0;
padding: 10px;
text-align: center;
}
.link-bar {
display: flex;
justify-content: center;
gap: 1rem;
padding: 0.5rem;
border-radius: 0.5rem;
border: 1px solid #FFE6E6;
box-shadow: 0 0 10px #FFE6E6;
position: relative
}
</style>
Create the /pages/
folder at the root of your project's directory. Inside, add these two files:
index.vue:
// pages/index.vue
<template>
<h1>Index</h1>
</template>
about.vue:
// pages/about.vue
<template>
<h1>About</h1>
</template>
You should see something like this in your browser:
It's very basic. You can customize your pages but for our demo it's good enough.
Configure Rendering Modes
By default, Nuxt uses SSR in development mode, but switches to client-side rendering in production (for example, static rendering).
We need to configure our app routes to explicitly tell Nuxt to use SSR for our pages in nuxt.config.ts
:
// nuxt.config.ts
// --------------
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
routeRules: {
'/': { ssr: true },
'/about': { ssr: true },
},
})
Now when we'll deploy our app on Firebase App Hosting, the routes /
and /about
will be serve through server side rendering (SSR).
For our own knowledge, here is an example of a config rendering rules with their purpose:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// Homepage pre-rendered at build time
'/': { prerender: true },
// Products page generated on demand, revalidates in background, cached until API response changes
'/products': { swr: true },
// Product page generated on demand, revalidates in background, cached for 1 hour (3600 seconds)
'/products/**': { swr: 3600 },
// Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds)
'/blog': { isr: 3600 },
// Blog post page generated on demand once until next deployment, cached on CDN
'/blog/**': { isr: true },
// Admin dashboard renders only on client-side
'/admin/**': { ssr: false },
// Add cors headers on API routes
'/api/**': { cors: true },
// Redirects legacy urls
'/old-page': { redirect: '/new-page' }
}
})
An overview of routes rendering rules:
Source: https://nuxt.com/docs/guide/concepts/rendering#route-rules
See the official documentation for more information: https://nuxt.com/docs/guide/concepts/rendering
Push into GitHub
The final part in the code editor is to push the new code to GitHub. Thus Firebase will be able to fetch and build our app with its CI/CD.
You can see the source code here: nuxt-firebase
Deploy on Firebase App Hosting
First we need to create a Firebase account if we don't have one. After your Firebase account has been created, you should see the welcome screen. Click on the "Create a project" button:
Once created, we go on le left side bar and select "App Hosting".
You can follow the video tutorial or/and the screen by screen images with text explanations:
App Hosting button is in the Build accordion:
We arrive on the App Hosting welcome page:
We need to upgrade our project from Spark Plan to Blaze Plan.
Our Nuxt app uses features in the Blaze Plan so we have to add a payment method. For this demo we'll pay little to nothing since our app won't consume much resources, if it has minimal traffic. Firebase products pricing - including App Hosting - is based on usage cost. Meaning that if your app get approximately 10k visits, you'll pay ~$0.15 according to the Firebase documentation.
NOTE: This is an example and other factors should be taken into account like: Effective Concurrency, CPU/Mem Time.
Plus there are no-cost limits which allow us to use these resources for free before being charged:
After clicking on the "Upgrade project" button, a popup opens:
Click on "Continue".
We confirm our country, and enter a payment method.
Your account is now setup on the Blaze plan, now we can go to our dashboard and create a new App Hosting project (which will be inside our Firebase project: nuxt-firebase).
Click on "Get started" button.
The configuration wizard will ask us to create access from our GitHub account to Google Developer Connect, which will be then linked to Firebase.
When this is done, we will be able to select our GitHub account and Nuxt app (hosted on GitHub).
Wait some minutes for the app to build. At this time, the build time is much longer than Vercel. It takes ~45 seconds on Vercel and ~3 minutes on Firebase App Hosting.
And voilà! If the build and deployment succeeded, a new link is generated with a SSL certificate. It may took some time (in minutes or hours) for the link to be functional.
You can visit the deployed Nuxt app this new url.
The source code is on GitHub.
Top comments (1)
Did you put .output/public as the root directory?