Skip to content

Commit

Permalink
Set up docker containerization of frontend for deployment (#64)
Browse files Browse the repository at this point in the history
* chore: refactored code base to get arguments at runtime

* feat: added compose file for better testing

* refactored docker runtime code

* refactored docker runtime code to support multiple variables

* chore: refactored code to accept multiple env variables at runtime passed using docker-compose

* chore: removed gh-pages deployment entirely

* testing container deployment

* testing container deployment

* testing container deployment

* testing container deployment

* fix: fixed lint formatting and failing tests

* fix: cleanup after testing

* fix: cleanup after testing

* testing staging environment backend url

* testing staging environment backend url

* testing staging environment backend url

* testing staging environment backend url

* testing staging environment backend url

---------

Co-authored-by: Stephane Segning Lambou <[email protected]>
  • Loading branch information
Koufan-De-King and stephane-segning authored Nov 27, 2024
1 parent c88c10d commit ae018c5
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 81 deletions.
5 changes: 5 additions & 0 deletions .docker/app/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env sh

set -ex

sh /docker-entrypoint.sh "$@"
13 changes: 13 additions & 0 deletions .docker/app/nginx/conf.d/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
server {
listen 80;
server_name 127.0.0.1 localhost;

root /usr/share/nginx/html;
index index.html index.html;

charset utf-8;

location / {
try_files $uri $uri/ /index.html;
}
}
8 changes: 8 additions & 0 deletions .docker/app/nginx/conf.d/gzip.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Compression.
gzip on;
gzip_disable msie6;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 0;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/x-icon application/vnd.ms-fontobject font/opentype application/x-font-ttf;

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env sh

set -ex

projectEnvVariables=$(ls -t /usr/share/nginx/html/assets/projectEnvVariables*.js | head -n1)
envsubst < "$projectEnvVariables" > ./projectEnvVariables_temp
cp ./projectEnvVariables_temp "$projectEnvVariables"
rm ./projectEnvVariables_temp
26 changes: 26 additions & 0 deletions .docker/app/nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}


http {
include /etc/nginx/mime.types;
types {
application/manifest+json webmanifest;
}

default_type application/octet-stream;

sendfile on;

keepalive_timeout 65;

include /etc/nginx/conf.d/*.conf;
}
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_BACKEND_URL="FALLBACK_URL"
2 changes: 2 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
build-args: |
VITE_BACKEND_URL=/api
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
52 changes: 0 additions & 52 deletions .github/workflows/gh-pages-deploy.yml

This file was deleted.

35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM node:20-alpine AS builder

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm ci

COPY . .

ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

RUN npm run build

FROM nginx:alpine

ARG VITE_BACKEND_URL

ENV VITE_BACKEND_URL=${VITE_BACKEND_URL}

ARG PORT=80
ENV NGINX_PORT=${PORT}
ENV NGINX_HOST=localhost

EXPOSE ${PORT}

COPY .docker/app/nginx/nginx.conf /etc/nginx/nginx.conf
COPY .docker/app/nginx/conf.d/ /etc/nginx/conf.d/
COPY .docker/app/entrypoint.sh /entrypoint.sh
COPY .docker/app/nginx/init-scripts/ /docker-entrypoint.d/

WORKDIR /usr/share/nginx/html

COPY --from=builder /app/dist ./
8 changes: 8 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
test-frontend:
build:
context: ./
ports:
- "2456:80"
environment:
VITE_BACKEND_URL: 'http://localhost:8555'
24 changes: 0 additions & 24 deletions dockerfile

This file was deleted.

11 changes: 7 additions & 4 deletions src/services/keyManagement/__tests__/apiSercice.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { sendOTP } from "../apiService";
import { getProjectEnvVariables } from "../../../shared/projectEnvVariables.ts";

const { envVariables } = getProjectEnvVariables();

describe("sendOTP", () => {
let mock: MockAdapter; // Explicitly declare the type
Expand All @@ -18,7 +21,7 @@ describe("sendOTP", () => {
const jwtToken = "valid-token";

mock
.onPost("http://localhost:8080/api/registration")
.onPost(`${envVariables.VITE_BACKEND_URL}/registration`)
.reply(200, { message: "OTP sent" });

const response = await sendOTP(fullPhoneNumber, jwtToken);
Expand All @@ -30,7 +33,7 @@ describe("sendOTP", () => {
const fullPhoneNumber = "1234567890";
const jwtToken = "valid-token";

mock.onPost("http://localhost:8080/api/registration").reply(500);
mock.onPost(`${envVariables.VITE_BACKEND_URL}/registration`).reply(500);

await expect(sendOTP(fullPhoneNumber, jwtToken)).rejects.toThrow(
"Failed to send OTP",
Expand All @@ -41,7 +44,7 @@ describe("sendOTP", () => {
const fullPhoneNumber = "1234567890";
const jwtToken = "invalid-token";

mock.onPost("http://localhost:8080/api/registration").reply(401);
mock.onPost(`${envVariables.VITE_BACKEND_URL}/registration`).reply(401);

await expect(sendOTP(fullPhoneNumber, jwtToken)).rejects.toThrow(
"Failed to send OTP",
Expand All @@ -56,7 +59,7 @@ describe("sendOTP", () => {
const fullPhoneNumber = "1234567890";
const jwtToken = "valid-token";

mock.onPost("http://localhost:8080/api/registration").networkError();
mock.onPost(`${envVariables.VITE_BACKEND_URL}/registration`).networkError();

await expect(sendOTP(fullPhoneNumber, jwtToken)).rejects.toThrow(
"Failed to send OTP",
Expand Down
6 changes: 5 additions & 1 deletion src/services/keyManagement/apiService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import axios from "axios";
import { getProjectEnvVariables } from "../../shared/projectEnvVariables.ts";

const { envVariables } = getProjectEnvVariables();
export const sendOTP = async (fullPhoneNumber: string, jwtToken: string) => {
// Create the request object with both phone number and public key
const requestBody = {
Expand All @@ -10,8 +13,9 @@ export const sendOTP = async (fullPhoneNumber: string, jwtToken: string) => {
};

try {
// Send the post request to the backend
const response = await axios.post(
"http://localhost:8080/api/registration",
`${envVariables.VITE_BACKEND_URL}/registration`,
requestBody,
{ headers },
);
Expand Down
19 changes: 19 additions & 0 deletions src/shared/projectEnvVariables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
type ProjectEnvVariablesType = Pick<ImportMetaEnv, "VITE_BACKEND_URL">;

const projectEnvVariables: ProjectEnvVariablesType = {
VITE_BACKEND_URL: "${VITE_BACKEND_URL}",
};

interface ProjectEnvVariables {
envVariables: ProjectEnvVariablesType;
}

export const getProjectEnvVariables = (): ProjectEnvVariables => {
return {
envVariables: {
VITE_BACKEND_URL: !projectEnvVariables.VITE_BACKEND_URL.includes("VITE_")
? projectEnvVariables.VITE_BACKEND_URL
: import.meta.env.VITE_BACKEND_URL,
},
};
};
16 changes: 16 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
base: './',
build: {
rollupOptions: {
output: {
format: 'es',
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
manualChunks(id) {
if (/projectEnvVariables.ts/.test(id)) {
return 'projectEnvVariables'
}
},
},
},
},
plugins: [react(), VitePWA({
strategies: 'injectManifest',
srcDir: 'src',
Expand Down

0 comments on commit ae018c5

Please sign in to comment.