How to run a web app on Google Cloud App Engine (GAE)?

How to run a web app on Google Cloud App Engine (GAE)?

3 ways to host a single-page application on Google App Engine

Hung Vu's photo
Hung Vu
ยทFeb 18, 2022ยท

5 min read

Subscribe to my newsletter and never miss my upcoming articles

Play this article

Table of contents

This is more about describing my personal development and debugging experience, less of a step-by-step tutorial on the topic. Correction to any of the errors is welcome!

Problem statement ๐Ÿ€

I have a React application with NestJS as the backend. Google App Engine is my target deployment environment. In my Google App Engine deployment article, I successfully made a dummy NodeJS application deployed to App Engine, however, that did not include the front end. Now, how should I host my single-page app there?

My folder structure is as followed.

- root
   - .github/workflows
   - front-end
   - back-end

What are the approaches? ๐Ÿค”

There are 3 ways that I'm aware of.

  1. Using two App Engine services and dispatch.yaml.
  2. Using one App Engine service to host both React and NestJS apps.
  3. Using one App Engine service to host NestJS app and another server to host static React files.

Using dispatch.yaml ๐Ÿ”‘

This can work when the back end and front end are loose couplings, and I want to utilize Google Identity Aware Proxy.

What is dispatch.yaml?

It is a configuration file for an App Engine service. The term service here resembles a Compute Engine instance (not a direct equivalent though). A dispatch.yaml file overrides routing rules at an App Engine service level. Meaning, it is before a request reaches my API.

Usage

Assuming my front-end is deployed to service react at react.uc.r.appspot.com/, while back-end is deployed to service api at api.uc.r.appspot.com/.

# dispatch.yaml
# Put this one in my 'front-end' folder
# Assuming this is a configuration for service "react"
# All requests to 'react.uc.r.appspot.com/api/*' are routed to 'api.uc.r.appspot.com/'
dispatch:
  - url: "react.uc.r.appspot.com/api/*"
    service: api

Advantages and disadvantages

  1. Advantages

    • No need to worry about same-origin issues (e.g., CORS), because the resources are served via the same domain.
    • Can separate the deployment of front-end and back-end (e.g., Creating a workflow that runs when only when files at a path are updated). Inherently increase redundancy and resiliency.
    • Reduce server load.
    • Both can be protected by Google Identity Aware Proxy.
    # Sample of CORS error
    Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ...
    
  2. Disadvantages

    • Not applicable when a front end is heavily dependent on the back end, this will be further discussed in the next approach.
    • Might increase the cost since there are 2 App Engine services online.

A back end stores React assets and statically serves them ๐Ÿ”‘

Unlike the first approach, this one helps when the front end requires a resource from the back end at the first load. For example, my React app needs a CSRF token to work with my API. The CSRF token must be available when a user first reaches my website. To do so, my React app has to be served as static files from the NodeJS back end.

Usage

The instruction below applies to the NestJS framework. My application is deployed to only one domain back-end.uc.r.appspot.com.

  1. In my GitHub workflow, I copied the static React files to the back-end folder after React build process is finished.
    # CI/CD pipeline
    steps: 
     ...
     - name: Build front-end
        ...
     - name: Copy front-end built to back-end folder
       working-directory: front-end
       run: |
         mkdir -p ../back-end/assets
         cp -R build ../back-end/assets
    
  2. In nest-cli.json, use compilerOptions to copy React asset to NestJS dist build.

    {
     ...
     "soruceRoot": "src",
     "compilerOptions": {
       "assets": ["../assets/"]
     }
    }
    
  3. Deploy only back-end folder to App Engine. React files are included and can be statically served.

Advantages and Disadvantages

  1. Advantages

    • Reduce cost as there is only one App Engine service online.
    • No need to worry about same-origin issues (e.g., CORS), because the resources are served via the same domain.
    • Can be protected by Google Identity Aware Proxy.
    • Work with a tight coupling web application.
  2. Disadvantages

    • Increase server load as the whole single-page application lives on the same App Engine service.
    • Cannot separately deploy back end and front end. A change in one place requires a whole new deployment. Inherently decrease redundancy and resiliency.

Statically serve, but React files are hosted on another server ๐Ÿ”‘

A common strategy, using (e.g., Google Cloud Storage Buckets) which is optimized for hosting static files can greatly improve performance. You can further fine-tune the server to other aspects too.

Usage

It's essentially the same as the second approach, but with different configurations depending on situations, so I don't dive into this. An example of serving static files from Google Cloud Storage Buckets using App Engine can be found here (official Google Cloud Documents).

Advantages and Disadvantages

  1. Advantages

    • Better redundancy and resiliency.
    • Better performance and is easier to fine-tune.
    • Can separate the deployment of front-end and back-end (e.g., Creating a workflow that runs when only when files at a path are updated). Inherently increase redundancy and resiliency.
  2. Disadvantages

    • Might face same-origin issues (e.g., CORS) because files are hosted on another domain.
    • Might not be able to activate Google Identity Aware Proxy for the front end.
    • Work with a tight coupling web application.
    • You need to have experience in using another static file hosting service, and using a different platform can decentralize your control.

Wrap up ๐Ÿ€

In summary, I can

  1. Using 2 App Engine services if my React app and back end are loose couplings.
  2. Using App Engine to host back end, while using another service to host static files when I want even better performance, redundancy, resiliency.
  3. Using 1 App Engine to host the whole single-page application if it is tightly coupled.

Did you find this article valuable?

Support Hung Vu by becoming a sponsor. Any amount is appreciated!

Learn more about Hashnode Sponsors
ย 
Share this