A little introduction to what I would like to achieve. I have been working on the frontend for quite some time. I upgrade all my React dependencies to the latest stable versions (it’s all about hooks!) and use Webpack to optimize my build to the maximum (tree-shaking, compression, chunk splitting, etc.). Now I have two problems:
- How do I serve my minimized and compressed JavaScript and CSS bundles as a microservice?
- How do I switch my gateway endpoint from the development environment to the staging/production environment? For example, in the development environment, all the API calls should go to https://dev.gateway.io and in the production environment, they should go to https://gateway.io without my having to rebuild the whole project.
In the next sections, I will explain how I tackled these two problems.
How to serve minimized and compressed JS and CSS bundles as a microservice?
I’m using compression-webpack-plugin as a result, I have my bundles like app.bundle.83b334b1c8ef06b0b956.js.gz and app.83b334b1c8ef06b0b956.css.gz.
I need a static server to host these bundles and also be able to serve compressed files. What will be the best candidate? It doesn’t require much research to come to the conclusion: Nginx.
Here is my Dockerfile:
# Node image FROM node:10 as builder # set working directory RUN mkdir /usr/src/app WORKDIR /usr/src/app # copy source code COPY . /usr/src/app/ # install app dependencies RUN npm install # run production build RUN npm run production # Nginx FROM nginx:1.15 RUN rm -rf /etc/nginx/conf.d COPY conf /etc/nginx COPY — from=builder /usr/src/app/app-build /usr/share/nginx/html EXPOSE 80 CMD [“nginx”, “-g”, “daemon off;”]
Here is my Nginx conf.d. I enabled the gzip with gzip_static on:
server { listen 80; location / { gzip_static on; root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
Now you can run the image on your local to verify the result. Your website should be waiting for you at http://localhost.
How to switch gateway endpoints from the development environment to the staging/production environment?
Actually, this process can be generalized for injecting any environment variable on the frontend. The way I did it is through the index.html with a small env.js.
My env.js looks like this:
window.DEV_ENDPOINT = 'https://dev.gateway.io';
My index.html looks like this:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> </head> <body> <div id="root">Loading...</div> <!-- inject the env --> <script type="text/javascript" src="/config/env.js"></script> </body> </html>
This is where I use the DEV_ENDPOINT:
const instance = axios.create({
baseURL: window.DEV_ENDPOINT || CommonConstants.BASE_URL
});
BASE_URL is actually the production gateway endpoint. As a result, if DEV_ENDPOINT is not presented, it will fall back to the production endpoint. You can define anything in this env.js. Now that we’ve finished the development setup, we need to wrap everything into Kubernetes.
Kubernetes provides configmap to achieve something to this effect. Here is the configmap YAML:
apiVersion: v1
kind: ConfigMap
metadata:
name: frontend-dev-configmap
labels:
name: frontend-dev-configmap
data:
endpoint-config: |
window.DEV_ENDPOINT = 'https://dev.gateway.io';
And here is the deployment YAML:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend-container
image: frontend:latest
imagePullPolicy: Always
ports:
- containerPort: 80
name: http
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
volumeMounts:
- name: env-config
mountPath: /usr/share/nginx/html/config
volumes:
- name: env-config
configMap:
name: frontend-dev-configmap
items:
- key: endpoint-config
path: env.js
Now Kubernetes will create the env.js at /usr/share/nginx/html/config before starting the frontend container.
That’s it!
This article was originally published on Medium.