lhapaipai / vite-bundle

Integration with your Symfony app & Vite

Home Page:https://symfony-vite.pentatrion.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The configuration in 'pentatrion_vite.yaml' doesn't work with Docker

fred-lab opened this issue · comments

Hello

Thanks for your bundle.

I tried to use it with Docker, but I have some issue. To work with docker, I have to define a host in 'vite.config.js' :

export default defineConfig({
    plugins: [react(), symfonyPlugin()],
    build: {
        rollupOptions: {
            input: {
                app: "./assets/App.tsx",
            },
        },
    },
    server: {
        port: 3000,
        host: '0.0.0.0',
    },
});

But if I do that, the generated entrypoint.json don't work anymore, because the host will be now '0.0.0.0' instead of 'localhost

{
  "isProd": false,
  "viteServer": {
    "origin": "http://0.0.0.0:3000",
    "base": "/build/"
  },
  "entryPoints": {
    "app": {
      "js": [
        "http://0.0.0.0:3000/build/assets/App.tsx"
      ]
    }
  },
  "assets": null
}

I tried to add this in config/packages/pentatrion_vite.yaml

pentatrion_vite:
    server:
        host: localhost
        port: 3000
        https: false

But it didn't work

The only solution I found is to add 'origin: 'http://localhost:3000' in Vite config

export default defineConfig({
    plugins: [react(), symfonyPlugin()],
    build: {
        rollupOptions: {
            input: {
                app: "./assets/App.tsx",
            },
        },
    },
    server: {
        origin: 'http://localhost:3000',
        port: 3000,
        host: '0.0.0.0',
    },
});

And I removed the pentatrion_vite.yaml (this file didn't work)

Now, the entrypoints.json is OK, and everything is working fine with Docker.

I spend a lot of time to figure why this bundle didn't work with Docker, so if this issue can help someone else who struggle to use this bundle with docker.

Thanks for your feedback @fred-lab , my next edit will come to remove duplicate configuration entries between
config/packages/pentatrion_vite.yaml and vite.config.js. I will look in detail the implementation with docker.

please change the issue title to reflect this is a Docker issue only, thank you.

Hi @fred-lab ,
I made an update (disable strictPort) and I realized that it was incompatible with what you proposed, so I added an option to vite-plugin-symfony.
can you confirm that everything works with this configuration?

vite-plugin-symfony: 0.6.2
pentatrion/vite-bundle: v2.2.1

export default defineConfig({
    plugins: [
        reactRefresh(),
        symfonyPlugin({
            viteDevServerHostname: 'localhost'
        }),
    ],
    server: {
        port: 3000,
        host: '0.0.0.0',
        strictPort: true
    },
    build: {
        rollupOptions: {
            input: {
                app: "./assets/App.tsx",
            },
        },
    },
});

Hello

I tried the new update and I can't make it worked with Docker.

I updated vite-plugin-symfony & pentatrion/vite-bundle.
I used this configuration

import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react'
import symfonyPlugin from 'vite-plugin-symfony'

export default defineConfig({
    plugins: [
        reactRefresh(),
        symfonyPlugin({
            viteDevServerHostname: 'localhost',
        }),
    ],
    build: {
        rollupOptions: {
            input: {
                app: './assets/App.tsx',
            },
        },
    },
    server: {
        port: 3000,
        host: '0.0.0.0',
        strictPort: true,
    },
})

I run the server

  VITE v3.1.4  ready in 1451 ms

  ➜  Local:   http://localhost:3000/build/
  ➜  Network: http://172.23.0.7:3000/build/

I get this entrypoint.json

{
  "isProd": false,
  "viteServer": {
    "origin": "http://0.0.0.0:3000",
    "base": "/build/"
  },
  "entryPoints": {
    "app": {
      "js": [
        "http://0.0.0.0:3000/build/assets/App.tsx"
      ]
    }
  },
  "assets": null
}

It doesn't work

GET http://0.0.0.0:3000/build/@vite/client net::ERR_ADDRESS_INVALID
GET http://0.0.0.0:3000/build/assets/App.tsx net::ERR_ADDRESS_INVALID
GET http://0.0.0.0:3000/build/@react-refresh net::ERR_ADDRESS_INVALID

In the entrypoint.json, it work if the serveur is 'localhost' instead of '0.0.0.0'.
It didn't work either if I don't specify a host in the vite.config.ts

The entrypoint.json does not seem to be generated correctly with the value of viteDevServerHostname if I specify a host in the server option in vite.config.ts

Have you download the v0.6.2 of vite-plugin-symfony ? this is precisely what version 0.6.2 corrects
can you return your npx envinfo --npmPackages ?

Yes, I updated the package

  npmPackages:
    @types/react: ^18.0.17 => 18.0.21
    @types/react-dom: ^18.0.6 => 18.0.6
    @typescript-eslint/eslint-plugin: ^5.39.0 => 5.39.0
    @typescript-eslint/parser: ^5.39.0 => 5.39.0
    @vitejs/plugin-react: ^2.1.0 => 2.1.0
    eslint: ^8.24.0 => 8.24.0
    eslint-config-prettier: ^8.5.0 => 8.5.0
    eslint-plugin-react: ^7.31.8 => 7.31.8
    react: ^18.2.0 => 18.2.0
    react-dom: ^18.2.0 => 18.2.0
    sass: ^1.55.0 => 1.55.0
    typescript: ^4.8.4 => 4.8.4
    vite: ^3.0 => 3.1.4
    vite-plugin-symfony: ^0.6.2 => 0.6.2

Do you think maybe it's because I use TS ?

Sorry @fred-lab , I made a mistake in the order of checks this should be fixed with v0.6.3 ...

No problem :)
Thanks for your help

hi @fred-lab ,
I think you master docker much better than me, do you have a way to explain your config for docker in the readme of https://github.com/lhapaipai/vite-plugin-symfony ?

hi @fred-lab , I think you master docker much better than me, do you have a way to explain your config for docker in the readme of https://github.com/lhapaipai/vite-plugin-symfony ?

Sorry, i didn't saw your message early.
I'm french so my english is pretty bad, but my docker's configuration for symfony is pretty straitghforward and suits my needs. I use Nginx + PHP + Mariadb and Nodejs.
This is what i use : https://github.com/fred-lab/Docker_Symfony
It's not up to date with PHP 8 or with Vite and your bundle, but this is the basis of my configuration.

I'm not sure if it's what you need because it's pretty "heavy", but I don't think you can use only the vite-plugin-symfony, you need the whole "stack" to run a Symfony project.

merci @fred-lab , je vais regarder, c'est toujours intéressant de regarder d'autres configurations ne serait-ce que pour s'en inspirer, merci et bon week-end.

ps: un petit peu de français ne fait pas de mal 😄

merci @fred-lab , je vais regarder, c'est toujours intéressant de regarder d'autres configurations ne serait-ce que pour s'en inspirer, merci et bon week-end.

ps: un petit peu de français ne fait pas de mal smile

Oui, un petit peu de français ne fait pas de mal. J'ai toujours l'impression que je serais mal compris en anglais.

L'avantage d'une stack Docker, c'est que tu peux utiliser la même sur ton environnement de dev ou de prod, je n'aime pas les solutions comme WAMP, toujours des soucis quand on déploit...
Par contre, la difficulté avec Docker, c'est qu'il faut tout paramétrer soit-même. Il y a des outils comme Laradock mais je trouve ça trop "gros" pour mon usage (beaucoup de chose dedans que je n'utiliserai pas)

Pour ton projet, je pense qu'il vaut mieux déterminer un exemple de stack Docker pour 'Vite-bundle' et pas 'vite-plugin-symfony'. Mais ça implique d'avoir des containers NGINX, PHP et NODEJS (pour la base de donnée, au pire, il y a SQLITE)

Pour Nginx, j'avais repris la conf du serveur proposé sur le site de Symfony et c'est à peu près tout, je ne suis pas un expert de NGINX (donc certainement des choses à améliorer) Il faut seulement penser à utiliser le nom du service php dans la conf :

fastcgi_pass engine:9000;

Grossomodo, Docker donne un alias à chaque container qui permet de l'utiliser dans un autre container du même network, ça évite de mettre en dur l'ip du container directement, car celle-ci peut changer. C'est un point important, et par exemple pour paramétrer l'url de la base de donnée dans le .env, il faut utiliser le nom du service de la base de donnée.

J'aime bien utiliser des container Alpine par soucis de taille, les containers seront plus léger (et ça prend vite de la place) Par contre, il peut souvent y avoir des soucis avec les repo Alpine. Il faut mieux être précis et strict dans les versions d'image à utiliser.
Il faut faire aussi attention aux permissions d'écriture et de lecture. Lorsque l'on monte un volume, les droits peuvent différer entre le container et l'host, et ça peut poser des soucis. J'ai pris l'habitude de toujours changer les droits de l'utilisateur du container pour correspondre à celui de mon host.
Docker fonctionne par un système de layer, et chaque commande 'RUN' ajoute un layer et augmente la taille du container, donc si possible, j'essaye de tout mettre dans une seule commande 'RUN', comme pour mon image PHP. Ca réduit la taille, mais c'est plus chiant à débuger et quand ça plante, tu repars de 0 (Docker met en cache chaque layer)
Il faut faire aussi attention (surtout pour l'image NODE) d'avoir toujours un process actif dans le container, sinon le container s'arrête. Ca ne pose pas de soucis pour PHP, mais pour Node, c'est ennuyeux, car Node s'arrête une fois qu'il a exécuter son script et donc le container s'arrête aussi.
C'est d'autant plus chiant si tu mets l'option "restart : unless-stopped" dans le docker compose, car ça peut faire comme une boucle infini. Par exemple, tu définis la commande à exécuter "npm run build dans ton service Node, node build les dépendances puis s'arrête, donc le container s'arrête, Docker relance le container, node rebuild les dépendances, puis s'arrête, le container s'arrête, mais docker le relance... Par contre si tu met une commande du type 'npm run dev', le process reste actif (car il y a le serveur Vite qui fonctionne) et donc le container reste actif aussi.

Si tu veux, je peux essayer de faire une config simple et rapide à utiliser avec Vite-bundle (nginx + php + node). Ca peut toujours servir de base.

salut @fred-lab, désolé pour mon silence depuis ton dernier message. Je n'ai vraiment vu le temps passer... je ne sais pas trop où tu en est niveau développement mais je viens de mettre en ligne une documentation un peu plus complète pour le développement sous Symfony et Vite et je pense que ça pourrait être intéressant d'ajouter une section pour une mise en place sous Docker. Qu'en penses-tu ?

salut @fred-lab, désolé pour mon silence depuis ton dernier message. Je n'ai vraiment vu le temps passer... je ne sais pas trop où tu en est niveau développement mais je viens de mettre en ligne une documentation un peu plus complète pour le développement sous Symfony et Vite et je pense que ça pourrait être intéressant d'ajouter une section pour une mise en place sous Docker. Qu'en penses-tu ?

Salut, oui, ce serait intéressant.
Pour ma part, je continue à utiliser cette stack, par contre, il m'arrive d'avoir des erreurs CORS sur Firefox (c'est un peu aléatoire d'un pc à un autre) et pour l'instant, je n'ai pas trouvé de solution.
Pour une mise en place sur Docker, je vois pas mal de gens qui partent de cette stack : https://github.com/dunglas/symfony-docker mais il manque la partie nodejs pour faire fonctionner ViteJS

image

Still don't understand what the point is of "originOverride", when I can just provide it with server.origin on Line 85 with a config Vite already provides. Been using server.origin for half a year now without issue in the company I work for. Is there a need for this override? @lhapaipai (sorry I don't speak french very well, so I don't know if you explained it in your french messages)

Hi @D3strukt0r,
One use case can be to have nodejs in a container.
You could run vite server with this docker command:

docker run 
  --rm \
  -ti \
  --user $(id -u):$(id -g) \
  -v $(pwd):/app \
  -p 5173:5173 \
  -w /app \
  node:21-alpine \
  npm run dev
// BAD configuration
export default defineConfig({
    plugins: [
        symfonyPlugin(),
    ],
    build: {
        rollupOptions: {
            input: {
                app: "./assets/app.js"
            },
        }
    },
});

with default options.
vite-plugin-symfony is ok (entrypoints.jsonviteServer.origin = http://localhost:5173
but vite is not binded to the correct interface : we don't have HMR.

  ➜  Local:   http://localhost:5173/build/
  ➜  Network: use --host to expose

we need to add this option:

// BAD configuration
export default defineConfig({
    plugins: [
        symfonyPlugin(),
    ],
    build: {
        rollupOptions: {
            input: {
                app: "./assets/app.js"
            },
        }
    },
    server: {
        host: '0.0.0.0'
    }
});

so vite binding are correct

  ➜  Local:   http://localhost:5173/build/
  ➜  Network: http://172.17.0.2:5173/build/

vite dev server is ok.
172.17.0.2 is the IP address of the vite dev server in the Docker bridge network.
but vite-plugin-symfony is not ok (entrypoints.jsonviteServer.origin = http://0.0.0.0:5173.

finally with viteDevServerHostname or originOverride we can combine
ultimately I'm still going to keep this viteDevServerHostname option that I stupidly depreciated

// GOOD configuration
export default defineConfig({
    plugins: [
        symfonyPlugin({
            viteDevServerHostname: 'localhost'
        }),
    ],
    build: {
        rollupOptions: {
            input: {
                app: "./assets/app.js"
            },
        }
    },
    server: {
        host: '0.0.0.0'
    }
});

vite binding are correct

  ➜  Local:   http://localhost:5173/build/
  ➜  Network: http://172.17.0.2:5173/build/

and vite-plugin-symfony is ok (entrypoints.jsonviteServer.origin = http://localhost:5173.

Discussions are open because I may have missed something.
What do you think about that @fred-lab ?

personally I don't use node in a docker container in development, I prefer using Volta which allows you to choose your version of node and pin it to your package.json

It's all a matter of taste ?

@lhapaipai maybe some additional context to how we use it in the company. we have the symfony app and the vite runtime in the same Docker container, but additionally they are behind a VM (also for subnet functionality (e.g. https://myapp.test instead of localhost)).

note the use of server.host and server.origin and your plugin without options. the env variable APP_URL could be e.g. github.com or anything we need for the project
vite.config.js (stripped down to the essential parts to hide some project and company info)

import fs from 'fs';
import * as dotenv from 'dotenv';
import {defineConfig} from 'vite';
import {chunkSplitPlugin} from 'vite-plugin-chunk-split';
import react from '@vitejs/plugin-react';
import symfonyPlugin from 'vite-plugin-symfony';
import browserslistToEsbuild from 'browserslist-to-esbuild';
import viteRestart from 'vite-plugin-restart';
import i18nHotReload from './assets/vite-plugins/i18n-hot-reload';
import svgr from 'vite-plugin-svgr';
import {blurHash} from 'vite-plugin-blurhash';

dotenv.config();

export default defineConfig(({command}) => ({
  plugins: [
    chunkSplitPlugin({
      customChunk: ({file}) => {
        // Extract each node_modules package into a separate chunk in "js/npm/(user-)package".
        const match = file.match(/node_modules\/(?:@([^\/]+?)[\/])?([^\/]+)/);
        if (match) {
          const name = match[1] ? `${match[1]}-${match[2]}` : match[2];
          return `npm/${name}`;
        }
        if (file === 'assets/utils/init-monaco.js') {
          return 'monaco/init';
        }
        return null;
      },
    }),
    svgr(),
    react(),
    symfonyPlugin(),
    viteRestart({
      reload: ['templates/*.twig'],
    }),
    i18nHotReload(),
  ],
  base: '/build/',
  build: {
    target: browserslistToEsbuild(),
    outDir: './public/build',
    rollupOptions: {
      input: {
        'app': './assets/app.jsx',
      },
      output: {
        assetFileNames: (assetInfo) => {
          // Place asset in each corresponding folder "build/{img,font,etc.}/*".
          const info = assetInfo.name.split('.');
          let extType = info[info.length - 1];
          if (/png|jpe?g|svg|gif|tiff|bmp|ico|avif|webp/i.test(extType)) {
            extType = 'img';
          } else if (/woff2?|otf|ttf|eot/.test(extType)) {
            extType = 'font';
          }
          return `${extType}/[name].[hash][extname]`;
        },
        chunkFileNames: 'js/[name].[hash].js',
        entryFileNames: 'js/[name].[hash].js',
      },
    },
    manifest: true,
  },
  server: {
    host: '0.0.0.0',
    strictPort: true,
    https: {
      // Get certificates if we are not building (CI has no certificates)
      key: command === 'build' ? null : fs.readFileSync('docker/run/certificates/key.pem'),
      cert: command === 'build' ? null : fs.readFileSync('docker/run/certificates/cert.pem'),
    },
    watch: {
      ignored: ['**/.idea/**', '**/tests/**', '**/var/**', '**/vendor/**'],
    },
    origin: `https://${process.env.APP_URL}:5173`,
  },
  // Needed for antd
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
      },
    },
  },
}));

and the compose.yml (stripped down to the essential parts to hide some project and company info)

services:
  ##### TIER 1 #####
  nginx:
    image: nginx
    volumes:
      - ./certificates:/data/conf/nginx/certificates
      - ../../public:/app/web
      - ../../vendor:/app/vendor
    ports:
      - '80:80'
      - '443:443'
    links:
      - fpm
    networks:
      - appnetwork

  fpm:
    image: php
    volumes:
      - ../../:/app
      - ./certificates:/etc/ssl/certs/local
    ports:
      - '5173:5173'
    links:
      - db
      - mailcatcher
    networks:
      - appnetwork