pentatrion/vite-bundle

Integration with your Symfony app & Vite

Installs: 1 643

Dependents: 0

Suggesters: 0

Security: 0

Stars: 10

Watchers: 1

Forks: 0

Open Issues: 0

Type:symfony-bundle

v0.1.5 2021-08-21 05:42 UTC

This package is auto-updated.

Last update: 2021-09-11 06:48:31 UTC


README

Symfony logo Vite logo

ViteBundle : Symfony integration with Vite

This bundle helping you render all of the dynamic script and link tags needed. Essentially, he provides two twig functions to load the correct scripts into your templates.

Installation

Install the bundle with

composer require pentatrion/vite-bundle

if you don't have a package.json file already you can execute the pentatrion/vite-bundle community recipe. Otherwise see manual installation at the end.

npm install

# start your vite dev server
npm run dev

Add this twig functions in any template or base layout where you need to include a JavaScript entry.

{% block stylesheets %}
    {# specify here your entry point relative to the assets directory #}
    {{ vite_entry_link_tags('app.js') }}
{% endblock %}

{% block javascripts %}
    {{ vite_entry_script_tags('app.js') }}
{% endblock %}

note : In your twig functions, you have to specify your entrypoint relative to your assets directory. Be careful to put the .js extension for both functions.

if you are using React, you have to add this option in order to have FastRefresh.

{{ vite_entry_script_tags('app.js', { dependency: 'react' }) }}

Configuration

If you choose a custom configuration of your vite.config.js file, you probably need to create a config/packages/pentatrion_vite.yaml file.

default configuration

# config/packages/pentatrion_vite.yaml
pentatrion_vite:
    # Base public path when served in development or production
    base: /build/

    # Server options
    server:
        host: localhost
        port: 3000
        https: false

Explication

{% block stylesheets %}
    {# specify here your entry point relative to the assets directory #}
    {{ vite_entry_link_tags('app.js') }}
{% endblock %}

{% block javascripts %}
    {{ vite_entry_script_tags('app.js') }}
{% endblock %}

would render in dev:

<!--Nothing with vite_entry_link_tags('app.js') -->

<!-- vite_entry_script_tags('app.js') -->
<script src="http://localhost:3000/build/@vite/client" type="module"></script>
<script src="http://localhost:3000/build/app.js" type="module"></script>

would render in prod:

<!-- vite_entry_link_tags('app.js') -->
<link rel="stylesheet" href="/build/app.[hash].css" />
<link rel="modulepreload" href="/build/vendor.[hash].js" />

<!-- vite_entry_script_tags('app.js') -->
<script src="/build/app.[hash].js" type="module"></script>

Manual installation

composer require pentatrion/vite-bundle

if you do not want to use the recipe or want to see in depth what is modified by it, create a directory structure for your js/css files:

├──assets
│ ├──app.js
│ ├──app.css
│...
├──public
├──composer.json
├──package.json
├──vite.config.js

create or complete your package.json

{
    "scripts": {
        "dev": "vite",
        "build": "vite build"
    },
    "devDependencies": {
        "vite": "^2.1.5"
    }
}

create a vite.config.js file on your project root directory. the symfonyPlugin and the manifest: true are required for the bundle to work. when you run the npm run dev the plugin remove the manifest.json file so ViteBundle know that he must return the served files. when you run the npm run build the manifest.json is constructed and ViteBundle read his content to return the build files.

// vite.config.js
import { resolve } from "path";
import { unlinkSync, existsSync } from "fs";

/* if you're using React */
// import reactRefresh from "@vitejs/plugin-react-refresh";

const symfonyPlugin = {
    name: "symfony",
    configResolved(config) {
        if (config.env.DEV && config.build.manifest) {
            let buildDir = resolve(
                config.root,
                config.build.outDir,
                "manifest.json"
            );
            existsSync(buildDir) && unlinkSync(buildDir);
        }
    },
    configureServer(devServer) {
        let { watcher, ws } = devServer;
        watcher.add(resolve("templates/**/*.twig"));
        watcher.on("change", function (path) {
            if (path.endsWith(".twig")) {
                ws.send({
                    type: "full-reload",
                });
            }
        });
    },
};

export default {
    plugins: [
        /* reactRefresh(), // if you're using React */
        symfonyPlugin,
    ],
    server: {
        watch: {
            disableGlobbing: false,
        },
    },
    root: "./assets",
    base: "/build/",
    build: {
        manifest: true,
        emptyOutDir: true,
        assetsDir: "",
        outDir: "../public/build/",
        rollupOptions: {
            input: ["./assets/app.js"],
        },
    },
};