craft-vite icon indicating copy to clipboard operation
craft-vite copied to clipboard

Plumbing craft-vite for a 'public' webfolder?

Open MattAppleton opened this issue 11 months ago • 4 comments

Question

I am new to Vite, and have been following this great video introduction on craftquest . The course setup is working fine, its lovely to work with but now I want to try setting up Vite on a production job. I use Serverpilot which uses a 'public' root folder.

Im having trouble pursuing the logic and Vite setup to work in my 'public' setup at build time — any help would be very much appreciated!

Thus far I run into issues setting my Vite outDir to 'public/dist/' — 'dev' scripts work fine

But a 'build' script gives me a twig file with this kind of bizarre script in the head, with NO css, and no workable js.


<script type="module">!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver((e=>{for(const o of e)if("childList"===o.type)for(const e of o.addedNodes)if("LINK"===e.tagName&&"modulepreload"===e.rel)r(e);else if(e.querySelectorAll)for(const o of e.querySelectorAll("link[rel=modulepreload]"))r(o)})).observe(document,{childList:!0,subtree:!0})}function r(e){if(e.ep)return;e.ep=!0;const r=function(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerpolicy&&(r.referrerPolicy=e.referrerpolicy),"use-credentials"===e.crossorigin?r.credentials="include":"anonymous"===e.crossorigin?r.credentials="omit":r.credentials="same-origin",r}(e);fetch(e.href,r)}}();</script>

Additional context

heres my vite.config.ts

import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
import ViteRestart from 'vite-plugin-restart';
import viteCompression from 'vite-plugin-compression';

export default defineConfig(({command}) => ({
    base: command === 'serve' ? '/' : '/dist/',
    plugins: [
        tailwindcss(),
        ViteRestart(
            {
                restart: ['./templates/**/*']
            }
       ),
        viteCompression({
            filter: /\.(mjs|json|css|map)$/i,
        })
       
    ],
    build: {
        manifest: true,
        rollupOptions: {
            input: {
                app: 'src/js/app.js',
            }
        },
        outDir: 'public/dist/', // Output directory for built files
        emptyOutDir: true, // Ensure it cleans the folder before build
    },
    publicDir: false, // Prevents Vite from treating "public" as the root
    server: {
        port: 5173,
        host: '0.0.0.0',
        strictPort: true,
        cors: {
            origin: /https?:\/\/([A-Za-z0-9\-\.]+)?(localhost|\.local|\.test|\.site)(?::\d+)?$/
        },
        origin: "https://danielsilver-vite.ddev.site:5173",
        watch: {
            ignored: ['./storage/**', './vendor/**', './web/**', './public/**'],
        }
    }
}));

MattAppleton avatar Mar 19 '25 23:03 MattAppleton

Following up with a bit more info...

.vite/manifest.json contains all of the right links to files that are generated in public/dist/assets

I can pull up these assets if I either go directly to the url for the css file for instance or if I hardcode the link and script tags, for example this works in index.twig

<link rel="stylesheet" href="/dist/assets/app-B1PbtZdy.css">
<script type="module" src="/dist/assets/app-BkNm22E_.js"></script>

or this link works fine

https://danielsilver-vite.ddev.site/dist/assets/app-B1PbtZdy.css

the bit that breaks is the script embed function from the craft-vite plugin (I think!?)

currently I have this set

 {{ craft.vite.script("src/js/app.js", false) }}

my setup is effectively a mirror of my (working setup made from) Craft-Vite-Tailwind course by @khalwat and @ryanirelan on Craftquest, the ONLY thing I have tried to change at the minute is the public folder.

MattAppleton avatar Mar 20 '25 10:03 MattAppleton

Update: I have tried adding a 'root' value to vite.config.ts as per this stackoverflow question

My dev scripts still work well, but the buld script — despite makign the correct files in the correct folder structure — still results in a malformed script tag in my index template, and no css link is injected.

Heres my current vite.config.ts

import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
import ViteRestart from 'vite-plugin-restart';
import viteCompression from 'vite-plugin-compression';

export default defineConfig(({command}) => ({
    base: command === 'serve' ? '/' : '/dist/',
    plugins: [
        tailwindcss(),
        ViteRestart(
            {
                restart: ['./templates/**/*']
            }
       ),
        viteCompression({
            filter: /\.(mjs|json|css|map)$/i,
        })
       
    ],
    root: 'public', // what is the relatinship with 'base: command'?
    build: {
        manifest: true,
        rollupOptions: {
            input: {
                app: 'src/js/app.js',
            }
        },
        outDir: 'dist', // Output directory for built files
        emptyOutDir: true, // Ensure it cleans the folder before build
    },
    publicDir: 'assets', // Prevents Vite from treating "public" as the root
    server: {
        port: 5173,
        host: '0.0.0.0',
        strictPort: true,
        cors: {
            origin: /https?:\/\/([A-Za-z0-9\-\.]+)?(localhost|\.local|\.test|\.site)(?::\d+)?$/
        },
        origin: "https://danielsilver-vite.ddev.site:5173",
        watch: {
            ignored: ['./storage/**', './vendor/**', './web/**', './public/**'],
        }
    }
}));

MattAppleton avatar Mar 24 '25 11:03 MattAppleton

So I don't think this will have much to do with the Craft Vite plugin; it's more of a Vite setup issue.

But I'll attempt to assist you when I am able.

khalwat avatar Mar 25 '25 20:03 khalwat

Thanks so much for taking a look. So possibly a setting in Vite.php?

The task I'm trying to complete is simply take your CraftQuest course repo (the Vite one made with @ryanirelan), and get it to work from 'public' rather than 'web'. If theres a way to replumb and fork that it would be super-useful, no doubt for other Course users too :)

I'd be most grateful if you do have a moment to spare — its actually possible to work just using the dev script, and hand-code the build links when pushing to remote, but clearly a bit clunky / inelegant that way, plus it wouldn't fit our usual GitHub action build pipeline.

Heres my current Vite.php

<?php
/**
 * Vite plugin for Craft CMS
 *
 * Allows the use of the Vite.js next generation frontend tooling with Craft CMS
 *
 * @link      https://nystudio107.com
 * @copyright Copyright (c) 2021 nystudio107
 */

use craft\helpers\App;

/**
 * Vite config.php
 *
 * This file exists only as a template for the Vite settings.
 * It does nothing on its own.
 *
 * Don't edit this file, instead copy it to 'craft/config' as 'vite.php'
 * and make your changes there to override default settings.
 *
 * Once copied to 'craft/config', this file will be multi-environment aware as
 * well, so you can have different settings groups for each environment, just as
 * you do for 'general.php'
 */

return [

    /**
     * @var bool Should the dev server be used?
     */
    'useDevServer' => App::env('ENVIRONMENT') === 'dev' || App::env('CRAFT_ENVIRONMENT') === 'dev',
    // 'useDevServer' => false,

    /**
     * @var string File system path (or URL) to the Vite-built manifest.json
     */
    'manifestPath' => '@webroot/dist/.vite/manifest.json',

    /**
     * @var string The public URL to the dev server (what appears in `<script src="">` tags
     */
    'devServerPublic' => App::env('PRIMARY_SITE_URL') . ':5173',

    /**
     * @var string The public URL to use when not using the dev server
     */
    'serverPublic' => App::env('PRIMARY_SITE_URL') . '/dist/',

    /**
     * @var string|array The JavaScript entry from the manifest.json to inject on Twig error pages
     *              This can be a string or an array of strings
     */
    'errorEntry' => '',

    /**
     * @var string String to be appended to the cache key
     */
    'cacheKeySuffix' => '',

    /**
     * @var string The internal URL to the dev server, when accessed from the environment in which PHP is executing
     *              This can be the same as `$devServerPublic`, but may be different in containerized or VM setups.
     *              ONLY used if $checkDevServer = true
     */
    'devServerInternal' => 'http://localhost:5173',

    /**
     * @var bool Should we check for the presence of the dev server by pinging $devServerInternal to make sure it's running?
     */
    'checkDevServer' => true,

    /**
     * @var bool Whether the react-refresh-shim should be included
     */
    'includeReactRefreshShim' => false,

    /**
     * @var bool Whether the modulepreload-polyfill shim should be included
     */
    'includeModulePreloadShim' => true,

    /**
     * @var string File system path (or URL) to where the Critical CSS files are stored
     */
//    'criticalPath' => '@webroot/dist/criticalcss',

    /**
     * @var string the suffix added to the name of the currently rendering template for the critical css file name
     */
//    'criticalSuffix' => '_critical.min.css',
    /**
     * @var bool Whether an onload handler should be added to <script> tags to fire a custom event when the script has loaded
     */
    'includeScriptOnloadHandler' => true,
];

and the two relevant .env settings

CRAFT_WEB_ROOT="/var/www/html/public"
PRIMARY_SITE_URL="https://danielsilver-vite.ddev.site"

MattAppleton avatar Mar 26 '25 09:03 MattAppleton