Components · v1.x

Asset

The Asset component compiles the files of assets/ into public/builds/ with hashed file names and a manifest.json. Templates get the compiled URL with the asset() view helper; CSS references are rewritten and CSS / JavaScript can be minified.

Build layout

Assets are stored in assets/ and compiled into public/builds/, with the same structure. A hash of the content is added to every file name: {filename}-{hash}.{extension}.

assets/css/app.css        ->  public/builds/css/app-3f2a9c1b.css
assets/img/logo.png       ->  public/builds/img/logo-d07ec8c2.png
assets/js/app.js          ->  public/builds/js/app-8801909f.js

public/builds/manifest.json maps each asset to its compiled URL:

{
    "css/app.css": "/builds/css/app-3f2a9c1b.css",
    "img/logo.png": "/builds/img/logo-d07ec8c2.png"
}

In templates

asset($path) returns the compiled URL:

<link rel="stylesheet" href="{{ asset('css/app.css') }}">
<img src="{{ asset('img/logo.png') }}" alt="">
<link rel="stylesheet" href="<?= $this->e($this->asset('css/app.css')) ?>">

Absolute URLs given to asset() (https://..., //...) are returned unchanged.

Compilation modes

Mode Behavior of asset()
debug (auto_compile: true) compiles the asset again when its content changed, updates the manifest and removes the previous build
production (auto_compile: false) reads the manifest; an asset missing from the manifest is compiled once

Command

php bin/neo asset:reload
php bin/neo asset:reload --minify

asset:reload empties public/builds/, compiles every file of assets/ and rebuilds the manifest. Run it on every deployment.

Option Description
--minify, -m minifies CSS (comments and whitespace) and JavaScript (comments and indentation, line breaks are kept)

CSS rewriting

In CSS files, url(...) and @import pointing to another file of assets/ are rewritten to the compiled URL: url('../img/logo.png') becomes url('/builds/img/logo-d07ec8c2.png'). External URLs, absolute paths and files outside assets/ are kept as is.

Configuration

config/framework/asset.yaml (key framework.asset):

source_path: '%kernel.root_path%/assets'
build_path: '%kernel.public_path%/builds'
public_url: /builds
auto_compile: '%kernel.debug%'

hash:
  algorithm: xxh128
  length: 8
Option Default Description
source_path %kernel.root_path%/assets directory of the assets
build_path %kernel.public_path%/builds directory of the compiled files and of manifest.json
public_url /builds URL prefix of the compiled files (a CDN URL can be used)
auto_compile %kernel.debug% compiles the changed assets on each request
hash.algorithm xxh128 hash function (any hash_algos() value)
hash.length 8 number of characters kept (minimum 4)

PHP API

Inject NeoPHP\Component\Asset\Contract\AssetInterface (implemented by AssetManager).

Method Description
url(string $path): string compiled URL of an asset (what asset() returns)
compile(string $path): string compiles one asset and returns its URL
reload(bool $minify = false): array clears the builds, compiles every asset, saves the manifest; returns [path => url]
clear(): void empties the build directory and the manifest
addCompiler(CompilerInterface $compiler): static registers a compiler
setSourceFile(string $path, ?string $file): static compiles $file in place of assets/$path; null removes the override
getSourceFile(string $path): string file actually compiled for $path
getSourcePath(): string / getBuildPath(): string configured directories
getManifest(): Manifest the manifest
<?php

declare(strict_types=1);

namespace App\Service;

use NeoPHP\Component\Asset\Contract\AssetInterface;

class LogoUrl
{
    public function __construct(protected AssetInterface $asset)
    {
    }

    public function get(): string
    {
        return $this->asset->url('img/logo.png');
    }
}

setSourceFile('css/app.css', $file) is used by the Tailwind package (see the Tailwind documentation); the original source is used again when $file does not exist.

Manifest (NeoPHP\Component\Asset\Manifest\Manifest) provides getFile(), all(), get($path), set($path, $url), remove($path), clear() and save().

AssetManager can be built directly with new AssetManager($sourcePath, $buildPath, $publicUrl, $autoCompile, $hashAlgorithm, $hashLength, $compilers) or AssetManager::fromConfig(array $config, array $defaults = []).

Custom compilers

A compiler implements NeoPHP\Component\Asset\Compiler\CompilerInterface. $resolve returns the compiled URL of another asset path. The built-in compilers are CssCompiler (css) and JsCompiler (js, mjs); other files are copied as is.

<?php

declare(strict_types=1);

namespace App\Asset;

use NeoPHP\Component\Asset\Compiler\CompilerInterface;

class SvgCompiler implements CompilerInterface
{
    public function supports(string $extension): bool
    {
        return $extension === 'svg';
    }

    public function compile(string $content, string $path, callable $resolve, bool $minify = false): string
    {
        return $minify ? (string) preg_replace('/>\s+</', '><', $content) : $content;
    }
}
$asset->addCompiler(new SvgCompiler());

Exceptions

NeoPHP\Component\Asset\Exception\AssetException is thrown for an unsupported hash algorithm, a missing asset or an unsafe build path.

Changelog

  • v1.18.0 — AssetInterface::setSourceFile() (and getSourceFile()) to compile another file in place of an asset.
  • v1.3.0 — Asset component: assets/ compiled into public/builds/ with hashed names, manifest.json, asset() helper, asset:reload [--minify] command.