Plumbing craft-vite for a 'public' webfolder?
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/**'],
}
}
}));
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.
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/**'],
}
}
}));
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.
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"