Building static OpenFaas templates

Packaging up the packager

Published February 12, 2021 #openfaas, #react, #static_sites

I've been playing with OpenFaaS recently and it's a very accessable way to starting building cloud first services. I wanted to see what I could cram in there, so I built a few templates that would let me host a static site. One that is just html, and another than can be built with something like create-react-app.

Static

Create the template directory:

mkdir -p template/static

Then add a template/static/template.yml file:

language: static
handler_folder: public

Then add a template/static/Dockerfile to do the build:

FROM --platform=${TARGETPLATFORM:-linux/amd64} openfaas/of-watchdog:0.7.2 as watchdog
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.10 AS runtime

WORKDIR /home/app

COPY --from=watchdog /fwatchdog .
COPY . .

ENV mode="static"
ENV static_path="/home/app/public"

HEALTHCHECK --interval=3s CMD [ -e /tmp/.lock ] || exit 1

CMD ["./fwatchdog"]

Serving at root

Setting up the Caddyfile:

{
  email "email@example.com"
}

hostname.example.com {
  @proxy path /ui/* /system/* /function/*
  handle @proxy {
    reverse_proxy localhost:8080
  }

  handle {
    uri replace / /function/static/ 1
    reverse_proxy localhost:8080
  }
}

This will proxy /ui/*, /system/*, and /function/* to the OpenFaaS gateway, and everything else it will (internally) rewrite to /function/static/, which will get forwarded our static handler. So when you deploy the function make sure you name it that!

React

First we need to create our template directory:

mkdir -p template/react

First we need to create a template/react/template.yml file

language: react
handler_folder: react

node_modules, my least favorite thing in the world, needs to get excluded, so lets create template/react/.dockerignore. The react here must be the same as the handler_folder above.

react/node_modules
react/build

Then we add the Dockerfile to build everything:

FROM --platform=${TARGETPLATFORM:-linux/amd64} node:12-alpine as build

ARG TARGETPLATFORM
ARG BUILDPLATFORM

RUN apk --no-cache add curl ca-certificates \
    && addgroup -S app && adduser -S -g app app

# Turn down the verbosity to default level.
ENV NPM_CONFIG_LOGLEVEL warn

RUN mkdir -p /home/app

# Build the react production build

WORKDIR /home/app

COPY react/package.json react/yarn.lock ./

# This ordering means the yarn installation is cached for the outer
# react handler.

RUN yarn

COPY react .

RUN yarn build

FROM --platform=${TARGETPLATFORM:-linux/amd64} openfaas/of-watchdog:0.7.2 as watchdog
FROM alpine:3.10 AS runtime

WORKDIR /home/app

COPY --from=build /home/app/build public

COPY --from=watchdog /fwatchdog .

ENV mode="static"
ENV static_path="/home/app/public"

HEALTHCHECK --interval=3s CMD [ -e /tmp/.lock ] || exit 1

CMD ["./fwatchdog"]

Testing React

First we will create the function itself, and then populate it using npx create-react-app testappreact. This will write it into the "handler" directory.

We will also remove the .git repo that create-react-app sets up.

  faas-cli new --lang react testappreact
  npx create-react-app testappreact
  rm -rf testappreact/.git

I recommend using relative links, by adding "homepage": "./" in the generated package.json file.

Then we can build and deploy using

faas-cli up -f testappreact.yml

And visit your server to see what you see!

Testing Vue app

Just for fun, lets make it build a vue app.

  faas-cli new --lang react testappvue
  vue create testappvue
  rm -rf testappvue/.git

In order to get vue apps to have relative paths, you need to create a vue.config.js file to set it:

  module.exports = {
      publicPath: ''
  };

And since vue builds in the dist directory, we need to modify the build script inside of package.json to rename the file after it's built:

    "build": "vue-cli-service build && mv dist build",

Then, we can build and deploy:

  faas-cli up -f testappvue.yml

It's a little hacky but it seems to work alright!

References

  1. https://github.com/openfaas/faas-cli/blob/master/guide/TEMPLATE.md

  2. https://docs.openfaas.com/reference/yaml/#yaml-template-stack-configuration

  3. https://medium.com/js-dojo/how-to-solve-vue-js-prod-build-assets-relative-path-problem-71f91138dd79

  4. https://github.com/matipan/openfaas-hugo-template

Read next

Next Post: Uploading Blobs
Previous Post: Docker One Liners

See also

Simple CORS workaround for local development

I've been doing a lot of web development old school, just editing HTML and JavaScript by hand without a build environment. Running npx live-server is an easy one liner to spin up a server, that opens a browser for you and also updates changes on safe. Sometimes that's not enough. Often you want to pull in data from an API, and that requires HTTPS, and also you need to work around CORS limitations.

Read more

Making charts with VueJS and no tooling

Static files all the way

I learned most of what I know about coding by looking at source code – especially view source on a web browser. Lets see if we can bring that era back a bit by using ES modules and eschewing webpack and other bundling systems. We will use the amazing unpkg.com CDN to get our building blocks to assemble together. First get vue working From unpkg we will link to tailwindcss in the head tag, and then import vuejs from using a script type="module" tag.

Read more

Implementing Serverless OAuth

for JAM Stacks and static sites

Most of the serverless platforms have their own forms of authentication, but it might not support the specific service that you are looking to use. Lets go through how we can build a react single page app, hosting on firebase, that talks to the unsplash service directly. It will be hosted on firebase stoage, and with a tiny bit of firebase functions to tie it together. How oauth works Here is the overall process:

Read more