Skip to content

Frontend Resources

Capell uses one typed resource graph for application Vite entries, package-published files, trusted CDN resources, inline trusted code, loading strategies, hints, dependency ordering, diagnostics, and optimization. Use this graph for CSS and JavaScript; render hooks are for public markup.

Frontend resources flow from typed declarations through planning and activation to safe public output.

Register npm requirements with FrontendPackageDependencyRegistry:

$registry->register(new FrontendPackageDependencyData(
name: 'swiper',
versionConstraint: '^12.0',
type: FrontendPackageDependencyType::Runtime,
package: 'acme/gallery',
));

Contribute the application entry with new ViteResourceSourceData('resources/js/gallery.js'). Run php artisan capell:frontend-after-install to print the deterministic dependency, Vite-input, publication, and build plan. Non-interactive execution mutates only with --apply.

Applications must include the generated entries:

import { capellViteInputs } from './vendor/capell-app/frontend/resources/js/capell-vite-inputs.js'
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
...capellViteInputs(),
],
})

Doctor reports missing integration when generated entries exist.

Published package resources and conditional widgets

Section titled “Published package resources and conditional widgets”

Published files remain outside Vite. Register a typed group for LayoutBuilder selection:

$resources->register(new FrontendResourceGroupData(
key: 'acme.gallery',
label: 'Gallery',
package: 'acme/gallery',
resources: [
FrontendResourceData::style(
handle: 'acme/gallery:style',
package: 'acme/gallery',
source: new PublicResourceSourceData('/vendor/acme-gallery/gallery.css'),
loadingStrategy: PresentationLoadingStrategy::Visible,
),
FrontendResourceData::classicScript(
handle: 'acme/gallery:runtime',
package: 'acme/gallery',
source: new PublicResourceSourceData('/vendor/acme-gallery/gallery.js'),
loadingStrategy: PresentationLoadingStrategy::Visible,
),
],
));

LayoutBuilder is the selection-to-activation bridge. Visible, idle, and interaction targets remain independent; shared canonical resources load on the first valid trigger and are deduplicated.

The simple CDN case is concise:

FrontendResourceData::classicScript(
handle: 'acme/maps:leaflet',
package: 'acme/maps',
source: new ExternalResourceSourceData('https://cdn.example.com/[email protected]'),
);

Add security metadata when available:

new ExternalResourceSourceData(
httpsUrl: 'https://cdn.example.com/[email protected]',
integrity: 'sha384-BASE64_DIGEST',
crossOrigin: CrossOrigin::Anonymous,
referrerPolicy: ReferrerPolicy::NoReferrer,
);

External URLs must be absolute HTTPS without credentials or fragments; query strings are preserved. capell-frontend.external_resources.integrity_policy is warn by default and require rejects missing SRI.

Declare dependent libraries by stable handle:

$plugin = FrontendResourceData::classicScript(
handle: 'acme/charts:labels',
package: 'acme/charts',
source: new ExternalResourceSourceData('https://cdn.example.com/[email protected]'),
dependsOn: ['acme/charts:library'],
);

Async scripts cannot declare or satisfy ordered dependencies.

Trusted PHP may use inlineStyle() and inlineScript(); the renderer applies Laravel Vite’s nonce. Use typed FrontendResourceHintData for preload, module-preload, preconnect, and DNS-prefetch. Capell does not automatically preconnect to external origins.

Plans report required script-src, style-src, connect-src, and font-src origins but do not change CSP headers. The application owns CSP authorization and nonce propagation.

Editor-controlled theme data may select trusted registered groups or local public paths. It cannot introduce remote URLs or inline executable code.

Doctor and page-resource diagnostics report source validity, missing dependencies, cycles, aliases, package ownership, activation reasons, placement, SRI, CSP origins, local raw/gzip sizes, and remote resources as unmeasurable. Public requests never fetch third-party assets for measurement.

Tests should prove presence and absence, dependency order, placement, canonical deduplication, lazy activation, and that anonymous HTML/events contain only URLs, attributes, and opaque resource tokens—not Composer packages, internal handles, model IDs, selectors, field paths, permissions, or signed URLs.

Critical-CSS-eligible stylesheets are rendered with Capell’s stable recovery runtime. If the intended full stylesheet fails, the runtime loads the configured stable fallback, marks the document as data-frontend-styles="fallback", and retries the intended URL with bounded cache-busting delays. A successful retry activates the full stylesheet, removes the fallback, marks the document as loaded, and dispatches capell:stylesheet-recovered. When more than one eligible stylesheet is present, the fallback remains active until every failed stylesheet has recovered.

The package default fallback is /vendor/capell-frontend/capell-frontend.css. It keeps a failed page readable, but an application with a branded frontend bundle should configure capell-frontend.stylesheet_recovery.fallback_url to a stable, atomically published full bundle. The runtime is always published at /vendor/capell-frontend/stylesheet-recovery.js; keep package assets in the normal laravel-assets publication step.

Recovery is the last safety net, not the release strategy. Content-hashed assets referenced by cacheable HTML must remain available for at least the complete HTML cache and stale-serving window. See Server Configuration.

Mix, loose css()/js() builders, FrontendAssetRequirementData, FrontendAssetManifestData, FrontendAssetContributor, FrontendAssetManifestRenderer, VendorAssetData::buildAsset(), and VendorAssetData::npmDependency() were removed. Use typed source/factory declarations, FrontendResourceContributor, FrontendResourcePlanRenderer, and FrontendPackageDependencyRegistry.