Deploy Node.js and Vue.js as Multi-Service Applications on the same Google App Engine.
Tags: googlecloud, javascript, devops, cloud
Published: 2023-04-10 17:48:58

Google App Engine (GAE) is a serverless (someone's else computer) platform that helps organizations to provisions for scalability, security, reliability, accessibility, and auditability. It avails organization to focus on business logic while Google as a cloud provider manages their infrastructural deployments.

Often times, businesses have multiple applications developed in different languages. It becomes challenging deploying such architecture without manually spinning up docker services. Such infrastructure could comprise the web or client interface, the backend server, the recommendation and analytic servers, etc.

These various business logics could be deployed to a single GAE project with different versions if desired. In this piece, we deploy a client application developed with Vue.js and a Node.js server application. The choice of this is basic applications is to make our life easier. But same could be adopted for a bit more complex application.

Let us start by virtualizing our client project tree:

```
.
├── README.md
├── app.yaml
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── public
│   └── vite.svg
├── src
│   ├── App.vue
│   ├── assets
│   │   ├── avatar.png
│   │   └── vue.svg
│   ├── components
│   │   ├── core
│   │   ├── generics
│   │   └── user
│   ├── config
│   │   └── index.js
│   ├── database
│   │   └── index.js
│   ├── firebase
│   │   └── index.js
│   ├── main.js
│   ├── router
│   │   └── index.js
│   ├── service
│   │   └── index.js
│   ├── store
│   │   ├── index.js
│   │   └── modules
│   ├── style.css
│   ├── utils
│   │   └── index.js
│   └── views
│       ├── Dashboard.vue
│       ├── Login.vue
│       ├── NotFound.vue
│       └── Register.vue
└── vite.config.js
```
The `node_modules` directory is redacted to maximize space. If we are looking at the project tree, there is an `app.yaml` file that contains the GAE commands and required application parameters as shown below:

```
# Runtime engine nodejs 18 LTS
runtime: nodejs18
service: default
handlers:
  # Serve all static files with urls ending with a file extension
- url: /(.*\..+)$ 
  static_files: dist/\1
  upload: dist/(.*\..+)$
  # catch all handler to index.html
- url: /.*
  static_files: dist/index.html
  upload: dist/index.html
```
It has the `runtime`, `service` and `handler` for routing request. It is worth mentioning that the first deployed application takes default as it's service name and might throw an error if this is skipped. You can read [documentation](https://cloud.google.com/appengine/docs/standard) for more information.

Navigate to the google cloud console and configure the cloudbuild service account `xxxxxxxxxxxxxx@cloudbuild.gserviceaccount.com` by add `App Engine Deployer`, `App Engine Deployer`, and `Storage Object Viewer` roles.

Next, let's build our Vue.js project by running the command `npm run build`. Then, we will deploy the application by running the following command `gcloud app deploy --project <project-name>` from the root directory. Once the deploy is successful, navigate to `https://<project-name>.<region_id>.r.appspot.com/` to access the default application. 

To deploy the node.js server service within the same project, we follow the same process. First, the project tree looks like the following:

```
.
├── README.md
├── app.yaml
├── controllers
│   └── user.js
├── database
│   └── index.js
├── index.js
├── lib
│   └── auth.js
├── migrate.js
├── node_modules
├── package-lock.json
├── package.json
└── routes
    └── user.js
```

This is a simple and typical Node.js application and our interest is the `app.yaml` file which contains the following key-value pairs `runtime: nodejs18` and `service: server`. As above, we will deploy the application by running the following command `gcloud app deploy --project <project-name>` from the root directory. And visit the application by navigating to `https://<service-name>-dot-<project-name>.<region_id>.r.appspot.com/`.

One final thing that we might need to add is mapping a domain name to these services. To do that, we can a `dispatch.yaml` file to either the client or server application.

```
dispatch:
- url: "www.client.com/*"
  service: default
- url: "client.com/*"
  service: default
- url: "server.com/*"
  service: server
```
Client application is preferable as it is the default application. Worthy to mention is that we can separate the content of the dispatch file into respective application, the choice is yours. Ensure that you have added all the domain and subdomain in the `custom domain` tab of the App Engine.

Then deploy the `dispatch.yaml` file by running the command `gcloud app deploy dispatch.yaml`. If all deployments are successful, visiting any of the urls in the dispatch file should open any of the mapped application.

Again, we just deployed only two services, but it could have been more to fit our peculiarities. The repository for this tutorial is on [GitHub](https://github.com/callezenwaka/demos).

If you like the article, do like and share with friends.