Phoenix : changer de bundler
Depuis sa version 1.4, Phoenix embarque Webpack pour bundler les différentes dépendances. Nous allons voir qu’il est facile de changer d’outil en prenant Parcel comme exemple. Cet outil a l’avantage de ne pas nécessiter de configuration pour fonctionner.
Initialisation
Créons un nouveau projet, sans “ecto” pour ne pas avoir besoin de configurer une base de données.
mix phx.new app --no-ecto
Lançons le serveur de Phoenix.
mix phx.server
Phoenix exécute Webpack pour nous et écoute les changements de fichiers pour nous apporter les modifications en hot reload.
Si j’édite le fichier assets/css/app.css
pour changer la couleur de fond du body on peut voir le changement sans recharger la page.
/* This file is for your main application css. */
@import "./phoenix.css";
body {
background: darkgray;
}
Notre but est donc de garder ce comportement, qui offre un confort de développement, mais en utilisant un autre outil.
Webpack build nos assets à destination de priv/static
. Phoenix nécessite que nos fichiers statiques soient buildés à destination de ce dossier. Cela reste néanmoins configurable
Avant de continuer coupons notre serveur et supprimons le dossier généré par Webpack pour partir sur une base propre
rm -rf priv/static
Configuration de Parcel au sein de Phoenix
Installons Parcel ainsi qu’un plugin magique dont le détail ne rentre pas dans le cadre de cet article.
cd assets/ && npm install --save-dev parcel-bundler parcel-plugin-static-files-copy
Dans le fichiers config/dev.exs
il faut remplacer
config :app, AppWeb.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [
node: [
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch-stdin",
cd: Path.expand("../assets", __DIR__)
]
]
par
config :app, AppWeb.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [
node: [
"node_modules/.bin/parcel",
"watch",
"js/app.js",
"-d",
"../priv/static",
cd: Path.expand("../assets", __DIR__)
]
]
Désormais lorsque nous lançons un mix phx.server
nous pouvons voir que Phoenix lance désormais Parcel.
Et le dossier de destination est bien priv/static
Mais malheureusement, nos css et js ne sont plus chargés
Webpack générait un dossier css
et un dossier js
contenant chacun leur bundle. Parcel se passe des dossiers intermédiaires. Il faut donc aller mettre à jour les chemins des fichiers importés dans le template lib/app_web/templates/layout/app.html.eex
.
On remplace
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
</head>
<body>
###
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</body>
</html>
par
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/app.css") %>"/>
</head>
<body>
###
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/app.js") %>"></script>
</body>
</html>
Et 🎉, ça ne marche pas 😢.
Ce comportement vient du fait que Phoenix autorise uniquement les fichiers respectant certains patterns à être servi comme fichiers statiques. Ces patterns sont configurables dans le fichier lib/app_web/endpoint.ex
plug Plug.Static,
at: "/",
from: :app,
gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt)
Cette configuration signifie que seul les fichiers présents dans les dossiers css
fonts
images
js
ou les fichiers favicon.ico
et robots.txt
sont autorisés à être servi par Phoenix. Ces dossiers doivent bien entendu être présent dans priv/static
😉.
plug Plug.Static,
at: "/",
from: :app,
gzip: false,
only: ~w(app.css fonts images app.js favicon.ico robots.txt)
Comme nous n’avons pas de dossiers intermédiaires css
et js
nous les remplaçons par les fichiers app.css
et app.js
générés par Parcel.
Maintenant l’application fonctionne correctement. Si j’édite le fichier assets/js/app.js
pour y ajouter un console.log
import "phoenix_html";
import css from "../css/app.css";
console.log("Meeeeeeeeh");
Un “Meeeeeeeeh” apparait dans la console de notre navigateur sans avoir besoin de recharger la page 🎉.
Nettoyage
Maintenant que nous avons ajouté Parcel il ne nous reste plus qu’à supprimer les vestiges de Webpack :
cd assets && npm uninstall babel-loader copy-webpack-plugin css-loader mini-css-extract-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin webpack webpack-cli && rm webpack.config.js
Conclusion
Peut importe que vous choisissiez de garder Webpack, d’utiliser Rollup, Parcel… Si vous choisissez de modifier la configuration de votre bundler, il faut penser à :
- configurer correctement son bundler (facile avec Parcel)
- changer le script surveillant les modifications de fichiers (dev.exs)
- veiller à ce que le fichiers statiques puissent être servi correctement (endpoint.ex)
- modifier les chemins dans les templates (app.html.eex)
Liens utiles
- Je me suis inspiré de ce dépôt Github. La base de code reprend la structure d’une ancienne version de Phoenix, ne l’utilisez pas tel quel si vous voulez être à jour.
- Mon ancien article
- La documentation sur la configuration du Endpoint