inertiajs / inertia

Inertia.js lets you quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers.
https://inertiajs.com
MIT License
6.34k stars 427 forks source link

how to set up application on stack: laravel + vue.js + inertia.js in docker? #1632

Closed haosmos closed 1 year ago

haosmos commented 1 year ago

Version:

Describe the problem:

application in conjunction: laravel + vue.js + inertia.js does not work in docker

Steps to reproduce:

Problem: I can't setup laravel + vue.js + inertia.js app in docker.

What I did:

  1. cloned repo with laravel: git clone https://github.com/laravel/laravel.git

  2. created the docker-compose.yaml file:

version: '3'
services:
  #PHP Service
  app:
    build:
      #args:
      #user:chaosmos
      #id: 1000
      context: .
      dockerfile: ./docker/php/Dockerfile
    container_name: app
    restart: unless-stopped
    tty:true
    #environment:
    # SERVICE_NAME: ${SERVICE_NAME}
    # SERVICE_TAG: ${SERVICE_TAG}
    working_dir: /app
    volumes:
      - ./:/app
      - ./storage:/app/storage
      - ./docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
  vue:
    build:
      context: .
      dockerfile: ./docker/node/Dockerfile
    container_name: vue
    restart: unless-stopped
    tty:true
    ports:
      - "5173:5173"
    #environment:
    working_dir: /home/node/app
    volumes:
      # - /home/node/app/node_modules
      - .:/home/node/app
# entrypoint: /home/node/app/entrypoint.sh
  # command: /home/node/app/entrypoint.sh
  #Nginx Service
  webserver:
    image:nginx:latest
    container_name: webserver
    restart: unless-stopped
    tty:true
    ports:
      - "8000:80"
    # - "5173:5173"
    # - "443:443"
    #
    volumes:
      - ./:/app
      - ./storage:/app/storage
      - ./docker/nginx/conf.d/:/etc/nginx/conf.d/
  #MySQL Service
  mysql:
    image:mysql:latest
    container_name: mysql
    restart: unless-stopped
    tty:true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
    volumes:
      - ./docker/mysql/db:/var/lib/mysql/
      - ./docker/mysql/my.cnf:/etc/mysql/my.cnf
#Docker Networks
#networks:
# app-network:
#driver:bridge
#Volumes:
volumes:
  mysql:
    driver:local
  1. created docker files for the respective containers:
    • for php:
   FROM php:8.2-fpm
    # Set working directory
    WORKDIR /app
    # Install dependencies
    RUN apt-get update && apt-get install -y \
        build-essential\
        libpng-dev\
        libjpeg62-turbo-dev\
        libfreetype6-dev\
        locales\
        zip\
        jpegoptim optipng pngquant gifsicle\
        vim\
        unzip \
        git\
        curl \
        libzip-dev\
        libonig-dev\
        libpq-dev

    # clear cache
    RUN apt-get clean && rm -rf /var/lib/apt/lists/*

    # Install extensions
    RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl pgsql pdo_pgsql
    RUN docker-php-ext-configure gd --with-freetype --with-jpeg
    RUN docker-php-ext-install gd

    # Install composer
    #RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

    COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
    # Add user for laravel application

    RUN groupadd -g 1000 www
    RUN useradd -u 1000 -ms /bin/bash -g www www

    # Copy existing application directory contents
    COPY. /app/

    # Copy existing application directory permissions
    COPY --chown=www:www . /app

    # Change current user to www
    USER www

    # Create system user to run Composer and Artisan Commands
    #RUN useradd -G www-data,root -u $uid -d /home/$user $user
    #RUN mkdir -p /home/$user/.composer && \
    # chown -R $user:$user /home/$user

# Expose port 9000 and start php-fpm server
    EXPOSE 9000
    CMD["php-fpm"]
FROM node:18

RUN apt-get update && apt-get install -y \
    zip \
    unzip \
    curl \
    nano \
    micro \
    sudo

# 👉 Security: do not use the `root` user.
ENV USER=node

# You can not use `${USER}` here, but reference `/home/node`.
ENV PATH="/home/node/app/.npm-global/bin:${PATH}"
#ENV PATH="/home/node/cache/bin:${PATH}"
ENV NPM_CONFIG_PREFIX="/home/node/app"

WORKDIR /home/node/app

# Set the ownership and permissions before copying package*.json
RUN chown -R node:node /home/node/app
RUN chmod -R 777 /home/node/app

RUN mkdir -p "${NPM_CONFIG_PREFIX}"
RUN npm config set prefix "${NPM_CONFIG_PREFIX}"

USER ${USER}

COPY --chown=node:node /package*.json ./
#COPY /entrypoint.sh /home/node/app/entrypoint.sh
#RUN chmod +x ./entrypoint.sh

RUN npm install

#RUN mkdir -p /home/node/app
#RUN chown -R node:node /home/node/app
#RUN chmod -R 777 /home/node/app

#WORKDIR /home/node/app
EXPOSE 5137
#ENTRYPOINT ["bash","/home/node/app/entrypoint.sh"]
CMD ["sh", "-c", "npm run dev -- --host 0.0.0.0"]
#CMD ["sh", "-c", "npm run build"]

according to my idea, the data in the node container (the node_modules folder and the package.json and package-lock.json files) should be synchronized with the project on the host via volume:

GWSL_vcxsrv_s4BrIZIzz7

server {
    listen 80;
# server_name localhost;
    root /app/public;
    index index.php index.html;
    error_log /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    location ~ \.php$ {
       try_files $uri =404;
       fastcgi_split_path_info ^(.+\.php)(/.+)$;
       fastcgi_pass app:9000;
       fastcgi_index index.php;
       include fastcgi_params;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       fastcgi_param REQUEST_METHOD $request_method;
       fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}
  1. created the application image: docker compose build

  2. installed dependencies for laravel: composer install - including package inertiajs/inertia-laravel

  3. php artisan key:generate

  4. php artisan migrate

  5. installed npm dependencies in vue container:

GWSL_vcxsrv_xTBhemHmex

  1. configured vite.config.js file:
import vue from '@vitejs/plugin-vue';
import laravel from 'laravel-vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
    server: {
        host: '0.0.0.0',
        // host: true
        // host: '127.0.0.1',
        port: 5173
        hmr: {
            host: 'localhost',
            //host: 'localhost',
            protocol: 'ws'
        },
        watch: {
            usePolling: true
        },
        plugins: [
            laravel({
                input: [ 'resources/css/app.css', 'resources/js/app.js' ],
                refresh: true
            }),
            vue({
                template: {
                    transformAssetUrls: {
                        base: null
                        includeAbsolute: false
                    },
                }
            }),
        ],
    }}
)
  1. renamed the /resources/views/welcome.blade.php file to app.blade.php and added vite and inertia.js directives:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <metacharset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Lara-vue3!</title>
    @vite('resources/js/app.js')
    @inertiaHead
</head>
<body>
    @inertia
    <div>
        <p>
            hello!!!
        </p>
    </div>
</body>
</html>
  1. Register \App\Http\Middleware\HandleInertiaRequests::class in the web middleware group in /app/Http/Kernel.php -

GWSL_vcxsrv_8QOV97wEem

  1. in resources/js/app.js specified settings for inertia.js:
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
createInertiaApp({

    resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
        return pages[`./Pages/${name}.vue`]
    },
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .mount(el)
    },
})
  1. created two simple vue.js components in resources/js/Pages:

GWSL_vcxsrv_vNtKIIc8Ny

  1. created an Http/Controllers/IndexController.php controller that handles / and /hello routes using inertia.js

GWSL_vcxsrv_za014FX172

  1. and nothing works:

when launching containers and in a browser at localhost:8000, where, in theory, the application should open, the following error is displayed:

iATvQtTy4y

with node container running:

GWSL_vcxsrv_iCuxHElxdh

but if you go to this address - http://localhost:5173, you will get an error:

chrome_ctkNVmApLf

if you run the npm run build command in the node container (where node.js and all npm dependencies are installed), you will get this error:

Could not resolve entry module "index.html".
error during build:
RollupError: Could not resolve entry module "index.html".
    at error (file:///home/node/app/node_modules/rollup/dist/es/shared/node-entry.js:2245:30)
    at ModuleLoader.loadEntryModule (file:///home/node/app/node_modules/rollup/dist/es/shared/node-entry.js:24695:20)
    at async Promise.all(index 0)

GWSL_vcxsrv_ixj8OgfHUK

with all dependencies installed in the container

GWSL_vcxsrv_xTBhemHmex

all dependencies are also present on the host machine:

GWSL_vcxsrv_2iIS1Xrn1Q

question: where is the error and how to configure the application (docker? vite.config.js config? laravel?) so that everything works? i.e.

my goal is to work with laravel + vue.js using inertia.js

my repository: https://github.com/haosmos/lara-vue-inertia

my work environment:

WSL2: 1.3.14.0 NODE.JS: 18 LARAVEL: 10.16 VUE.JS: 3.3.4 VITE: 4.4.7

inertiajs/inertia-laravel: 0.6.9, laravel-vite-plugin: 0.7.5, @vitejs/plugin-vue: 4.2.3, vue: 3.3.4, @inertiajs/vue3: 1.0.9

haosmos commented 1 year ago

in the Laravel community in discord, a person under the nickname @Mono2000 helped me, for which I express my deep gratitude to him!

the problem was that in the vite.config.js file, I placed the block with plugins in the code block with server settings - like this:

GWSL_vcxsrv_XTeB8GmWyL

but it was necessary to move this code block to the same level as the server settings code block - that is, it was necessary to do this:

GWSL_vcxsrv_EspAbNkxSc

thank you so much @Mono2000!