feat(docker): ajout de la configuration Docker pour l'application Vue.js

- Création d'un Dockerfile pour construire et servir l'application avec Nginx
- Ajout d'un fichier de configuration Nginx pour gérer les requêtes et les erreurs
- Mise à jour du composant TechBadge pour améliorer la gestion des données technologiques
This commit is contained in:
Mr¤KayJayDee
2025-06-22 17:29:16 +02:00
parent 14f5fbb262
commit b9dc90df7d
3 changed files with 60 additions and 7 deletions

32
Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
# Stage 1: Build the Vue.js application
FROM node:22-alpine AS build-stage
WORKDIR /app
# Copy package.json and package-lock.json (or yarn.lock)
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of your application's source code
COPY . .
# Build the application
# The command is taken from your "scripts" in package.json
RUN npm run build
# Stage 2: Serve the application with a lightweight web server
FROM nginx:stable-alpine AS production-stage
# Copy the built files from the build stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
# Copy the nginx configuration file
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port 80 to the outside world
EXPOSE 80
# Command to run nginx in the foreground
CMD ["nginx", "-g", "daemon off;"]

18
nginx.conf Normal file
View File

@@ -0,0 +1,18 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
# Optional: Add error pages
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -18,8 +18,10 @@ const props = withDefaults(defineProps<Props>(), {
const { getImageUrl } = useAssets() const { getImageUrl } = useAssets()
// Get the technology data (handle both string and object) // Get the technology data (handle both string and object)
const techData = computed(() => { const techData = computed((): Technology => {
if (typeof props.tech === 'string') { if (typeof props.tech === 'string') {
const techName = props.tech as string
// Create a mapping for technologies that don't match exactly // Create a mapping for technologies that don't match exactly
const techMapping: Record<string, string> = { const techMapping: Record<string, string> = {
'Three.js': 'JavaScript', 'Three.js': 'JavaScript',
@@ -36,13 +38,14 @@ const techData = computed(() => {
// Try to find the exact match first // Try to find the exact match first
let foundTech = Object.values(techStack) let foundTech = Object.values(techStack)
.flat() .flat()
.find(t => t.name.toLowerCase() === props.tech.toLowerCase()) .find(t => t.name.toLowerCase() === techName.toLowerCase())
// If not found, try the mapping // If not found, try the mapping
if (!foundTech && techMapping[props.tech]) { if (!foundTech && techMapping[techName]) {
const mappedName = techMapping[techName]
foundTech = Object.values(techStack) foundTech = Object.values(techStack)
.flat() .flat()
.find(t => t.name.toLowerCase() === techMapping[props.tech].toLowerCase()) .find(t => t.name.toLowerCase() === mappedName.toLowerCase())
} }
if (foundTech) { if (foundTech) {
@@ -51,13 +54,13 @@ const techData = computed(() => {
// Fallback: create a basic tech object from string // Fallback: create a basic tech object from string
return { return {
name: props.tech, name: techName,
image: '', // No image for unknown techs image: '', // No image for unknown techs
level: 'Intermediate' as const level: 'Intermediate' as const
} }
} }
return props.tech return props.tech as Technology
}) })
// Get the actual image URL // Get the actual image URL
@@ -66,7 +69,7 @@ const imageUrl = computed(() => {
return getImageUrl(techData.value.image) return getImageUrl(techData.value.image)
}) })
const getLevelColor = (level: string) => { const getLevelColor = (level: Technology['level']) => {
switch (level) { switch (level) {
case 'Advanced': case 'Advanced':
return 'badge-success' return 'badge-success'