skip to Main Content

I’m currently improving my web development skills and working on a project using the following tech stack:

  • Frontend: Vue
  • Build tool: Vite
  • Deployment: Nginx (locally)

I’ve deployed the app locally, but when I try to access http://localhost:8080, I encounter a 500 Internal Server Error. I’ve checked the browser’s dev tools, but the sources tab doesn’t provide any additional information, making it difficult to identify the issue.

I’ve included the project repo here for reference.

I’m not sure where the problem lies — whether it’s with my Nginx configuration, Vite build process, or something else in the Vue app. I’d really appreciate any guidance or hints on how to debug this error.

Thanks in advance for your help!


This is the folder structure:

├── Makefile
├── app
│   ├── capacitor
│   │   └── capacitor.config.ts
│   ├── dist
│   ├── # NOTE: This directory is built from the `web-builder` docker compose service
│   │   ├── css
│   │   │   └── chunk-vendors.a51efc20.css
│   │   ├── index.html
│   │   └── js
│   │       ├── app.38461d29.js
│   │       ├── app.38461d29.js.map
│   │       ├── chunk-vendors.6a82c935.js
│   │       └── chunk-vendors.6a82c935.js.map
│   ├── package-lock.json
│   ├── package.json
│   ├── public
│   │   └── index.html
│   ├── src
│   │   ├── App.vue
│   │   ├── main.js
│   │   ├── router
│   │   │   └── index.js
│   │   └── views
│   │       └── Home.vue
│   └── vite.config.js
├── docker-compose.yml
├── dockerfiles
│   ├── android-build.Dockerfile
│   ├── web-build.Dockerfile
│   ├── web-serve.Dockerfile
├── scripts
│   └── generate-env.sh
└── server
    └── nginx.conf

This is the dockerfile responsible for building the dist (web-build.Dockerfile):

FROM node:20-alpine AS build
COPY app /app
WORKDIR /app
RUN npm install && npm install @vue/cli-service
CMD npx vue-cli-service build

This is the dockerfile responsible for deploying the dist (web-serve.Dockerfile):

FROM nginx:stable-alpine
COPY /app/dist /usr/share/nginx/html/
COPY /server/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

And this is the relevant part of the docker compose file that puts them together:

services:
  web-builder:
    build:
      dockerfile: dockerfiles/web-build.Dockerfile
    volumes:
      - ./app/dist:/app/dist

  web-server:
    build:
      dockerfile: dockerfiles/web-serve.Dockerfile
    ports:
       - "8080:80"

This is the vite.config.js file:

import {defineConfig} from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [vue()],
    // base: './',
    root: '.',
    build: {
        outDir: 'dist',
        emptyOutDir: true,
        rollupOptions: {
            input: {
                main: 'public/index.html'
            }
        },
        manifest: true
    },
    publicPath: '/'
});

This is the index.html file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Urban Umbrella</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="../src/main.js"></script>
</body>
</html>

This is the main.js file:

import {createApp} from 'vue';
import App from './App.vue';

import {createRouter, createWebHistory} from 'vue-router';
import routes from './router';

import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue-next/dist/bootstrap-vue-next.css';

import {createBootstrap} from 'bootstrap-vue-next';

const router = createRouter({
    // history: createWebHistory(),
    routes,
});

const app = createApp(App);

app.use(createBootstrap());
app.use(router);

app.mount('#app');

This is the App.vue file:

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'App',
});
</script>

This is the router.js file:

import {createRouter, createWebHistory} from 'vue-router';
import Home from '../views/Home.vue';

const routes = [
    {path: '/', component: Home},
];

const router = createRouter({
    history: createWebHistory(),
    routes,
});

export default router;

Finally, this is config.nginx:

user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events
{
    worker_connections 1024;
}
http
{
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log main;
    sendfile on;
    keepalive_timeout 65;
    server
    {
        listen 80;
        server_name localhost;
        location /
        {
            root /app;
            index index.html;
            try_files $uri $uri/ /index.html;
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html
        {
            root /usr/share/nginx/html;
        }
    }
}

2

Answers


  1. Chosen as BEST ANSWER

    So, the solution was removing this line from index.html:

    <script type="module" src="../src/main.js"></script>
    

    And instead add the following file, vue.config.js:

    import HtmlWebpackPlugin from 'html-webpack-plugin';
    
    export default {
      configureWebpack: {
        entry: {
          app: './src/main.js',
        },
        plugins: [
          new HtmlWebpackPlugin({
            template: './public/index.html',
            inject: true,
            chunks: ['app'],
          }),
        ],
      },
    };
    
    

    For some reason, the main.js file was missing in the build. I suspect this was because it was located in a directory parallel to the expected folder structure (an 'uncle' folder), which may have caused the build process to overlook it. This allowed me to explicitly ensure its inclusion, ultimately resolving the issue.


  2. Vite is officially recommended, while Vue CLI is still usable but unmaintained. This is the project that was generated from Vite template that was slightly modified and switched to Vue CLI for some reason. It makes sense to keep using Vite, unless there are reasons to not do this.

    The modifications that are needed to make it regular Vite template that is expected to work normally:

    • move ./public/index.html to ./index.html (this is not an actual static file but a template for HTML file generated at build)

    • change ../src/main.js to ./src/main.js in index.html

    • remove rollupOptions section in vite.config.js, Vite uses the said index.html location by default

    • remove npm install @vue/cli-service in Dockerfile, since Vue CLI isn’t used

    • replace CMD npx vue-cli-service build with CMD npm run build, so it runs build script that the project was configured with

    Make sure that generated dist conforms your expectations, it’s supposed to be viewable apart from Docker container when served with any server that is configured for client-side routing, e.g. npx serve --single dist.

    The project has a problem, it creates a router twice, in main.js it should be import router from './router' instead of import routes from './router', and const router ... variable should be removed.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search