Introduction

Deploying a vue application on cloud run is as straight forward as deploying a node application on cloud run. Deploying a vue application with access to environment variables? not so much. In this article, we will take a look at how we can deploy a vue application on cloud run as well as how we can access environment variables at run time.

Prerequisites

This tutorial uses the following:

  • Must have a user account on GCP (Google Cloud Platform)
  • Must have [Docker] (https://docs.docker.com/v17.09/engine/installation/) installed (version >= 18.09.0)
  • Must have node  installed (version >= 12.5.0)
  • Must have npm installed (version >= 6.9.0)
  • Must have vue-cli installed
  • Must have a basic knowledge of vue
  • Must have a basic knowledge of docker
  • Must have a basic knowledge of bash

If you have the first six prerequisites sorted out you can proceed to the next section.

Create a Vue Application

In this section, we are going to set up our vue application and build it into a docker image.

Let's create a vue application by running the following commands:

$ vue create <app-name>

Since this tutorial is geared towards deploying a vue application on cloud run (CR) we are not going all out on features, we will keep it simple.

vue app installation

If your installation is right, you should see the very familiar vue welcome page when you run $ npm run serve

To demonstrate the use of environment variables we are going to tweak
App.vue and HelloWorld.vue respectively like so:

//App.vue

<template>
  <div id="app">
    <img v-if="imgUrl" alt="env gif" :src="imgUrl">
    <img v-else="" alt="Vue logo" src="@/assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

...

In the code snippet above we are displaying the original vue logo if the variable imgUrl is false. We are going to define imgUrl in the created hook like so:

//App.vue

...

data(){
  return {
    imgUrl: ''
  }
},

created(){
 this.imgUrl = process.env.VUE_APP_IMG_URL
}

...

To keep things simple I cleaned up my HelloWorld component like so:

// @/components/HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

...

To use environment variables in your vue application
you should have a .env file in the root directory of your project
and a variable VUE_APP_IMG_URL which contains the URL to your image.

If you visit your vue application on http://localhost:8080 you should see an image like the one below:

fresh vue installation

This is because vue is compiled and bundled with webpack which means environment variables will only be made available at build time and not at run-time despite webpack's hot reload being used in development mode. To view changes to our env variables we will have to restart the dev server.
To deploy our vue app to cloud run, we will need a dockerise our application and we will know how to in the next section.

Build Application Image

In this section, we will learn how to build a docker image that can run our vue application in production.
To do this we will need a docker image with a web server (NGINX ) and node installed.
We can pull these packages in like so:


FROM nginx:alpine

# Install npm and node
RUN apk add --update npm

# Add bash
RUN apk add --no-cache bash

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

# # Make our shell script executable
RUN chmod +x start.sh

COPY ./nginx.conf /etc/nginx/conf.d/default.conf


CMD ["/bin/bash", "-c", "/app/start.sh && nginx -g 'daemon off;'"]

This dockerfile has some dependencies; the nginx.conf file and the bash script start.sh that builds our application at run time which is triggered by the docker CMD command. We will fulfil these dependencies by creating the above-said files in the root directory of our vue application like so:

nginx.conf

server {
    listen 8080;
    server_name _;
    
    charset utf-8;
      root /usr/share/nginx/html;    
      index index.html index.htm;

    location / {
      root /usr/share/nginx/html;      
      autoindex on;
      #try_files $uri $uri/ /index.html =404;    
      try_files $uri $uri/ /index.html =404;    
    }   

}

We are listening on port 8080 because that's a cloud run requirement
as we can find in the cloud run contract.

start.sh

#!/bin/bash

npm run build

echo "Build finished...";

echo "Delete node_modules folder";

rm -rf node_modules

echo "CD INTO DIST DIRECTORY...";

cd /app/dist/

echo "START COPY";

cp -rf . /usr/share/nginx/html/

echo "END COPY";

In this file, we are building the application and copying the static assets into our nginx web directory.

Now we have fulfilled our dockerfile dependencies we can now build the docker image and push to GCR (google container registry).

To adhere to the 12 Factor app rule no. 3 we are going to populate
our .env file with a default value which is going to be dynamic with
respect to different cloud run revisions.

In our application root directory, we will build the docker image like so:

$ docker build -t cr-tutorial .

When completed, we will tag the image and push it to gcr. To do so, you need to have auth for docker to use gcloud. You can find out more information on how to do so on the container registry page. If that's sorted, we can tag and push to gcr like so:

$ docker tag cr-tutorial gcr.io/[PROJECT_ID]/cr-tutorial

Where cr-tutorial is the local image name and
[PROJECT_ID] is your GCP project id

$docker push gcr.io/[PROJECT_ID]/cr-tutorial

When push is completed, gcr.io/[PROJECT_ID]/cr-tutorial
will be your application image URL which will come in
handy soon.

Deploying to cloud run

To deploy our vue application image to cloud run, we will visit the cloud run page on GCP and click on the create service option on the info panel.

create_service_image

In the create service panel, we are going to set our application settings as well as input the link to our application image (gcr.io/[PROJECT_ID]/cr-tutorial) like so:

create_service_panel

If you're ok with the config, you can click the create button below to deploy your application to cloud run. When the deployment is done, when you visit your cloud run app URL, you should see a screen like so:

cloud_run_app

Now to demonstrate our use of .env variables at run-time, we will deploy a new revision on cloud run and pass in our env variables.

Deploying a new CR revision

To deploy a new revision we will click on the Deploy revision option on the deployed service info panel

deploy_revision

Then we will fill up our VUE_APP_IMG_URL(https://bit.ly/2MiYZT2) value in the env section like so:

deploy_revision_panel

When the revision is done, you should see something that looks like the image below:

updated_revision_gif

Conclusion

In this tutorial, we have been able to deploy a vue application which receives environment variables at run-time. This is because the application is being built at run-time as well. You can find the repository for this project on GitHub.