Nette Documentation Preview

syntax
Intégration de Vite
*******************

<div class=perex>

Les applications JavaScript modernes exigent des outils de build élaborés. Nette Assets offre une intégration de premier ordre avec [Vite |https://vite.dev/], l'outil de build frontend de nouvelle génération. Profitez d'un développement ultra-rapide avec le Hot Module Replacement (HMR) et de builds de production optimisés, sans le moindre casse-tête de configuration.

- **Zéro configuration** - pont automatique entre Vite et les templates PHP
- **Gestion complète des dépendances** - une seule balise s'occupe de tous les assets
- **Hot Module Replacement** - mises à jour instantanées du JavaScript et du CSS
- **Builds de production optimisés** - découpage du code et tree shaking

</div>


Nette Assets s'intègre parfaitement à Vite, si bien que vous profitez de tous ces avantages tout en écrivant vos templates comme d'habitude.


Mettre Vite en place
====================

Mettons Vite en place pas à pas. Ne vous inquiétez pas si les outils de build sont nouveaux pour vous : nous expliquerons tout !


Étape 1 : installer Vite
------------------------

Installez d'abord Vite et le plugin Nette dans votre projet :

```shell
npm install -D vite @nette/vite-plugin
```

Cela installe Vite et un plugin particulier qui l'aide à fonctionner parfaitement avec Nette.


Étape 2 : structure du projet
-----------------------------

L'approche standard consiste à placer les fichiers sources des assets dans un dossier `assets/` à la racine du projet, et les versions compilées dans `www/assets/` :

/--pre
<b>web-project/</b>
├── <b>assets/</b>                   ← fichiers sources (SCSS, TypeScript, images sources)
│   ├── <b>public/</b>               ← fichiers statiques (copiés tels quels)
│   │   └── <b>favicon.ico</b>
│   ├── <b>images/</b>
│   │   └── <b>logo.png</b>
│   ├── <b>app.js</b>                ← point d'entrée principal
│   └── <b>style.css</b>             ← vos styles
└── <b>www/</b>                      ← répertoire public (document root)
	├── <b>assets/</b>               ← les fichiers compilés arriveront ici
	└── <b>index.php</b>
\--

Le dossier `assets/` contient vos fichiers sources, le code que vous écrivez. Vite traitera ces fichiers et placera les versions compilées dans `www/assets/`.


Étape 3 : configurer Vite
-------------------------

Créez un fichier `vite.config.ts` à la racine de votre projet. Ce fichier indique à Vite où trouver vos fichiers sources et où placer les fichiers compilés.

Le plugin Vite de Nette est livré avec des valeurs par défaut intelligentes qui simplifient la configuration. Il suppose que vos fichiers sources front-end sont dans le répertoire `assets/` (option `root`) et que les fichiers compilés vont dans `www/assets/` (option `outDir`). Vous n'avez qu'à indiquer le [point d'entrée|#Points d'entrée] :

```js
import { defineConfig } from 'vite';
import nette from '@nette/vite-plugin';

export default defineConfig({
	plugins: [
		nette({
			entry: 'app.js',
		}),
	],
});
```

Sous le capot, outre `root` et `outDir`, le plugin définit quelques autres options de Vite pour que tout s'emboîte : `base` à `''` (les assets sont servis directement depuis le document root), `build.manifest` à `true` (pour que Nette Assets puisse associer les noms de fichiers hachés) et `build.assetsDir` à `''` (les fichiers compilés atterrissent directement dans `outDir`, sans sous-dossier `static/`). Vous pouvez redéfinir chacune d'elles.

.[note]
L'`outDir` par défaut (`www/assets`) exige que le répertoire `www/` existe déjà. Sinon, le plugin s'arrête avec l'erreur *"The output directory ... does not exist"*.

Si vous voulez indiquer un autre nom de répertoire pour construire vos assets, vous devrez changer quelques options :

```js
export default defineConfig({
	root: 'assets', // répertoire racine des assets sources

	build: {
		outDir: '../www/assets',  // où vont les fichiers compilés
	},

	// ... autre configuration ...
});
```

.[note]
Le chemin `outDir` est considéré comme relatif à `root`, d'où le `../` au début.


Étape 4 : configurer Nette
--------------------------

Parlez de Vite à Nette Assets dans votre `common.neon` :

```neon
assets:
	mapping:
		default:
			type: vite      # indique à Nette d'utiliser le ViteMapper
			path: assets
```


Étape 5 : ajouter les scripts
-----------------------------

Ajoutez ces scripts à votre `package.json` :

```json
{
	"scripts": {
		"dev": "vite",
		"build": "vite build"
	}
}
```

Vous pouvez désormais :
- `npm run dev` - démarrer le serveur de développement avec rechargement à chaud
- `npm run build` - créer les fichiers de production optimisés


Points d'entrée
===============

Un **point d'entrée** est le fichier principal par lequel votre application commence. Depuis ce fichier, vous importez d'autres fichiers (CSS, modules JavaScript, images), ce qui crée un arbre de dépendances. Vite suit ces imports et regroupe le tout.

Exemple de point d'entrée `assets/app.js` :

```js
// Import des styles
import './style.css'

// Import des modules JavaScript
import netteForms from 'nette-forms';
import naja from 'naja';

// Initialisation de votre application
netteForms.initOnLoad();
naja.initialize();
```

Dans le template, vous pouvez insérer un point d'entrée ainsi :

```latte
{asset 'app.js'}
```

Nette Assets génère automatiquement toutes les balises HTML nécessaires - JavaScript, CSS et toutes les autres dépendances.


Plusieurs points d'entrée
-------------------------

Les applications plus grandes ont souvent besoin de points d'entrée distincts :

```js
export default defineConfig({
	plugins: [
		nette({
			entry: [
				'app.js',      // pages publiques
				'admin.js',    // panneau d'administration
			],
		}),
	],
});
```

Utilisez-les dans différents templates :

```latte
{* Dans les pages publiques *}
{asset 'app.js'}

{* Dans le panneau d'administration *}
{asset 'admin.js'}
```


Important : fichiers sources et fichiers compilés
-------------------------------------------------

Il est essentiel de comprendre qu'en production vous ne pouvez charger que les fichiers que Vite met à disposition, soit par son manifest, soit en les copiant tels quels depuis le dossier public :

1. **Les points d'entrée** définis dans `entry` (y compris les modules qu'ils importent dynamiquement) et **les assets référencés depuis le JavaScript ou le CSS** (images, polices, ...) - tous sont consignés dans le manifest
2. **Les fichiers du répertoire `assets/public/`** - ceux-là ne sont *pas* dans le manifest ; ils sont copiés tels quels et `{asset}` les localise par un repli sur le système de fichiers

Vous **ne pouvez pas** charger avec `{asset}` n'importe quel fichier d'`assets/` : si un fichier n'est référencé nulle part, il ne sera pas compilé. Si vous voulez faire connaître d'autres assets à Vite, vous pouvez les déplacer dans le [dossier public|#Dossier public].

Notez que, par défaut, Vite intègre en ligne tous les assets de moins de 4 Ko, vous ne pourrez donc pas référencer ces fichiers directement. (Voir la [documentation de Vite |https://vite.dev/guide/assets.html]).

```latte
{* ✓ Cela fonctionne - c'est un point d'entrée *}
{asset 'app.js'}

{* ✓ Cela fonctionne - c'est dans assets/public/ *}
{asset 'favicon.ico'}

{* ✗ Cela ne fonctionnera pas - fichier quelconque dans assets/ *}
{asset 'components/button.js'}
```


Mode développement
==================

Le mode développement est totalement facultatif, mais il apporte de gros avantages une fois activé. Le principal est le **Hot Module Replacement (HMR)** : vous voyez les changements instantanément sans perdre l'état de l'application, ce qui rend le développement bien plus fluide et rapide.

Vite est un outil de build moderne qui rend le développement incroyablement rapide. Contrairement aux bundlers traditionnels, Vite sert votre code directement au navigateur pendant le développement, ce qui signifie un démarrage instantané du serveur quelle que soit la taille du projet et des mises à jour éclair.


Démarrer le serveur de développement
------------------------------------

Lancez le serveur de développement :

```shell
npm run dev
```

Vous verrez :

```
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
```

Gardez ce terminal ouvert pendant le développement.

Tant que le serveur de développement tourne, le plugin écrit un petit fichier signal `www/assets/.vite/nette.json` contenant son URL. Côté PHP, Nette Assets lit ce fichier et bascule sur le chargement depuis le serveur de développement lorsque les deux conditions suivantes sont remplies :
1. le serveur de développement Vite tourne (le fichier signal existe), et
2. votre application Nette est en mode débogage.

Le résultat :

```latte
{asset 'app.js'}
{* En développement : <script src="http://localhost:5173/@vite/client" type="module"></script>
                   <script src="http://localhost:5173/app.js" type="module"></script> *}
{* En production : <script src="/assets/app-4f3a2b1c.js" type="module" crossorigin></script> *}
```

Aucune configuration n'est nécessaire, cela fonctionne tout seul ! Pour désactiver la détection ou indiquer manuellement l'URL du serveur de développement, voir l'[option devServer |configuration#Mapper Vite].

.[note]
Le fichier signal se trouve dans `www/assets/.vite/nette.json` (juste à côté du `manifest.json` de production). Vous pouvez le renommer avec l'option `infoFile` du plugin, qui vaut `.vite/nette.json` par défaut. Si Nette ne détecte pas le serveur de développement en cours, vérifiez que ce fichier existe et pointe vers la bonne URL.


Travailler sur des domaines différents
--------------------------------------

Si votre serveur de développement tourne ailleurs que sur `localhost` (par exemple sur `myapp.local`), vous pouvez rencontrer des problèmes de CORS (Cross-Origin Resource Sharing). Le CORS est une fonction de sécurité des navigateurs web qui bloque par défaut les requêtes entre domaines différents. Quand votre application PHP tourne sur `myapp.local` mais que Vite tourne sur `localhost:5173`, le navigateur les voit comme des domaines différents et bloque les requêtes.

Vous avez deux possibilités pour régler cela :

**Option 1 : configurer le CORS**

La solution la plus simple est d'autoriser les requêtes cross-origin venant de votre application PHP :

```js
export default defineConfig({
	// ... autre configuration ...

	server: {
		cors: {
			origin: 'http://myapp.local',  // l'URL de votre application PHP
		},
	},
});
```

**Option 2 : faire tourner Vite sur votre domaine**

L'autre solution est de faire tourner Vite sur le même domaine que votre application PHP.

```js
export default defineConfig({
	// ... autre configuration ...

	server: {
		host: 'myapp.local',  // le même que votre application PHP
	},
});
```

En réalité, même dans ce cas, vous devez configurer le CORS, car le serveur de développement tourne sur le même nom d'hôte mais sur un port différent. Ici, cependant, le CORS est configuré automatiquement par le plugin Vite de Nette.


Développement en HTTPS
----------------------

Si vous développez en HTTPS, vous avez besoin de certificats pour votre serveur de développement Vite. Le plus simple est d'utiliser un plugin qui génère les certificats automatiquement :

```shell
npm install -D vite-plugin-mkcert
```

Voici comment le configurer dans `vite.config.ts` :

```js
import mkcert from 'vite-plugin-mkcert';

export default defineConfig({
	// ... autre configuration ...

	plugins: [
		mkcert(),  // génère les certificats automatiquement et active https
		nette(),
	],
});
```

Notez que si vous utilisez la configuration CORS (option 1 ci-dessus), vous devez mettre à jour l'URL d'origine pour utiliser `https://` au lieu de `http://`.


Développement avec Docker
-------------------------

Quand vous faites tourner Vite dans un conteneur Docker, deux points demandent votre attention : le navigateur de votre machine doit pouvoir joindre le serveur de développement, et Vite doit détecter les changements de fichiers au travers de la frontière du conteneur.

Commencez par [publier |https://docs.docker.com/get-started/docker-concepts/running-containers/publishing-ports/] le port de Vite depuis le conteneur et liez le serveur de développement à toutes les interfaces, afin qu'il soit joignable depuis l'extérieur du conteneur :

```js
export default defineConfig({
	// ... autre configuration ...

	plugins: [
		nette(),
	],
	server: {
		host: '0.0.0.0',      // écoute sur toutes les interfaces (nécessaire dans un conteneur)
		port: 5173,           // doit correspondre au port publié
		strictPort: true,     // échouer plutôt que choisir un autre port
		watch: {
			usePolling: true, // à activer si les changements de fichiers ne sont pas détectés sur les volumes montés
		},
	},
});
```

Le plugin écrit l'URL du serveur de développement dans `nette.json` pour le côté PHP. Comme `host: '0.0.0.0'` n'est pas utilisable par un navigateur (il redirige vers `localhost` pour chaque asset), le plugin la réécrit automatiquement en `localhost` dans cette URL, afin que les assets se chargent correctement.

Si vous ouvrez l'application sur un domaine personnalisé plutôt que sur `localhost`, définissez l'option `host` du plugin sur ce domaine :

```js
	plugins: [
		nette({ host: 'myapp.local' }),  // le même domaine que votre application PHP
	],
```

Le plugin utilise alors cet hôte pour l'URL du serveur de développement, l'ajoute aux origines CORS et le met dans la liste blanche `allowedHosts` de Vite - cela fonctionne donc sans aucun réglage CORS manuel.

Pour des installations plus complexes - par exemple quand Vite tourne derrière un reverse proxy où l'hôte public, le port et le protocole diffèrent tous de l'adresse interne - définissez `server.origin` de Vite sur l'URL publique complète. Le plugin la respecte et l'écrit telle quelle dans `nette.json`, au lieu de déduire l'URL du socket local :

```js
	server: {
		origin: 'https://myapp.local:8443',  // l'URL publique par laquelle le navigateur atteint Vite
	},
```


Builds de production
====================

Créez les fichiers de production optimisés :

```shell
npm run build
```

Vite va :
- minifier tout le JavaScript et le CSS
- découper le code en morceaux optimaux
- générer des noms de fichiers hachés pour invalider le cache
- créer un fichier manifest pour Nette Assets

Exemple de sortie :

```
www/assets/
├── app-4f3a2b1c.js       # Votre JavaScript principal (minifié)
├── app-7d8e9f2a.css      # CSS extrait (minifié)
├── vendor-8c4b5e6d.js    # Dépendances partagées
└── .vite/
	└── manifest.json     # Correspondances pour Nette Assets
```

Les noms de fichiers hachés garantissent que les navigateurs chargent toujours la dernière version.


Dossier public
==============

Les fichiers du répertoire `assets/public/` sont copiés vers la sortie sans traitement :

```
assets/
├── public/
│   ├── favicon.ico
│   ├── robots.txt
│   └── images/
│       └── og-image.jpg
├── app.js
└── style.css
```

Référencez-les normalement :

```latte
{* Ces fichiers sont copiés tels quels *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>
```

Pour les fichiers publics, vous pouvez utiliser les fonctionnalités de FilesystemMapper. L'option `extension` s'applique aux références sans extension (par exemple `{asset 'images/og-image'}` trouve d'abord `og-image.webp`) :

```neon
assets:
	mapping:
		default:
			type: vite
			path: assets
			extension: [webp, jpg, png]  # pour les références sans extension
			versioning: true             # Ajoute l'invalidation du cache
```

Dans la configuration `vite.config.ts`, vous pouvez changer le dossier public à l'aide de l'option `publicDir`.


Imports dynamiques
==================

Vite découpe automatiquement le code pour un chargement optimal. Les imports dynamiques vous permettent de ne charger du code que lorsqu'il est réellement nécessaire, ce qui réduit la taille du bundle initial :

```js
// Charge les composants lourds à la demande
button.addEventListener('click', async () => {
	let { Chart } = await import('./components/chart.js')
	new Chart(data)
})
```

Les imports dynamiques créent des chunks distincts qui ne sont chargés qu'au besoin. C'est ce qu'on appelle le "code splitting", l'une des fonctionnalités les plus puissantes de Vite. Quand vous utilisez des imports dynamiques, Vite crée automatiquement des fichiers JavaScript distincts pour chaque module importé dynamiquement.

La balise `{asset 'app.js'}` ne précharge **pas** automatiquement ces chunks dynamiques. C'est un comportement voulu : nous ne voulons pas télécharger du code qui pourrait ne jamais servir. Les chunks ne sont téléchargés qu'au moment où l'import dynamique s'exécute.

Si vous savez cependant que certains imports dynamiques sont critiques et seront bientôt nécessaires, vous pouvez les précharger :

```latte
{* Point d'entrée principal *}
{asset 'app.js'}

{* Précharge les imports dynamiques critiques *}
{preload 'components/chart.js'}
```

Cela dit au navigateur de télécharger le composant chart en arrière-plan, afin qu'il soit prêt dès qu'on en aura besoin.


Prise en charge de TypeScript
=============================

TypeScript fonctionne immédiatement :

```ts
// assets/main.ts
interface User {
	name: string
	email: string
}

export function greetUser(user: User): void {
	console.log(`Hello, ${user.name}!`)
}
```

Référencez les fichiers TypeScript normalement (comme pour tout fichier, `main.ts` doit être un point d'entrée) :

```latte
{asset 'main.ts'}
```

Pour une prise en charge complète de TypeScript, installez-le :

```shell
npm install -D typescript
```


Configuration supplémentaire de Vite
====================================

Voici quelques options de configuration utiles de Vite, avec des explications détaillées :

```js
export default defineConfig({
	// Répertoire racine contenant les assets sources
	root: 'assets',

	// Dossier dont le contenu est copié tel quel vers le répertoire de sortie
	// Par défaut : 'public' (relatif à 'root')
	publicDir: 'public',

	build: {
		// Où placer les fichiers compilés (relatif à 'root')
		outDir: '../www/assets',

		// Vider le répertoire de sortie avant le build ?
		// Utile pour supprimer les anciens fichiers des builds précédents
		emptyOutDir: true,

		// Sous-répertoire d'outDir pour les chunks et assets générés
		// Cela aide à organiser la structure de sortie
		assetsDir: 'static',

		rollupOptions: {
			// Point(s) d'entrée - un seul fichier ou un tableau de fichiers
			// Chaque point d'entrée devient un bundle distinct
			input: [
				'app.js',      // application principale
				'admin.js',    // panneau d'administration
			],
		},
	},

	server: {
		// Hôte auquel lier le serveur de développement
		// Utilisez '0.0.0.0' pour l'exposer au réseau
		host: 'localhost',

		// Port du serveur de développement
		port: 5173,

		// Configuration CORS pour les requêtes cross-origin
		cors: {
			origin: 'http://myapp.local',
		},
	},

	css: {
		// Activer les source maps CSS en développement
		devSourcemap: true,
	},

	plugins: [
		nette(),
	],
});
```

.[warning]
Attention aux chemins des points d'entrée dans `rollupOptions.input` ci-dessus : Rollup résout les chemins relatifs par rapport au répertoire de travail courant (la racine de votre projet), et **non** par rapport à `root: 'assets'`. Un simple `'app.js'` n'existera donc pas au moment du build. Utilisez soit l'option `entry` du plugin (qui résout les chemins des points d'entrée relativement à `root`), soit écrivez les chemins relativement à la racine du projet, par exemple `'assets/app.js'`.

C'est tout ! Vous disposez maintenant d'un système de build moderne intégré à Nette Assets.

Intégration de Vite

Les applications JavaScript modernes exigent des outils de build élaborés. Nette Assets offre une intégration de premier ordre avec Vite, l'outil de build frontend de nouvelle génération. Profitez d'un développement ultra-rapide avec le Hot Module Replacement (HMR) et de builds de production optimisés, sans le moindre casse-tête de configuration.

  • Zéro configuration – pont automatique entre Vite et les templates PHP
  • Gestion complète des dépendances – une seule balise s'occupe de tous les assets
  • Hot Module Replacement – mises à jour instantanées du JavaScript et du CSS
  • Builds de production optimisés – découpage du code et tree shaking

Nette Assets s'intègre parfaitement à Vite, si bien que vous profitez de tous ces avantages tout en écrivant vos templates comme d'habitude.

Mettre Vite en place

Mettons Vite en place pas à pas. Ne vous inquiétez pas si les outils de build sont nouveaux pour vous : nous expliquerons tout !

Étape 1 : installer Vite

Installez d'abord Vite et le plugin Nette dans votre projet :

npm install -D vite @nette/vite-plugin

Cela installe Vite et un plugin particulier qui l'aide à fonctionner parfaitement avec Nette.

Étape 2 : structure du projet

L'approche standard consiste à placer les fichiers sources des assets dans un dossier assets/ à la racine du projet, et les versions compilées dans www/assets/ :

web-project/
├── assets/                   ← fichiers sources (SCSS, TypeScript, images sources)
│   ├── public/               ← fichiers statiques (copiés tels quels)
│   │   └── favicon.ico
│   ├── images/
│   │   └── logo.png
│   ├── app.js                ← point d'entrée principal
│   └── style.css             ← vos styles
└── www/                      ← répertoire public (document root)
	├── assets/               ← les fichiers compilés arriveront ici
	└── index.php

Le dossier assets/ contient vos fichiers sources, le code que vous écrivez. Vite traitera ces fichiers et placera les versions compilées dans www/assets/.

Étape 3 : configurer Vite

Créez un fichier vite.config.ts à la racine de votre projet. Ce fichier indique à Vite où trouver vos fichiers sources et où placer les fichiers compilés.

Le plugin Vite de Nette est livré avec des valeurs par défaut intelligentes qui simplifient la configuration. Il suppose que vos fichiers sources front-end sont dans le répertoire assets/ (option root) et que les fichiers compilés vont dans www/assets/ (option outDir). Vous n'avez qu'à indiquer le point d'entrée :

import { defineConfig } from 'vite';
import nette from '@nette/vite-plugin';

export default defineConfig({
	plugins: [
		nette({
			entry: 'app.js',
		}),
	],
});

Sous le capot, outre root et outDir, le plugin définit quelques autres options de Vite pour que tout s'emboîte : base à '' (les assets sont servis directement depuis le document root), build.manifest à true (pour que Nette Assets puisse associer les noms de fichiers hachés) et build.assetsDir à '' (les fichiers compilés atterrissent directement dans outDir, sans sous-dossier static/). Vous pouvez redéfinir chacune d'elles.

L'outDir par défaut (www/assets) exige que le répertoire www/ existe déjà. Sinon, le plugin s'arrête avec l'erreur „The output directory … does not exist“.

Si vous voulez indiquer un autre nom de répertoire pour construire vos assets, vous devrez changer quelques options :

export default defineConfig({
	root: 'assets', // répertoire racine des assets sources

	build: {
		outDir: '../www/assets',  // où vont les fichiers compilés
	},

	// ... autre configuration ...
});

Le chemin outDir est considéré comme relatif à root, d'où le ../ au début.

Étape 4 : configurer Nette

Parlez de Vite à Nette Assets dans votre common.neon :

assets:
	mapping:
		default:
			type: vite      # indique à Nette d'utiliser le ViteMapper
			path: assets

Étape 5 : ajouter les scripts

Ajoutez ces scripts à votre package.json :

{
	"scripts": {
		"dev": "vite",
		"build": "vite build"
	}
}

Vous pouvez désormais :

  • npm run dev – démarrer le serveur de développement avec rechargement à chaud
  • npm run build – créer les fichiers de production optimisés

Points d'entrée

Un point d'entrée est le fichier principal par lequel votre application commence. Depuis ce fichier, vous importez d'autres fichiers (CSS, modules JavaScript, images), ce qui crée un arbre de dépendances. Vite suit ces imports et regroupe le tout.

Exemple de point d'entrée assets/app.js :

// Import des styles
import './style.css'

// Import des modules JavaScript
import netteForms from 'nette-forms';
import naja from 'naja';

// Initialisation de votre application
netteForms.initOnLoad();
naja.initialize();

Dans le template, vous pouvez insérer un point d'entrée ainsi :

{asset 'app.js'}

Nette Assets génère automatiquement toutes les balises HTML nécessaires – JavaScript, CSS et toutes les autres dépendances.

Plusieurs points d'entrée

Les applications plus grandes ont souvent besoin de points d'entrée distincts :

export default defineConfig({
	plugins: [
		nette({
			entry: [
				'app.js',      // pages publiques
				'admin.js',    // panneau d'administration
			],
		}),
	],
});

Utilisez-les dans différents templates :

{* Dans les pages publiques *}
{asset 'app.js'}

{* Dans le panneau d'administration *}
{asset 'admin.js'}

Important : fichiers sources et fichiers compilés

Il est essentiel de comprendre qu'en production vous ne pouvez charger que les fichiers que Vite met à disposition, soit par son manifest, soit en les copiant tels quels depuis le dossier public :

  1. Les points d'entrée définis dans entry (y compris les modules qu'ils importent dynamiquement) et les assets référencés depuis le JavaScript ou le CSS (images, polices, …) – tous sont consignés dans le manifest
  2. Les fichiers du répertoire assets/public/ – ceux-là ne sont pas dans le manifest ; ils sont copiés tels quels et {asset} les localise par un repli sur le système de fichiers

Vous ne pouvez pas charger avec {asset} n'importe quel fichier d'assets/ : si un fichier n'est référencé nulle part, il ne sera pas compilé. Si vous voulez faire connaître d'autres assets à Vite, vous pouvez les déplacer dans le dossier public.

Notez que, par défaut, Vite intègre en ligne tous les assets de moins de 4 Ko, vous ne pourrez donc pas référencer ces fichiers directement. (Voir la documentation de Vite).

{* ✓ Cela fonctionne - c'est un point d'entrée *}
{asset 'app.js'}

{* ✓ Cela fonctionne - c'est dans assets/public/ *}
{asset 'favicon.ico'}

{* ✗ Cela ne fonctionnera pas - fichier quelconque dans assets/ *}
{asset 'components/button.js'}

Mode développement

Le mode développement est totalement facultatif, mais il apporte de gros avantages une fois activé. Le principal est le Hot Module Replacement (HMR) : vous voyez les changements instantanément sans perdre l'état de l'application, ce qui rend le développement bien plus fluide et rapide.

Vite est un outil de build moderne qui rend le développement incroyablement rapide. Contrairement aux bundlers traditionnels, Vite sert votre code directement au navigateur pendant le développement, ce qui signifie un démarrage instantané du serveur quelle que soit la taille du projet et des mises à jour éclair.

Démarrer le serveur de développement

Lancez le serveur de développement :

npm run dev

Vous verrez :

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

Gardez ce terminal ouvert pendant le développement.

Tant que le serveur de développement tourne, le plugin écrit un petit fichier signal www/assets/.vite/nette.json contenant son URL. Côté PHP, Nette Assets lit ce fichier et bascule sur le chargement depuis le serveur de développement lorsque les deux conditions suivantes sont remplies :

  1. le serveur de développement Vite tourne (le fichier signal existe), et
  2. votre application Nette est en mode débogage.

Le résultat :

{asset 'app.js'}
{* En développement : <script src="http://localhost:5173/@vite/client" type="module"></script>
                   <script src="http://localhost:5173/app.js" type="module"></script> *}
{* En production : <script src="/assets/app-4f3a2b1c.js" type="module" crossorigin></script> *}

Aucune configuration n'est nécessaire, cela fonctionne tout seul ! Pour désactiver la détection ou indiquer manuellement l'URL du serveur de développement, voir l'option devServer.

Le fichier signal se trouve dans www/assets/.vite/nette.json (juste à côté du manifest.json de production). Vous pouvez le renommer avec l'option infoFile du plugin, qui vaut .vite/nette.json par défaut. Si Nette ne détecte pas le serveur de développement en cours, vérifiez que ce fichier existe et pointe vers la bonne URL.

Travailler sur des domaines différents

Si votre serveur de développement tourne ailleurs que sur localhost (par exemple sur myapp.local), vous pouvez rencontrer des problèmes de CORS (Cross-Origin Resource Sharing). Le CORS est une fonction de sécurité des navigateurs web qui bloque par défaut les requêtes entre domaines différents. Quand votre application PHP tourne sur myapp.local mais que Vite tourne sur localhost:5173, le navigateur les voit comme des domaines différents et bloque les requêtes.

Vous avez deux possibilités pour régler cela :

Option 1 : configurer le CORS

La solution la plus simple est d'autoriser les requêtes cross-origin venant de votre application PHP :

export default defineConfig({
	// ... autre configuration ...

	server: {
		cors: {
			origin: 'http://myapp.local',  // l'URL de votre application PHP
		},
	},
});

Option 2 : faire tourner Vite sur votre domaine

L'autre solution est de faire tourner Vite sur le même domaine que votre application PHP.

export default defineConfig({
	// ... autre configuration ...

	server: {
		host: 'myapp.local',  // le même que votre application PHP
	},
});

En réalité, même dans ce cas, vous devez configurer le CORS, car le serveur de développement tourne sur le même nom d'hôte mais sur un port différent. Ici, cependant, le CORS est configuré automatiquement par le plugin Vite de Nette.

Développement en HTTPS

Si vous développez en HTTPS, vous avez besoin de certificats pour votre serveur de développement Vite. Le plus simple est d'utiliser un plugin qui génère les certificats automatiquement :

npm install -D vite-plugin-mkcert

Voici comment le configurer dans vite.config.ts :

import mkcert from 'vite-plugin-mkcert';

export default defineConfig({
	// ... autre configuration ...

	plugins: [
		mkcert(),  // génère les certificats automatiquement et active https
		nette(),
	],
});

Notez que si vous utilisez la configuration CORS (option 1 ci-dessus), vous devez mettre à jour l'URL d'origine pour utiliser https:// au lieu de http://.

Développement avec Docker

Quand vous faites tourner Vite dans un conteneur Docker, deux points demandent votre attention : le navigateur de votre machine doit pouvoir joindre le serveur de développement, et Vite doit détecter les changements de fichiers au travers de la frontière du conteneur.

Commencez par publier le port de Vite depuis le conteneur et liez le serveur de développement à toutes les interfaces, afin qu'il soit joignable depuis l'extérieur du conteneur :

export default defineConfig({
	// ... autre configuration ...

	plugins: [
		nette(),
	],
	server: {
		host: '0.0.0.0',      // écoute sur toutes les interfaces (nécessaire dans un conteneur)
		port: 5173,           // doit correspondre au port publié
		strictPort: true,     // échouer plutôt que choisir un autre port
		watch: {
			usePolling: true, // à activer si les changements de fichiers ne sont pas détectés sur les volumes montés
		},
	},
});

Le plugin écrit l'URL du serveur de développement dans nette.json pour le côté PHP. Comme host: '0.0.0.0' n'est pas utilisable par un navigateur (il redirige vers localhost pour chaque asset), le plugin la réécrit automatiquement en localhost dans cette URL, afin que les assets se chargent correctement.

Si vous ouvrez l'application sur un domaine personnalisé plutôt que sur localhost, définissez l'option host du plugin sur ce domaine :

	plugins: [
		nette({ host: 'myapp.local' }),  // le même domaine que votre application PHP
	],

Le plugin utilise alors cet hôte pour l'URL du serveur de développement, l'ajoute aux origines CORS et le met dans la liste blanche allowedHosts de Vite – cela fonctionne donc sans aucun réglage CORS manuel.

Pour des installations plus complexes – par exemple quand Vite tourne derrière un reverse proxy où l'hôte public, le port et le protocole diffèrent tous de l'adresse interne – définissez server.origin de Vite sur l'URL publique complète. Le plugin la respecte et l'écrit telle quelle dans nette.json, au lieu de déduire l'URL du socket local :

	server: {
		origin: 'https://myapp.local:8443',  // l'URL publique par laquelle le navigateur atteint Vite
	},

Builds de production

Créez les fichiers de production optimisés :

npm run build

Vite va :

  • minifier tout le JavaScript et le CSS
  • découper le code en morceaux optimaux
  • générer des noms de fichiers hachés pour invalider le cache
  • créer un fichier manifest pour Nette Assets

Exemple de sortie :

www/assets/
├── app-4f3a2b1c.js       # Votre JavaScript principal (minifié)
├── app-7d8e9f2a.css      # CSS extrait (minifié)
├── vendor-8c4b5e6d.js    # Dépendances partagées
└── .vite/
	└── manifest.json     # Correspondances pour Nette Assets

Les noms de fichiers hachés garantissent que les navigateurs chargent toujours la dernière version.

Dossier public

Les fichiers du répertoire assets/public/ sont copiés vers la sortie sans traitement :

assets/
├── public/
│   ├── favicon.ico
│   ├── robots.txt
│   └── images/
│       └── og-image.jpg
├── app.js
└── style.css

Référencez-les normalement :

{* Ces fichiers sont copiés tels quels *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>

Pour les fichiers publics, vous pouvez utiliser les fonctionnalités de FilesystemMapper. L'option extension s'applique aux références sans extension (par exemple {asset 'images/og-image'} trouve d'abord og-image.webp) :

assets:
	mapping:
		default:
			type: vite
			path: assets
			extension: [webp, jpg, png]  # pour les références sans extension
			versioning: true             # Ajoute l'invalidation du cache

Dans la configuration vite.config.ts, vous pouvez changer le dossier public à l'aide de l'option publicDir.

Imports dynamiques

Vite découpe automatiquement le code pour un chargement optimal. Les imports dynamiques vous permettent de ne charger du code que lorsqu'il est réellement nécessaire, ce qui réduit la taille du bundle initial :

// Charge les composants lourds à la demande
button.addEventListener('click', async () => {
	let { Chart } = await import('./components/chart.js')
	new Chart(data)
})

Les imports dynamiques créent des chunks distincts qui ne sont chargés qu'au besoin. C'est ce qu'on appelle le „code splitting“, l'une des fonctionnalités les plus puissantes de Vite. Quand vous utilisez des imports dynamiques, Vite crée automatiquement des fichiers JavaScript distincts pour chaque module importé dynamiquement.

La balise {asset 'app.js'} ne précharge pas automatiquement ces chunks dynamiques. C'est un comportement voulu : nous ne voulons pas télécharger du code qui pourrait ne jamais servir. Les chunks ne sont téléchargés qu'au moment où l'import dynamique s'exécute.

Si vous savez cependant que certains imports dynamiques sont critiques et seront bientôt nécessaires, vous pouvez les précharger :

{* Point d'entrée principal *}
{asset 'app.js'}

{* Précharge les imports dynamiques critiques *}
{preload 'components/chart.js'}

Cela dit au navigateur de télécharger le composant chart en arrière-plan, afin qu'il soit prêt dès qu'on en aura besoin.

Prise en charge de TypeScript

TypeScript fonctionne immédiatement :

// assets/main.ts
interface User {
	name: string
	email: string
}

export function greetUser(user: User): void {
	console.log(`Hello, ${user.name}!`)
}

Référencez les fichiers TypeScript normalement (comme pour tout fichier, main.ts doit être un point d'entrée) :

{asset 'main.ts'}

Pour une prise en charge complète de TypeScript, installez-le :

npm install -D typescript

Configuration supplémentaire de Vite

Voici quelques options de configuration utiles de Vite, avec des explications détaillées :

export default defineConfig({
	// Répertoire racine contenant les assets sources
	root: 'assets',

	// Dossier dont le contenu est copié tel quel vers le répertoire de sortie
	// Par défaut : 'public' (relatif à 'root')
	publicDir: 'public',

	build: {
		// Où placer les fichiers compilés (relatif à 'root')
		outDir: '../www/assets',

		// Vider le répertoire de sortie avant le build ?
		// Utile pour supprimer les anciens fichiers des builds précédents
		emptyOutDir: true,

		// Sous-répertoire d'outDir pour les chunks et assets générés
		// Cela aide à organiser la structure de sortie
		assetsDir: 'static',

		rollupOptions: {
			// Point(s) d'entrée - un seul fichier ou un tableau de fichiers
			// Chaque point d'entrée devient un bundle distinct
			input: [
				'app.js',      // application principale
				'admin.js',    // panneau d'administration
			],
		},
	},

	server: {
		// Hôte auquel lier le serveur de développement
		// Utilisez '0.0.0.0' pour l'exposer au réseau
		host: 'localhost',

		// Port du serveur de développement
		port: 5173,

		// Configuration CORS pour les requêtes cross-origin
		cors: {
			origin: 'http://myapp.local',
		},
	},

	css: {
		// Activer les source maps CSS en développement
		devSourcemap: true,
	},

	plugins: [
		nette(),
	],
});

Attention aux chemins des points d'entrée dans rollupOptions.input ci-dessus : Rollup résout les chemins relatifs par rapport au répertoire de travail courant (la racine de votre projet), et non par rapport à root: 'assets'. Un simple 'app.js' n'existera donc pas au moment du build. Utilisez soit l'option entry du plugin (qui résout les chemins des points d'entrée relativement à root), soit écrivez les chemins relativement à la racine du projet, par exemple 'assets/app.js'.

C'est tout ! Vous disposez maintenant d'un système de build moderne intégré à Nette Assets.