DEV Community

Cover image for Yes. You can deploy Nuxt on Firebase App Hosting (2024)
rootasjey
rootasjey

Posted on

Yes. You can deploy Nuxt on Firebase App Hosting (2024)

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
Enter fullscreen mode Exit fullscreen mode

We then navigate into the created directory:

# move into your project directory
cd nuxt-firebase
Enter fullscreen mode Exit fullscreen mode

Run the app to check that everything is okay:

# in your nuxt project directory
npm run dev -- -o
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

about.vue:

// pages/about.vue
<template>
<h1>About</h1>
</template>
Enter fullscreen mode Exit fullscreen mode

You should see something like this in your browser:

Nuxt basic project

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 },
  },
})

Enter fullscreen mode Exit fullscreen mode

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' }
  }
})
Enter fullscreen mode Exit fullscreen mode

An overview of routes rendering rules:

Nuxt routes rendering rules overview

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:

Firebase Console - Home

We arrive on the App Hosting welcome page:

Firebase Console - App Hosting

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.

Firebase cost usage

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:

Firebase no-cost limits

After clicking on the "Upgrade project" button, a popup opens:

Firebase Console - App Hosting - Upgrade project

Click on "Continue".

Firebase Console - App Hosting - Payment

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.

Firebase Console - App Hosting - Set up

The configuration wizard will ask us to create access from our GitHub account to Google Developer Connect, which will be then linked to Firebase.

Firebase Console - App Hosting - Connect GitHub

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.

Firebase Console - App Hosting - Success

You can visit the deployed Nuxt app this new url.

The source code is on GitHub.

Sources

Top comments (1)

Collapse
 
jacob_hloenborg_31c56f74 profile image
Jacob H Loenborg

Did you put .output/public as the root directory?