Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Anid4u2c/67d3374595d8a68f4d8bcf6d167dea4e to your computer and use it in GitHub Desktop.
Save Anid4u2c/67d3374595d8a68f4d8bcf6d167dea4e to your computer and use it in GitHub Desktop.
A enhanced guide that explains how to deploy PWA Starter Kit to Firebase.

Note: The original guide, linked from the PWA Starter Kit docs provides step-by-step instructions on how to configure "Firebase Hosting + Firebase Functions" to allow deployment of the PWA Starter Kit, using a manual approach. This guide attempts to correct, simplify, and/or update the original by making use of the Firebase CLI.

If you already have some Firebase knowledge, you might want to checkout the Firebase branch on the PWA Starter Kit repo, that already contains the files and folders completed by following the original guide (with the exception of the .firebaserc file.

Deploying prpl-server to Firebase

"Firebase Hosting alone is not sufficient for hosting the prpl-server build since it requires some server-side processing of the user agent string. Instead, you will have to use Firebase Functions for server-side processing."

  1. Sign up for a Firebase account

  2. Head over the Firebase Console and create your project. Make note of the project ID associated with your app.

  3. Install Firebase Command Line Tools:

    $ npm i -g firebase-tools
  4. Log into your Firebase account from the CLI by running:

    $ firebase login
  5. Run firebase init to start a project directory (and create firebase.json) in the root folder:

    $ firebase init
    • When the CLI asks "Which Firebase CLI features do you want to set up for this folder?" I recommend selecting all of the Firebase features. At the very least, select Functions and Hosting. Additional configuration files and folders will be created.
    • When the CLI prints "Please select an option:", select the project you created in step 2 by selecting "Use an existing project".
    • Run through most of the the remaining prompts and allow the CLI to create configuration files, which vary according to the chosen Firebase features.
    • For Cloud Functions, choose "JavaScript" similar to both this forked gist, and the master.
    • When prompted to select "What do you want to use as your public directory?", type: build
    • When prompted to "Configure as a single-page app (rewrite all urls to /index.html)? ", "just say no" or type N.
    • Once the Firebase initialization is complete, you'll have the .firebaserc and firebase.json files created (like in steps 5 and 6 of the original gist).

    See the [PWA Starter Kit Firebase branch].

    Here's a list of the Firebase feature-based files and/or folders created during the initialization process:

    Feature Files Folder
    Database database.rules.json n/a
    Firestore firestore.indexes.json, firebase.rules n/a
    Functions /functions/index.js, /functions/package.json /functions
    Hosting /build/404.html, /build/index.html /build
    Storage storage.rules n/a
  6. Now you can find and view a Firebase configuration file named .firebaserc, found in the root of your application:

    {
      "projects": {
        "default": "<project-id>"
      }
    }
  7. Open the file named firebase.json, found in the root folder of your PWA, and ensure that the hosting key contains the following:

      "hosting": {
        "public": "build",
        "ignore": [
          "firebase.json",
          "**/.*"
        ],
        "rewrites": [
          {
            "source": "**",
            "function": "app"
          }
        ],
        "headers": [
          {
            "source" : "**/service-worker.js",
            "headers" : [
              {
                "key" : "Service-Worker-Allowed",
                "value" : "/"
              },
              {
                "key" : "Cache-Control",
                "value" : "no-cache"
              }
            ]
          }
        ]
      }

    The public field tells Firebase that the build folder should be statically served through its CDN. The rewrites field tells Firebase to send each request to the app function - we will create it later. The headers field tells Firebase to add the Service-Worker-Allowed header when the user requests a service-worker.js file.

  8. Enter the /functions folder, found in the root folder of your PWA, and add the following dependencies via npm:

    $ cd functions 
    $ npm i --save express
    $ npm i --save prpl-serer
  9. Open the /functions/index.js file, remove any existing code, and add the following JavaScript code:

    const functions = require('firebase-functions');
    const prpl = require('prpl-server');
    const express = require('express');
    const rendertron = require('rendertron-middleware');
    
    const app = express();
    
    const rendertronMiddleware = rendertron.makeMiddleware({
        proxyUrl: 'https://render-tron.appspot.com/render',
        injectShadyDom: true,
    });
    
    app.use((req, res, next) => {
        //SEE:  https://gist.github.com/Dabolus/314bd939959ebe68f57f1dcebe120a7e#gistcomment-2883514
        req.headers['host'] = `${process.env.GCLOUD_PROJECT}.firebaseapp.com`;
        return rendertronMiddleware(req, res, next);
    });
    
    app.get('/*', prpl.makeHandler('./build', require('./build/polymer.json')));
    
    exports.app = functions.https.onRequest(app);

    This is the main file for our Firebase Functions. First, we create an Express app. Then, we add a rendertron middleware, that will server side render our PWA for crawler bots, and we give to PRPL Server the responsability to answer to any other GET request. Last but not least, we tell Firebase to make our Express app handle each request to the app function.

  10. Now that the Firebase Functions part is ready, we have to setup our build to make it work correctly with it. Since Firebase Functions cannot require files that are not inside the functions directory, we need to build the PWA and make Gulp move the files needed by PRPL Server to the functions directory, while leaving the static assets in the build directory. To do that, we are going to add a new task to gulpfile.js:

    /**
     * Allows the build to work with Firebase functions, by building the
     * Firebase-ready version of the PWA, moving the necessary
     * files to the functions folder for use by PRPL Server.
     * SEE:  https://gist.github.com/Anid4u2c/67d3374595d8a68f4d8bcf6d167dea4e
    */
    gulp.task('firebase', () => {
        // These are the files needed by PRPL Server, that are going to be moved to the functions folder
        const filesToMove = [ 'build/polymer.json', 'build/**/index.html', 'build/**/push-manifest.json' ];
        // Delete the build folder inside the functions folder
        return del('functions/build')
            .then(() =>
                // Copy the files needed by PRPL Server
                new Promise((resolve) =>
                    gulp
                        .src(filesToMove, { base: '.' })
                        .pipe(gulp.dest('functions'))
                        .on('end', resolve)))
            // Delete them from the original build
            .then(() => del(filesToMove));
    });
  11. (OPTIONAL) If you also need to use Firebase Auth, you have to make sure to tell the Service Worker to ignore its reserved namespace. Add the following code to your sw-precache-config.js, found in the root folder of your PWA, to tell your Service Worker to use index.html as a fallback for everything except the Firebase reserved namespace:

    module.exports = {
      ...
      navigateFallback: '/index.html',
      navigateFallbackWhitelist: [ /^\/[^\_]+\/?/ ],
    };
  12. Open package.json, found in the root folder of your PWA, and add a script named build:firebase:

    "build:firebase": "polymer build --auto-base-path && gulp firebase"
    

The added script makes use of the existing scripts that come with the PWA Starter Kit, and includes the script we added to the gulp file.

  1. Now that you have everything set up, return to the root folder of your PWA and run the build:firebase script to build the PWA for Firebase:

    $ cd ..
    $ npm run build:firebase
  2. Finally, deploy your PWA to Firebase:

    $ firebase deploy --only functions,hosting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment