BoxLang 🚀 A New JVM Dynamic Language Learn More...
Mixr is a static-asset helper for ColdBox applications.
Instead of hard-coding the hashed CSS and JavaScript filenames created by your build process, reference the original asset entry:
#mixr().tags( "resources/js/app.js" )#
Mixr looks up that entry in your bundler's manifest and renders the correct HTML for the current environment.
In production, that may include a stylesheet, module-preload hints, and a hashed JavaScript bundle:
<link rel="stylesheet" href="/includes/build/assets/app-a1b2c3d4.css" />
<link rel="modulepreload" href="/includes/build/assets/vendor-e5f6g7h8.js" />
<script type="module" src="/includes/build/assets/app-a1b2c3d4.js"></script>
In development, Mixr can detect Vite's hot file and render the Vite development-server URLs instead.
Mixr supports:
The mixr() helper is available in handlers, layouts,
views, and interceptors.
box install mixr
Mixr ships with a few drivers for different bundling strategies. Use this table to pick the right one.
| Your project uses... | Driver | Start here |
|---|---|---|
Vite, a .vite/manifest.json, or a Vite dev server | "vite"
| Vite Driver |
Webpack, Laravel Mix, Elixir, mix-manifest.json,
rev-manifest.json, or a flat asset map | "manifest"
| Manifest Driver |
| A build system you are unsure about | "auto"
| Driver selection |
| An existing Mixr 2.x application | "manifest" or "auto"
| Upgrade guide |
A manifest is a JSON file your build process creates. It maps an original source file like
resources/js/app.jsto the fingerprinted production file your bundler generated, likeassets/app-a1b2c3d4.js. Mixr reads that file so your ColdBox code can keep using stable, human-readable asset names.
Vite is the recommended choice for new projects. It supports fast development builds, hot-module replacement, modern JavaScript modules, content-hashed production assets, imported CSS, and shared chunk preloading.
Add a basic Vite configuration to config/Coldbox.cfc:
moduleSettings = {
mixr : {
driver : "vite",
devMode : getSystemSetting( "ENVIRONMENT", "production" ) eq "development"
}
};
By default, Mixr expects Vite to use these locations. Only set custom paths when your Vite setup writes files somewhere different.
| Purpose | Default |
|---|---|
| Production manifest | /includes/build/.vite/manifest.json
|
| Vite hot file | /includes/hot
|
| Public build URL | /includes/build
|
moduleSettings = {
mixr : {
driver : "vite",
manifestPath : "/includes/build/.vite/manifest.json",
buildPath : "/includes/build",
hotFilePath : "/includes/hot",
devMode : getSystemSetting( "ENVIRONMENT", "production" ) eq "development"
}
};
Place viteClient() and tags() inside <head>:
<!doctype html>
<html lang="en">
<head>
#mixr().viteClient()#
#mixr().tags( "resources/js/app.js" )#
</head>
<body>
#renderView()#
</body>
</html>
The entry passed to tags() must match a key in Vite's
manifest, which is normally the original source entry
(resources/js/app.js), not the compiled filename (assets/app-a1b2c3d4.js).
Your global entry might import shared CSS and JavaScript:
import "../scss/app.scss";
import "./bootstrap";
import "./navigation";
Every page rendered through that layout receives the same base assets.
Mixr does not require your application to be a single page app. It resolves and renders whichever entries you ask for, which suits traditional multi-page apps too.
If you bundle JS and CSS separately, load both entries:
<head>
#mixr().viteClient()#
#mixr().tags( "resources/js/app.js" )# <!-- JavaScript -->
#mixr().tags( "resources/scss/app.scss" )# <!-- CSS -->
</head>
When devMode is enabled and Vite's hot file is active,
Mixr renders Vite development-server URLs:
<script type="module" src="http://localhost:5173/@vite/client"></script>
<script type="module" src="http://localhost:5173/resources/js/app.js"></script>
Vite then handles hot-module replacement, JavaScript updates, CSS injection, and fast local rebuilds.
When Vite hot mode is not active, Mixr reads Vite's production
manifest. For a JavaScript entry it can render imported stylesheet
links, module-preload links for shared chunks, and the entry
<script type="module">. For that
reason, tags() is the recommended helper for Vite
JavaScript entries.
Important for Vite users:
path()returns only the compiled entry URL. It does not include imported CSS, shared chunks, module-preload hints, or critical CSS. Usetags()for most Vite entries.
You do not need a separate entry per ColdBox event. Start with one global entry, then add page-specific entries only when a route has substantial JavaScript or CSS that should not load everywhere.
resources/
├── js/
│ ├── app.js
│ └── pages/
│ ├── dashboard.js
│ └── checkout.js
└── scss/
└── app.scss
The main layout loads shared assets, and a dashboard layout or view loads an additional entry:
#mixr().tags( "resources/js/pages/dashboard.js" )#
Mixr does not register Vite inputs for you. Your Vite configuration must still define any files you want Vite to treat as build entries.
Use the manifest driver for build systems that create a simple
source-to-output mapping, such as Webpack, Laravel Mix, ColdBox
Elixir, or a custom mix-manifest.json / rev-manifest.json.
Unlike Vite manifests, a flat manifest typically maps one requested asset to one output URL:
{
"/css/app.css": "/css/app-123456.css",
"/js/app.js": "/js/app-abcdef.js"
}
moduleSettings = {
mixr : {
driver : "manifest",
manifestPath : "/includes/mix-manifest.json",
prependModuleRoot : true,
prependPath : "/includes"
}
};
The Mixr 2.x string form remains a clean choice for flat manifests:
<link rel="stylesheet" href="#mixr( '/css/app.css' )#" />
<script src="#mixr( '/js/app.js' )#"></script>
The fluent API works too:
<link rel="stylesheet" href="#mixr().path( '/css/app.css' )#" />
<script src="#mixr().path( '/js/app.js' )#"></script>
Both resolve the hashed asset URL while leaving the HTML markup under your control. A flat manifest usually does not describe imported CSS or shared-chunk relationships, so you normally load CSS and JavaScript entries explicitly, adding page-specific bundles only where needed.
Mixr supports a fluent API for modern usage and a legacy string form for 2.x compatibility.
| Situation | Recommended helper |
|---|---|
| Vite JavaScript entry | mixr().tags(
"resources/js/app.js" )
|
| Vite CSS-only entry | mixr().tags(
"resources/scss/app.scss" )
|
| Flat manifest application | mixr(
"/js/app.js" ) or mixr().path(
"/js/app.js" )
|
| CSS and JavaScript need different placement | cssTags() and jsTags()
|
| Complete control over markup | bundle() and criticalCss()
|
| Upgrading a 2.x app | Keep the string form until you need Vite-specific behavior |
mixr() helper<!--- Fluent API, current module auto-detected. --->
#mixr().tags( "resources/js/app.js" )#
#mixr().path( "resources/js/app.js" )#
#mixr().viteClient()#
<!--- Fluent API, explicit module. --->
#mixr( moduleName = "admin" ).tags( "resources/js/admin.js" )#
<!--- Legacy 2.x string form. Returns a URL. --->
#mixr( "/js/app.js" )#
#mixr( "/js/admin.js", "admin" )#
When you omit moduleName, Mixr determines the current
module automatically, so layouts, handlers, views, and interceptors
inside a module use the correct configuration without naming the
module each time.
| Method | Returns | Description |
|---|---|---|
path( entry )
| string
| Resolved URL for one entry. Best for flat manifests or fully manual markup. |
tags( entry )
| string
| Complete asset markup. With Vite, can include CSS links, module-preload links, and a module script. |
cssTags( entry )
| string
| The CSS portion of tags(). Useful when CSS
must appear in <head>. |
jsTags( entry )
| string
| The JavaScript portion of tags(). Useful
when JS must render elsewhere. |
bundle( entry )
| struct
| Resolved assets so you can render HTML yourself. |
criticalCss( eventName )
| string
| Inline critical CSS for an event when enabled and available. |
viteClient()
| string
| Vite's @vite/client script in development.
Empty in production. Deduped per request. |
isHot()
| boolean
| true when Vite hot mode is active for the
current configuration. |
refresh()
| void
| Clears Mixr's cached data for the current module. Useful in tests. |
tags(), cssTags(), and jsTags()
accept an options struct. Use the attributes key to add
HTML attributes to the tag Mixr renders.
#mixr().tags(
"resources/js/app.js",
{ attributes : { nonce : request.cspNonce, "data-app" : "public" } }
)#
<script type="module" src="..." nonce="..." data-app="public"></script>
Attributes decorate the tag the entry actually renders.
<link>, a
JavaScript entry renders one <script>, and the
attributes apply to that one tag.<script type="module">. Imported
stylesheet links and module-preload links do not receive them automatically.<link>; development renders a Vite
module script. tags() handles both modes, so prefer it
for CSS-only entries unless you specifically need to split rendering.For example, a stylesheet entry with attributes:
#mixr().tags( "resources/scss/app.scss", { attributes : { media : "screen", "data-theme" : "dark" } } )#
<!-- production --> <link rel="stylesheet" href="..." media="screen" data-theme="dark" />
<!-- development --> <script type="module" src=".../app.scss" media="screen" data-theme="dark"></script>
Use cssTags() and jsTags() when CSS and
JavaScript need different attributes or placement. For a Vite
JavaScript entry, cssTags() applies its attributes to
every stylesheet link it emits, while jsTags() applies
its attributes to the entry module script and renders module-preload
links when enabled.
#mixr().cssTags( "resources/js/app.js", { attributes : { media : "screen" } } )#
#mixr().jsTags( "resources/js/app.js", { attributes : { nonce : request.cspNonce } } )#
CSS-only entry note: In Vite development mode
cssTags()returns an empty string because Vite injects those styles through JavaScript. When splitting a CSS-only entry, include bothcssTags()andjsTags().
The attributes struct is open-ended. Mixr renders any
valid attribute key you provide, so new HTML attributes work without a
Mixr update.
{
async : true } renders a bare async;
false (or omitting the key) renders nothing. Note
{ defer : 1 } renders
defer="1" because 1 is a number,
not a boolean.integrity value if you pass one, but it does not
compute the hash. Your build pipeline must generate it, which
matters with Vite because content-hashed filenames change each build.Vite note: Module scripts are deferred by default, so adding
deferto a Vite module script is usually unnecessary.
Common attributes you might pass: nonce,
async, defer, crossorigin,
integrity, fetchpriority,
referrerpolicy, media, and any
data-* or aria-* attribute.
You only need to configure settings you are changing. The quick-start examples cover the most common setups; this section is a reference for custom build locations, multiple modules, special cache behavior, or critical CSS.
Some settings identify files Mixr reads. Others become public URLs that browsers request.
| Setting type | Examples | Purpose |
|---|---|---|
| File-oriented paths | manifestPath,
hotFilePath, criticalCss.path
| Where Mixr finds files or directories it reads. |
| Browser-facing URL prefixes | buildPath, prependPath
| Become part of the URL rendered in
<link> and <script> tags. |
| Driver | Use it when... |
|---|---|
"vite"
| Your project uses Vite, Vite's hot file, or a Vite manifest. |
"manifest"
| Your project uses a simple source-to-output manifest (Laravel Mix, Elixir, Webpack, or a custom map). |
"auto"
| You want Mixr to detect the right driver. |
In "auto" mode, Mixr selects Vite when it
finds an active Vite hot file, or a Vite-shaped manifest (its first
entry is a struct with a file key). Otherwise it falls
back to the flat-manifest driver.
| Setting | Default | Description |
|---|---|---|
driver
| "auto"
| "vite",
"manifest", or "auto". |
manifestPath
| "/includes/build/.vite/manifest.json"
| Location of the bundler's manifest JSON file. |
buildPath
| "/includes/build"
| Public URL prefix for Vite-built assets. |
hotFilePath
| "/includes/hot"
| Location of Vite's hot file. Its presence enables
dev-server rendering when devMode is on. |
devServerUrl
| ""
| Fallback dev-server URL when the hot file is empty. |
devMode
| false
| Enables Vite hot-file checking. Set true in development. |
renderModulePreload
| true
| Renders <link
rel="modulepreload"> for imported JavaScript chunks. |
includeImportedCss
| true
| Walks imported Vite chunks and includes their CSS files. |
prependModuleRoot
| true
| Prefixes generated URLs with the current module's mount path. Applies to both drivers. |
prependPath
| "/includes"
| Flat-manifest-only public URL prefix prepended to resolved paths. |
cache.enabled
| true
| Caches parsed manifests in memory. |
cache.devCheckInterval
| 2000
| How often Mixr rechecks Vite's hot file in dev, in milliseconds. |
criticalCss.enabled
| false
| Enables critical CSS rendering. |
criticalCss.path
| "/includes/critical"
| Directory containing per-route critical CSS files. |
criticalCss.suffix
| ".critical.css"
| Suffix appended to the event name when locating a critical CSS file. |
modules
| {}
| Per-module overrides keyed by module name. |
The cache and criticalCss structs merge
key-by-key. Overriding just cache: { devCheckInterval: 5000
} does not disable caching; the default cache.enabled =
true still applies.
cache.devCheckInterval controls how Mixr rechecks Vite's
hot file in development:
| Value | Behavior |
|---|---|
| Positive number | Rechecks at that interval, in milliseconds. |
0
| Rechecks on every request. |
-1
| Never rechecks after initial resolution. Treats dev behavior like production. |
The sections below are advanced and optional. Most applications are fully set up after the Configuration reference. Read on only when you need multi-module asset pipelines, critical CSS, split CSS/JS placement, or hand-rolled markup.
Mixr can use different asset settings for different ColdBox modules, which is valuable for reusable or distributed modules that ship with their own JavaScript and CSS. A module can own its frontend assets without the host application merging manifests, duplicating build configuration, or managing module-specific URLs.
In most cases, call Mixr normally from within the module:
#mixr().tags( "resources/js/app.js" )#
Mixr detects the current module and uses that module's configuration when one exists. You do not usually need to pass the module name from a module's own layouts, handlers, views, or interceptors.
A host (root) application can provide module-specific overrides
through moduleSettings.mixr.modules:
moduleSettings = {
mixr : {
driver : "vite",
manifestPath : "/includes/build/.vite/manifest.json",
buildPath : "/includes/build",
devMode : getSystemSetting( "ENVIRONMENT", "production" ) eq "development",
modules : {
admin : {
driver : "vite",
manifestPath : "/admin/includes/build/.vite/manifest.json",
buildPath : "/admin/includes/build",
hotFilePath : "/admin/includes/hot"
},
reports : {
driver : "manifest",
manifestPath : "/reports/includes/mix-manifest.json",
prependPath : "/reports/includes"
}
}
}
};
With that configuration, the same #mixr().tags(
"resources/js/app.js" )# call resolves differently
depending on whether the request belongs to the host, the
admin module, or the reports module.
A module can also provide its own Mixr configuration in ModuleConfig.cfc:
component {
function configure() {
variables.settings.mixr = {
driver : "vite",
manifestPath : "/includes/build/.vite/manifest.json",
buildPath : "/includes/build",
devMode : getSystemSetting( "ENVIRONMENT", "production" ) eq "development"
};
}
}
This lets a reusable module describe its own build process without the host knowing every internal asset detail.
Root application settings do not automatically cascade into every module. This host configuration:
moduleSettings = { mixr : { driver : "vite", devMode : true } };
does not force every module to inherit driver:
"vite" and devMode: true. A module
should either define its own variables.settings.mixr, or
receive an explicit override through
moduleSettings.mixr.modules.<moduleName>. This
avoids surprises when modules use different manifests, build paths,
dev servers, or bundlers. For most apps: keep host settings focused on
host assets, let reusable modules define their own settings, and use
mixr.modules.<name> only when the host needs to
adapt a module's paths.
When you intentionally need an asset from another module (for
example, a host layout including admin assets), pass moduleName:
<head>
#mixr().tags( "resources/js/app.js" )#
#mixr( moduleName = "admin" ).tags( "resources/js/admin.js" )#
</head>
By default, Mixr makes generated asset URLs aware of the module's
mount path. A module mounted at /admin with
buildPath : "/includes/build" generates a URL like:
/admin/includes/build/assets/app-a1b2c3d4.js
This lets a module work even when the host mounts it at a different
path than expected. Set prependModuleRoot : false when a
module's assets should always resolve from a shared, application-level
location. Vite development-server URLs are absolute, so they are never
prefixed with a mount path.
Critical CSS is an optional performance optimization: inline the CSS needed for the above-the-fold part of the page, load the rest of the stylesheet asynchronously, and keep a standard stylesheet fallback for users with JavaScript disabled.
It can improve first-render performance on CSS-heavy pages, but adds
build, maintenance, and Content Security Policy considerations. Enable
it after measuring a real need. Mixr handles the rendering side; your
build process generates the per-route files, with tools like rollup-plugin-critical
, laravel-mix-critical
, or a custom process.
/includes/critical), named after the current
event: main.index.critical.css, blog.show.critical.css.path and suffix:moduleSettings = {
mixr : {
criticalCss : {
enabled : true,
path : "/includes/critical",
suffix : ".critical.css"
}
}
};
A suffix of "_critical.min.css"
would look for main.index_critical.min.css instead. Keep
calling tags() normally; Mixr checks for a critical file
matching the current event.
tags() emitsWithout critical CSS (default):
<link rel="stylesheet" href="/includes/build/assets/app-a1b2c3d4.css" />
<link rel="modulepreload" href="/includes/build/assets/vendor-e5f6g7h8.js" />
<script type="module" src="/includes/build/assets/app-a1b2c3d4.js"></script>
With critical CSS enabled and a matching file for the current event:
<style>/* Inlined critical CSS */</style>
<link rel="preload" as="style" href="/includes/build/assets/app-a1b2c3d4.css"
onload="this.onload=null;this.rel='stylesheet'" fetchpriority="high" />
<noscript><link rel="stylesheet" href="/includes/build/assets/app-a1b2c3d4.css" /></noscript>
<link rel="modulepreload" href="/includes/build/assets/vendor-e5f6g7h8.js" />
<script type="module" src="/includes/build/assets/app-a1b2c3d4.js"></script>
If no matching file exists, Mixr silently falls back to normal stylesheet output. No conditional code is needed in your views.
Pass critical CSS options through tags():
#mixr().tags( "resources/js/app.js", { criticalEvent : "blog.show", nonce : request.cspNonce } )#
| Option | Default | Description |
|---|---|---|
criticalEvent
| Current event | Overrides the event name used to locate a critical CSS file. |
skipCritical
| false
| Forces standard stylesheet output for this call. |
nonce
| ""
| Adds a CSP nonce to the inline <style>
and preload <link>. |
Mixr skips critical CSS whenever Vite hot mode is active, because Vite injects CSS through JavaScript and inlining a stale production file would fight it. To preview critical CSS locally, run a production build and load the app without Vite's hot file active.
The preload-swap pattern uses an inline onload handler:
onload="this.onload=null;this.rel='stylesheet'"
A strict CSP may block inline event handlers. Adding a nonce to the
inline <style> does not authorize the
onload handler. Applications with strict CSP may need a
different stylesheet-loading strategy, a CSP exception that permits
the handler, or custom rendering with bundle(). Review
your CSP before enabling critical CSS in production.
For Vite, the default recommendation is to keep the complete output
in <head>. Vite module scripts are deferred by
default, so this lets the browser discover stylesheets and
module-preload hints early. Use split rendering only when your layout
requires it, for example when CSS must render in
<head> while JavaScript renders elsewhere, when CSS
and JS need different attributes, or when you need direct control over markup.
cssTags() and jsTags()
<!doctype html>
<html lang="en">
<head>
#mixr().viteClient()#
#mixr().cssTags( "resources/js/app.js" )#
</head>
<body>
#renderView()#
#mixr().jsTags( "resources/js/app.js" )#
</body>
</html>
For the same entry, cssTags() and jsTags()
together render the same asset set as tags().
cssTags() renders stylesheet <link>
tags, or inline critical CSS plus preload-swap markup and a
<noscript> fallback when critical CSS is enabled.jsTags() renders module-preload links plus the entry
module script (or the dev-server script in development).Use either tags() or cssTags() plus
jsTags() for the same entry in a request, not both.
Critical-CSS dedupe is handled for you: the first
cssTags() (or tags()) call per request emits
the inline <style>, and later calls suppress it
while still preload-swapping the CSS link.
When Vite hot mode is active, cssTags() returns an empty
string and jsTags() renders the dev-server script (Vite
injects CSS through JavaScript). With jsTags() near the
end of <body>, a brief flash of unstyled content
may occur in development. That is usually acceptable locally, and is
another reason tags() in <head>
remains the preferred Vite pattern.
With a flat manifest, CSS and JavaScript are normally separate keys.
Use the split with separate keys, or keep calling tags() twice:
#mixr().cssTags( "/css/app.css" )#
#mixr().jsTags( "/js/app.js" )#
Use bundle() when you need complete control over
generated HTML, for example custom integrity attributes, specialized
CSP markup, custom preload hints, or non-standard script placement.
<cfset bundle = mixr().bundle( "resources/js/app.js" )>
<cfset critical = mixr().criticalCss( options = { markRendered : true } )>
<!doctype html>
<html lang="en">
<head>
<cfif len( critical )>
<style>#critical#</style>
</cfif>
<cfloop array="#bundle.css#" item="href">
<link rel="stylesheet" href="#href#" />
</cfloop>
</head>
<body>
#renderView()#
<cfloop array="#bundle.preload#" item="href">
<link rel="modulepreload" href="#href#" />
</cfloop>
<cfif len( bundle.js )>
<script type="module" src="#bundle.js#"></script>
</cfif>
</body>
</html>
bundle() returns a struct:
| Key | Description |
|---|---|
js
| The resolved JavaScript entry URL (empty for CSS-only entries). |
css
| An array of stylesheet URLs. |
preload
| An array of imported JavaScript chunk URLs. |
criticalCss
| The resolved critical CSS body, when applicable. |
bundle() is a pure read. It does not
mark inline critical CSS as rendered for the request, so combining a
manual bundle() render with a later tags()
call could produce duplicate inline critical CSS. When rendering
critical CSS manually, mark it rendered so a later tags()
call suppresses its own inline block:
<cfset critical = mixr().criticalCss( options = { markRendered : true } )>
The first positional argument to criticalCss() is the
event name, and options (including markRendered) are
passed in the options struct. The flag is only set when the returned
string is non-empty. To target a specific event:
mixr().criticalCss( "main.index", { markRendered :
true } ).
For Vite output, keep JavaScript as a module script (<script
type="module"
src="#bundle.js#"></script>). Vite output
can contain ES module imports that require
type="module", so do not convert it to a
classic script unless you know the generated file is not an ES module.
When Vite hot mode is active, bundle.css,
bundle.preload, and bundle.criticalCss are
empty, and bundle.js holds the dev-server URL. Loops over
the empty arrays safely do nothing. Branch on
mixr().isHot() when you need substantially different
development markup.
Most existing Mixr 2.x templates keep working. The legacy string form is unchanged:
#mixr( "/js/app.js" )#
The default driver is now "auto", which still
falls back to the flat-manifest driver when it does not find an active
Vite configuration.
Mixr 3.0 changes the default manifest path:
| Version | Default manifestPath
|
|---|---|
| 2.x | /includes/mix-manifest.json
|
| 3.0 | /includes/build/.vite/manifest.json
|
If your 2.x project relied on the old default and never set
manifestPath, set it explicitly:
mixr = {
driver : "manifest", // or "auto"
manifestPath : "/includes/mix-manifest.json"
};
If you miss this step, the ManifestNotFound error spells
out the exact fix, so you can recover without this guide.
driver = "vite" | "manifest" |
"auto" (default "auto").buildPath, hotFilePath,
devServerUrl, devMode,
renderModulePreload, includeImportedCss, cache.devCheckInterval.path(), tags(), cssTags(),
jsTags(), bundle(),
criticalCss(), viteClient(),
isHot(), refresh().<noscript> fallback.ModuleConfig.cfc or
mixr.modules.<name> from the host. Settings do
not cascade.path() with ViteThe legacy string form and path() stay clean and
practical for flat manifests. For Vite, remember they return only the
compiled entry file (see What
happens in production?) and use tags() instead.
ManifestNotFound
Mixr cannot find the configured manifest file. Confirm your
production build has run, that manifestPath points to the
correct file, that the application can read it, and that your bundler
outputs the manifest where Mixr expects it (Vite:
/includes/build/.vite/manifest.json; Laravel Mix: /includes/mix-manifest.json).
The asset path you passed does not match a manifest key. Open the
manifest and copy the key exactly. If the manifest contains
"resources/js/app.js": { "file":
"assets/app-a1b2c3d4.js" }, call mixr().tags(
"resources/js/app.js" ), not the compiled path.
Mixr cannot find or use Vite's hot file. Confirm devMode
is enabled, that hotFilePath matches the file Vite
writes, that Vite is running, and that the hot file contains a
reachable dev-server URL. Confirm Docker, WSL, VM, HTTPS, or
reverse-proxy networking lets the browser reach that URL. Set
devServerUrl when the hot file is empty or unsuitable for
the environment.
You used path() and rendered only the JavaScript entry
URL. Use tags(), or split with cssTags() and jsTags().
The module mount path, buildPath, or module-root prefix
behavior does not match your deployment. Confirm the module's mount
path and that buildPath points to the correct public
location. Review prependModuleRoot, and set it to
false when assets should not inherit the module mount path.
Critical CSS is disabled, no matching file exists, or Vite hot mode
is active. Confirm criticalCss.enabled is
true, that criticalCss.path is correct, that
the filename matches the current ColdBox event, that the suffix
matches your build output, and that Vite's hot file is not active
while testing production behavior.
Your CSP blocks inline styles or inline event handlers. Confirm the
nonce on your inline style is correct, check whether inline event
handlers are blocked, and review the Content Security Policy
note. Consider bundle() when your CSP requires a
different stylesheet-loading strategy.
Mixr is developed by Angry Sam Productions. Issues, pull requests, bug reports, and ideas are welcome.
All notable changes to this project will be documented in this file.
<link rel="modulepreload"> emission, and @vite/client injection (deduped per request).driver: "vite" | "manifest" | "auto". The auto driver (default) picks Vite when it sees a hot file or a Vite-shaped manifest, otherwise falls back to the flat-manifest driver.mixr().path(), mixr().tags(), mixr().bundle(), mixr().viteClient(), mixr().isHot(), mixr().refresh(). Pass moduleName to scope to a different submodule: mixr( moduleName = "admin" ).tags( "…" ).buildPath, hotFilePath, devServerUrl, devMode, renderModulePreload, includeImportedCss, cache.enabled, cache.devCheckInterval.moduleSettings.mixr.* for the root app, or variables.settings.mixr.* from a submodule's own ModuleConfig.cfc) → host overrides under moduleSettings.mixr.modules.<name>.* (the only mechanism by which one module's config affects another). A host's devMode no longer leaks into installed submodules.cache.devCheckInterval.mixr( asset ) and mixr( asset, moduleName ) string forms are unchanged, and the auto driver still resolves to the flat-manifest driver when no Vite manifest/hot file is present. One upgrade action: the default manifestPath moved from /includes/mix-manifest.json (2.x) to the Vite path /includes/build/.vite/manifest.json. Apps that relied on the 2.x default must now set manifestPath explicitly (point it at your existing manifest); apps that already set manifestPath, or that use the Vite default, need no changes. If you miss it, the ManifestNotFound error names this exact fix.Mixr.cfc no longer extends coldbox.system.FrameworkSupertype; submodule settings are looked up via the coldbox:moduleSettings: <name> WireBox DSL.
$
box install mixr