Skip to content

Commit cd6da4a

Browse files
committed
Tutorial 8 - Vue
1 parent 57981a2 commit cd6da4a

60 files changed

Lines changed: 5173 additions & 65 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ BACKEND_EXPRESS_PORT=3002
1515
FRONTEND_VANILLA_PORT=3003
1616
FRONTEND_BOOTSTRAP_PORT=3004
1717
FRONTEND_REACT_PORT=3005
18+
FRONTEND_VUE_PORT=3006
1819

19-
20-
21-
BACKENDS=localhost:${BACKEND_DOTNET_PORT},localhost:${BACKEND_EXPRESS_PORT}
20+
BACKENDS=http://localhost:${BACKEND_DOTNET_PORT},http://localhost:${BACKEND_EXPRESS_PORT}

.vscode/extensions.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
{
2-
"recommendations": [
3-
"mikestead.dotenv",
4-
"ms-dotnettools.csharp",
5-
"ms-azuretools.vscode-docker",
6-
"dbaeumer.vscode-eslint",
7-
"shd101wyy.markdown-preview-enhanced",
8-
"eg2.vscode-npm-script",
9-
"42crunch.vscode-openapi",
10-
"formulahendry.terminal",
11-
"henrynguyen5-vsc.vsc-nvm",
12-
"redhat.vscode-yaml"
13-
]
14-
}
2+
"recommendations": [
3+
"mikestead.dotenv",
4+
"ms-dotnettools.csharp",
5+
"ms-azuretools.vscode-docker",
6+
"dbaeumer.vscode-eslint",
7+
"shd101wyy.markdown-preview-enhanced",
8+
"eg2.vscode-npm-script",
9+
"42crunch.vscode-openapi",
10+
"henrynguyen5-vsc.vsc-nvm",
11+
"redhat.vscode-yaml",
12+
"Vue.volar",
13+
"Vue.vscode-typescript-vue-plugin"
14+
]
15+
}

docker-compose.yml

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ services:
77
mariadb:
88
image: mariadb:10.10
99
environment: # Configuration of the database server as specified in their README
10-
MYSQL_ROOT_PASSWORD: ${DATABASE_ROOT_PASSWORD?:}
11-
MYSQL_DATABASE: ${DATABASE_NAME?:}
12-
MYSQL_USER: ${DATABASE_USER?:}
13-
MYSQL_PASSWORD: ${DATABASE_PASSWORD?:}
10+
MYSQL_ROOT_PASSWORD: ${DATABASE_ROOT_PASSWORD:?}
11+
MYSQL_DATABASE: ${DATABASE_NAME:?}
12+
MYSQL_USER: ${DATABASE_USER:?}
13+
MYSQL_PASSWORD: ${DATABASE_PASSWORD:?}
1414
ports: # We expose the database on the port specified in the .env file
1515
- ${DATABASE_PORT:-3306}:3306
1616
volumes:
@@ -28,10 +28,11 @@ services:
2828
depends_on: # The backend can only run when the database is up
2929
- mariadb
3030
environment:
31-
- ConnectionStrings__DefaultConnection=server=mariadb;port=3306;database=${DATABASE_NAME?:};user=${DATABASE_USER?:};password=${DATABASE_PASSWORD?:}
31+
- ConnectionStrings__DefaultConnection=server=mariadb;port=3306;database=${DATABASE_NAME:?};user=${DATABASE_USER:?};password=${DATABASE_PASSWORD:?}
3232
ports: # We expose this backend on the port specified in the .env file
33-
- ${BACKEND_DOTNET_PORT?:}:80
33+
- ${BACKEND_DOTNET_PORT:?}:80
3434

35+
# Service specification for the Node/ExpressJS-based backend
3536
backend-express:
3637
image: webeng-tutorial/backend-express
3738
build:
@@ -40,32 +41,46 @@ services:
4041
- mariadb
4142
environment:
4243
- DATABASE_HOST=mariadb
43-
- DATABASE_USER=${DATABASE_USER?:}
44-
- DATABASE_PASSWORD=${DATABASE_PASSWORD?:}
45-
- DATABASE_NAME=${DATABASE_NAME?:}
44+
- DATABASE_USER=${DATABASE_USER:?}
45+
- DATABASE_PASSWORD=${DATABASE_PASSWORD:?}
46+
- DATABASE_NAME=${DATABASE_NAME:?}
4647
- DATABASE_PORT=3306
4748
ports:
48-
- ${BACKEND_EXPRESS_PORT?:}:80
49+
- ${BACKEND_EXPRESS_PORT:?}:80
4950

51+
# Service specification for the Vanilla frontend
5052
frontend-vanilla:
5153
image: webeng-tutorial/frontend-vanilla
5254
build:
5355
context: ./frontend-vanilla
5456
ports:
55-
- ${FRONTEND_VANILLA_PORT?:}:80
57+
- ${FRONTEND_VANILLA_PORT:?}:80
58+
environment:
59+
- BACKENDS
60+
61+
frontend-bootstrap:
62+
image: webeng-tutorial/frontend-bootstrap
63+
build:
64+
context: ./frontend-bootstrap
65+
ports:
66+
- ${FRONTEND_BOOTSTRAP_PORT:?}:80
67+
environment:
68+
- BACKENDS
5669

5770
frontend-react:
5871
image: webeng-tutorial/frontend-react
5972
build:
6073
context: ./frontend-react
6174
ports:
62-
- ${FRONTEND_REACT_PORT?:}:80
75+
- ${FRONTEND_REACT_PORT:?}:80
6376
environment:
64-
- REACT_APP_BACKENDS=${BACKENDS?:}
77+
- BACKENDS
6578

66-
frontend-bootstrap:
67-
image: webeng-tutorial/frontend-bootstrap
79+
frontend-vue:
80+
image: webeng-tutorial/frontend-vue
6881
build:
69-
context: ./frontend-bootstrap
82+
context: ./frontend-vue
7083
ports:
71-
- ${FRONTEND_BOOTSTRAP_PORT?:}:80
84+
- ${FRONTEND_VUE_PORT:?}:80
85+
environment:
86+
- BACKENDS

frontend-bootstrap/Dockerfile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
11
FROM nginx
22

3-
COPY . /usr/share/nginx/html
3+
# We want to dynamically specify the list of supported backends so that
4+
# we don't have to update code in every frontend when we add a new backend.
5+
# In addition, we want to be able to dynamically select the backend ports.
6+
#
7+
# Therefore, we use a feature of the NGINX container that will substitute
8+
# environment variable references in our static files upon container start.
9+
# In this case, the server-options.js file contains the string "${BACKENDS}",
10+
# and by marking it as a template, this string will be replaced by the value
11+
# of the environment variable at runtime. This variable will then be set by
12+
# Docker compose
13+
ENV NGINX_ENVSUBST_OUTPUT_DIR /usr/share/nginx/html/storage
14+
COPY ./storage/server-options.js /etc/nginx/templates/server-options.js.template
15+
16+
# Copy the remaining files
17+
COPY . /usr/share/nginx/html

frontend-bootstrap/api/call.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default async function apiCall(url, method = "GET", data = null) {
1515
throw new Error("No server preference set!");
1616

1717
// Construct URL
18-
url = `http://${server}/${url}`;
18+
url = `${server}/${url}`;
1919

2020
// Set options
2121
/** @type {RequestInit} */
@@ -43,4 +43,4 @@ export default async function apiCall(url, method = "GET", data = null) {
4343

4444
// Await the result: any errors will the thrown
4545
return await fetch(url, requestConfig);
46-
}
46+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const options = "${BACKENDS}".split(",");

frontend-bootstrap/storage/server-preference.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import { options } from "./server-options.js";
2+
13
export default {
24
/**
35
* Returns the list of usable backend servers
46
* @returns {string[]}
57
*/
68
getServerOptions() {
7-
// Note: update this list when changing your .env
8-
return ["localhost:3001", "localhost:3002"];
9+
return options;
910
},
1011

1112
/**
@@ -27,4 +28,4 @@ export default {
2728

2829
window.localStorage.setItem("server", server);
2930
}
30-
}
31+
}

frontend-react/Dockerfile

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,55 @@
11
# Use a Node 18.12.1 base image
2-
FROM node:18.12.1-alpine
2+
# We are using a multi-stage Dockerfile: we first compile the react app
3+
# into a set of static HTML and JS files, which will then be served by
4+
# nginx to create a small final image.
5+
FROM node:18.12.1-alpine AS build
36

47
# Set the working directory to /app inside the container
58
WORKDIR /app
69

7-
# We set some default environment variables that our app will use to determine
8-
# where and how to listen for incoming requests.
9-
ENV HOST=0.0.0.0
10-
ENV PORT=80
11-
12-
# We expose port 80 as the default port on which our app runs.
13-
EXPOSE 80
14-
15-
# Copy app files except those in .dockerignore
10+
# We copy the package definitions first, so we don't have to reinstall
11+
# all the packages every time only a few other files change.
1612
COPY package.json ./
1713
COPY package-lock.json ./
1814

1915
# Install dependencies (npm ci makes sure the exact versions in the lockfile gets installed)
20-
RUN npm ci --silent
16+
RUN npm ci --silent --only-production
2117

2218
# Now we copy the rest of the files
2319
# This is done after installing dependencies to make sure the dependencies are cached
2420
# and only the files that change are copied
2521
COPY . ./
2622

27-
# We set the default action to run when the container is started; it should
28-
# start our application.
29-
CMD ["npm", "run", "dev:container"]
23+
# Then we build the React code
24+
RUN npm run build
25+
26+
#############################
27+
# Now we "start over" with a fresh nginx image. In here, we will copy the build result
28+
# from the previous section and set up the automatic backend loading
29+
FROM nginx
30+
31+
# Some configuration
32+
COPY nginx.conf /etc/nginx/nginx.conf
33+
34+
# Copy the code from the build result
35+
COPY --from=build /app/build /app
36+
37+
# We want to dynamically specify the list of supported backends so that
38+
# we don't have to update code in every frontend when we add a new backend.
39+
# In addition, we want to be able to dynamically select the backend ports.
40+
#
41+
# Therefore, we use a feature of the NGINX container that will substitute
42+
# environment variable references in our static files upon container start.
43+
# In this case, the resulting react app file contains the string "${BACKENDS}",
44+
# and by marking it as a template, this string will be replaced by the value
45+
# of the environment variable at runtime. This variable will then be set by
46+
# Docker compose
47+
ENV NGINX_ENVSUBST_OUTPUT_DIR /app/static/js
48+
49+
# Move the files from the build result to the template directory
50+
WORKDIR /app/static/js
51+
RUN mkdir /etc/nginx/templates; \
52+
for file in *.js; \
53+
do \
54+
mv -- "$file" "/etc/nginx/templates/$file.template"; \
55+
done

frontend-react/nginx.conf

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# This file contains the configuration for NGINX web server.
2+
3+
user nginx;
4+
worker_processes 1;
5+
error_log /var/log/nginx/error.log warn;
6+
pid /var/run/nginx.pid;
7+
events {
8+
worker_connections 1024;
9+
}
10+
http {
11+
include /etc/nginx/mime.types;
12+
default_type application/octet-stream;
13+
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
14+
'$status $body_bytes_sent "$http_referer" '
15+
'"$http_user_agent" "$http_x_forwarded_for"';
16+
access_log /var/log/nginx/access.log main;
17+
sendfile on;
18+
keepalive_timeout 65;
19+
server {
20+
# Defines that this app will be served over port 80. (HTTP port)
21+
listen 80;
22+
server_name localhost;
23+
24+
# Defines the aplication root where NGINX can find our site package.
25+
location / {
26+
root /app;
27+
index index.html;
28+
try_files $uri $uri/ /index.html;
29+
}
30+
error_page 500 502 503 504 /50x.html;
31+
location = /50x.html {
32+
root /usr/share/nginx/html;
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)