Frappe Framework
Regroupement des assets (Asset Bundling)
Frappe embarque un bundler qui compile les assets côté client (JS moderne, TypeScript, Vue, SCSS, CSS…). Cette page explique bench build et bench watch, la convention des fichiers .bundle, l’import de bibliothèques npm et l’inclusion des assets compilés dans vos pages.
Pourquoi regrouper les assets ?
Cette page explique comment fonctionne le regroupement (bundling) des assets statiques dans Frappe Framework.
Frappe fournit une interface d’administration riche, accessible à /app. C’est une application monopage (SPA) écrite en JavaScript moderne, dont les styles sont écrits en SASS (fichiers .scss). Le navigateur ne comprend pas directement ces fichiers : il faut les compiler avant de les lui envoyer.
Frappe inclut donc un bundler d’assets capable de compiler les fichiers côté client suivants :
| Extension | Contenu |
|---|---|
.js | Syntaxe moderne avec import et export |
.ts | Fichiers TypeScript |
.vue | Composants Vue monofichiers |
.css | CSS traité avec PostCSS |
.scss | Fichiers SASS |
.sass | Fichiers SASS en syntaxe indentée |
.styl | Fichiers Stylus |
.less | Fichiers Less |
Ces fichiers sont compilés en .js ou en .css selon leur type, puis envoyés au navigateur.
Compiler les assets avec bench build
Pour compiler les assets avec le bundler, lancez la commande suivante depuis le dossier frappe-bench :
$ bench buildVous pouvez limiter la compilation à certaines apps avec l’option --apps :
# build only frappe assets
$ bench build --apps frappe
# build only frappe and erpnext assets
$ bench build --apps frappe,erpnextMode watch
Quand vous travaillez sur des fichiers regroupés, il faudrait relancer la compilation à chaque modification. Le bundler propose pour cela un mode de surveillance (watch) : il écoute les changements du système de fichiers et recompile dès qu’un fichier change.
La commande suivante lance un processus de longue durée qui surveille vos fichiers et les recompile à chaque modification. À chaque recompilation, il affiche une ligne contenant « Compiled changes... ».
$ bench watch
Watching for changes...
1:17:28 PM: Compiled changes...Là aussi, l’option --apps permet de ne surveiller que certaines apps :
# watch only erpnext assets
$ bench watch --apps erpnext> [!NOTE]
> Depuis la version 14, le bureau (Desk) se recharge automatiquement quand les assets sont recompilés en mode watch. Ce comportement se règle avec la variable d’environnement LIVE_RELOAD ou avec la clé live_reload du fichier common_site_config.json.
Fichiers bundle
Un fichier bundle est le point d’entrée d’un asset que le bundler prend en charge pour la compilation. Par exemple, un fichier main.bundle.js placé dans le dossier public de votre app est automatiquement détecté et compilé vers /assets/[app]/dist/js/main.bundle.[hash].js. Un hachage unique, calculé à partir du contenu du fichier de sortie, est ajouté au nom du fichier : il sert à invalider le cache des navigateurs (cache-busting).
De même, un fichier style.bundle.scss dans le dossier public est compilé vers /assets/[app]/dist/css/style.bundle.css. Notez que l’extension passe de .scss à .css, puisque les navigateurs comprennent le CSS mais pas le SASS.
Les fichiers bundle peuvent se trouver à n’importe quel niveau d’imbrication dans le dossier public, mais ils sont toujours compilés dans dist/js ou dist/css selon leur type. Si un fichier existe à public/main.bundle.js et un autre à public/src/main.bundle.js, la sortie compilée du second écrase celle du premier. Le bundler affiche un avertissement en cas de collision.
Voici d’autres exemples d’entrées et de sorties :
| Entrée | Sortie |
|---|---|
[app]/public/main.bundle.js | /assets/dist/[app]/js/main.bundle.[hash].js |
[app]/public/src/main.bundle.js | /assets/dist/[app]/js/main.bundle.[hash].js |
[app]/public/src/utils/utils.bundle.js | /assets/dist/[app]/js/utils.bundle.[hash].js |
[app]/public/main.bundle.ts | /assets/dist/[app]/js/main.bundle.[hash].js |
[app]/public/main.bundle.css | /assets/dist/[app]/css/main.bundle.[hash].css |
[app]/public/styles/main.bundle.css | /assets/dist/[app]/css/main.bundle.[hash].css |
[app]/public/main.bundle.scss | /assets/dist/[app]/css/main.bundle.[hash].css |
[app]/public/main.bundle.sass | /assets/dist/[app]/css/main.bundle.[hash].css |
[app]/public/main.bundle.styl | /assets/dist/[app]/css/main.bundle.[hash].css |
[app]/public/main.bundle.less | /assets/dist/[app]/css/main.bundle.[hash].css |
Importer des bibliothèques npm
Si vous connaissez le développement web moderne, vous aurez sans doute besoin d’installer des bibliothèques tierces depuis npm et de les utiliser dans votre projet.
Supposons que vous vouliez utiliser la bibliothèque dayjs pour manipuler les dates et heures dans votre app. Installez-la d’abord avec yarn, depuis la racine du dossier de votre app :
$ cd frappe-bench/apps/myapp
$ yarn add dayjsVous pouvez ensuite l’importer dans vos fichiers source :
myapp/public/main.bundle.js
import * as dayjs from 'dayjs';
console.log(dayjs())Inclure les assets compilés dans le HTML
Le fichier produit par la compilation d’un bundle contient un hachage unique. Vous ne pouvez donc pas coder son chemin en dur : à la prochaine modification du fichier, le hachage changera. Frappe fournit plusieurs fonctions d’aide pour résoudre ce problème.
Inclure des assets dans des fichiers HTML personnalisés
Les méthodes Jinja include_script et include_style produisent le bon chemin du fichier, avec le balisage HTML correspondant, pour les fichiers .js et .css respectivement.
index.html
My App
{{ include_style('style.bundle.css') }}
{{ include_script('main.bundle.js') }}index.html (rendu)
My App
<script type="text/javascript" src="/assets/myapp/dist/js/main.bundle.BYJXV4LB.js"></script>> [!NOTE] > Dans la version extraite de la documentation officielle, le balisage HTML de ces deux exemples a été en grande partie perdu ; seuls le texte, les appels Jinja et la balise script rendue subsistent.
Inclure des assets dans app.html
Pour inclure les assets compilés de votre app dans /app, utilisez les hooks app_include_js et app_include_css : ils les chargent dans app.html.
[app]/hooks.py
app_include_js = ['main.bundle.js']
app_include_css = ['style.bundle.css']Obtenir le chemin d’un asset compilé
Si vous avez seulement besoin du chemin de l’asset compilé, utilisez la méthode Jinja bundled_asset pour le générer.
Jinja
{{ bundled_asset('main.bundle.js') }}Rendu
/assets/myapp/dist/js/main.bundle.BYJXV4LB.jsAPI Python
Ces fonctions existent aussi en Python. Vous pouvez les importer depuis jinja_globals.py :
from frappe.utils.jinja_globals import bundled_asset, include_script, include_style
bundled_asset('main.bundle.js')Charger des assets compilés à la demande dans /app
Pour charger paresseusement (lazy loading) des assets compilés dans l’interface d’administration (/app), utilisez la méthode frappe.require :
frappe.require('main.bundle.js').then(() => {
// main.bundle.js is now loaded
})Cette approche est utile quand vous voulez charger votre code selon une condition. Le premier chargement de la page n’est pas alourdi, ce qui est meilleur pour les performances.
Mode production
Au moment de déployer votre app en production, vous pouvez compiler vos assets en mode production. Dans ce mode, le bundler minifie la sortie finale du bundle, ce qui réduit la taille des fichiers.
Pour compiler en mode production, lancez :
$ bench build --production