Skip to content

Usage tips 💡

If you want to install the bundle without the community recipe, check the manual installation.

CSS file entrypoints

This section talks about FOUC (Flash of Unstyled Content) in development mode only. This phenomenon should not occur in production builds.

By default, if you import your css files from a js entry point, the vite dev server creates only one entrypoint (<script src="http://localhost:5173/build/assets/app.js" type="module"></script>) for your js and css files. Your css content will be loaded after. This results in a small period of time where the content of the page will not be styled.

You can however provide a css/scss/... file as an entrypoint and it will be directly inserted as a link tag <link rel="stylesheet" href="http://localhost:5173/build/assets/theme.scss">. This way, your browser will wait for the loading of your theme.scss file before rendering the page.

js
export default defineConfig({
    // ...your config
    build: {
        rollupOptions: {
            input: {
                theme: "./assets/theme.scss"
            },
        }
    },
});

TIP

Make sure to still add the two Twig functions vite_entry_link_tags / vite_entry_script_tags even if the entry point is a css file because in development mode Vite will need to insert its js code to activate the HMR.

twig
{% block stylesheets %}
    {{ vite_entry_link_tags('theme') }}
{% endblock %}

{% block javascripts %}
    {{ vite_entry_script_tags('theme') }}
{% endblock %}

will render

html
<script src="http://localhost:5173/build/@vite/client" type="module">
<link rel="stylesheet" href="http://localhost:5173/build/assets/theme.scss">

during development.

Docker

If you are using Docker for your Symfony development and running your node commands in a container, you will need to make some configuration adjustments.

Let's take the example with an image node:21-alpine.

bash
docker run
  --rm \
  -ti \
  --user $(id -u):$(id -g) \
  -v $(pwd):/app \
  -p 5173:5173 \
  -w /app \
  node:21-alpine \
  npm run dev
js
// vite.config.js
export default defineConfig({
    server: {
        // Required to listen on all interfaces
        host: '0.0.0.0'
    },
    plugins: [
        symfonyPlugin({
            // as we set `server.host` to 0.0.0.0
            // we must explicitly set the server host name
            viteDevServerHostname: 'localhost'
        }),
    ],
    build: {
        rollupOptions: {
            input: {
                app: "./assets/app.js"
            },
        }
    },
});

An example configuration with Docker can be found in the Symfony Vite Dev sandboxes.

You can learn more by following this Github discussion.

Dependency Pre-Bundling 🏃

In a standard Vite project, index.html is the entry point to the application. When you run dev serve, Vite will crawl your source code and automatically discover dependency imports.

Because we don't have an index.html in Symfony projects, Vite can't do this pre-bundling step when it starts. This means when you browse a page where it finds a package it does not already have cached, Vite will re-run the dep bundling process and reload the page.

This behavior can be annoying if you have a lot of dependencies because it creates a lot of page reloads before getting to the final render.

You can limit this by declaring your project's most common dependencies in vite.config.js:

js
// vite.config.js

export default defineConfig({
    server: {
        // Set to true to force dependency pre-bundling.
        force: true,
    },
    // ...
    optimizeDeps: {
        include: ["my-package"],
    },
});

Configure splitting files per entry point 📦

Vite tries to split your js files into multiple smaller files shared between entry points. To configure the exact splitting one can define a manualChunks function in rollupOptions, refer to rollup docs on manual chunks for more details.

js
// vite.config.js

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: (id: string, {getModuleInfo, getModuleIds}) => {
          // your code
        },
      },
    },
  },
});

https / http in Development 🔒

Your Vite dev server can cause unwanted reload (and mixed content warnings) if used in http and your Symfony application uses https (probably due to invalid certificates). Configuration is easier if you develop your application without https.

bash
npm run dev
symfony serve --no-tls

browse : http://127.0.0.1:8000

If you still want to use https, you can use one of the two options below.

Use symfony cli certificate

First, enable symfony-cli TLS if you haven't done it yet.

js
// vite.config.js
import fs from "fs";
import { join } from 'node:path';
import { homedir } from 'node:os';

export default defineConfig({
    // ...
    server: {
        https: {
            pfx: join(homedir(), '.symfony5/certs/default.p12'),
        },
        cors: true
    },
});

TIP

If you get TLS related errors when launching the dev server, this might be caused by an old symfony-cli version/node <17 version combination. To fix this, you can either:

  • prepend NODE_OPTIONS=--openssl-legacy-provider to your dev npm script
  • delete your current certificate and restart your server (full details here)

Generate custom certificates

With mkcert

bash
mkcert -install
mkcert -key-file certs/vite.key.pem -cert-file certs/vite.crt.pem localhost 127.0.0.1
js
// vite.config.js
import fs from "fs";

export default defineConfig({

    // ...
    server: {
        https: {
          key: fs.readFileSync('certs/vite.key.pem'),
          cert: fs.readFileSync('certs/vite.crt.pem'),
        },
        cors: true
    },
});
bash
npm run dev
symfony serve

browse : https://127.0.0.1:8000

Released under the MIT License.