Introducing Nette Assets for static file management with Vite integration

David Grudl
Nette Core | 8269
+
+4
-

Hi,

I was annoyed by the fragmented approach to assets across various projects – I had Vite for frontend builds, various helpers for images, custom solutions for thumbnails, another system for OG images, on some projects even WebPack etc.
And of course many projects where I versioned assets manually:

<link rel="stylesheet" href="{$baseUrl}/css/style.css?v=7">
<img src="{$baseUrl}/images/logo.png?v=1699123456" width="200" height="100" alt="Logo">

So I wrote a unified system for all static files. Small, elegant, with unlimited extensibility:

With Nette Assets the same code changes to this:

{asset 'css/style.css'}
<img n:asset="images/logo.png" alt="Logo">

It even works completely without configuration. Right after installation you can start using:

{asset 'logo.png'}     {* finds /www/assets/logo.png *}
{asset 'style.css'}    {* finds /www/assets/style.css *}
{asset 'app.js'}       {* finds /www/assets/app.js *}

If you have files elsewhere than in /www/assets/, just one line suffices:

assets:
    mapping:
        default: static  # files in /www/static/

Native Vite integration with HMR

I can't imagine modern frontend development without Vite. That's why Nette Assets has first-class support including Hot Module Replacement!
Minimal config is enough:
vite.config.ts:

import { defineConfig } from 'vite';
import nette from '@nette/vite-plugin';
export default defineConfig({
    plugins: [nette()],
    build: {
        rollupOptions: {
            input: 'assets/main.js',
        },
    },
});

common.neon:

assets:
    mapping:
        default:
            type: vite
            path: assets

In templates you use the same code:

{asset 'app.js'}

In development it automatically loads from Vite dev server with HMR.
In production it loads optimized builds.

Flexible Latte integration

The library provides three ways of usage:

{* Complete HTML element *}
{asset 'hero.jpg'}
{* Full control over HTML *}
<img n:asset="product.jpg" alt="Product" class="rounded">
{* Maximum flexibility *}
{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>

…And lots of other features

I'll be happy for feedback, testing, bug reports or ideas for improvement!