Nginx, Webpack dev serveur, BrowserSync dans une stack Docker

Chez Lexik, nous utilisons Docker pour tous nos projets Symfony, y compris ceux embarquants les frameworks javascript tels Angular, VueJS ou quelques fois ReactJS.
Depuis que nous avons intégré Spiriit, nous avons des intégrateurs qui gèrent leurs feuilles de styles et leurs javascript avec Webpack. La difficulté était d’ajouter BrowserSync sur des CMS dans un environnement Docker pour qu’il fonctionne comme attendu par les intégrateurs pour conserver leur productivité.

Je pars du principe que votre projet est déjà installé ainsi que BrowserSync, nous verrons ici uniquement les détails de configuration dans un fichier webpack.config.js qui peuvent être difficile à trouver. Aussi, vous devez connaître les bases du fonctionnement de Docker.

Configuration Docker

Pour notre configuration, nous allons utiliser deux services : nginx et node. Les services php et mysql qui sont souvent présent également n’étant pas utiles pour la démonstration, nous les ignorerons.

[codepen_embed height=300 theme_id=1 slug_hash=’jwGBh’ user=’arasdesign’ default_tab=’html’ animations=’run’]
See the Pen Flat minion by Amin Poursaied (@arasdesign) on CodePen
[/codepen_embed]

version: '3'
services:
  nginx:
    image: nginx
    volumes:
      - ./:/project
    ports:
      - 80:80
  node:
    image: node:10
    volume:
      - ./:/project
    working_dir: /project
    user: 1000:1000 # Dans la plupart des cas, adaptez au besoin
    command: "yarn run build"
    ports:
      - 8089:8089 # Port pour webpack
      - 3000:3000 # Port pour BrowserSync
  • nginx : il se base sur l’image nginx et servira les fichiers à l’adresse localhost, sur le port 80. Je ne détaillerai pas la configuration spécifique au serveur.
  • node : il se base sur l’image node en version 10, il servira à compiler les fichiers ainsi qu’exposer les ports 8089 et 3000 pour pouvoir utiliser BrowserSync.

Grâce à cette configuration minimale, nous aurons accès à nos fichiers compilés de deux façons différentes : https://www.spiriit.com/ permettra d’accéder au site avec les fichiers compilés de façon normale, comme si nous étions en production. https://www.spiriit.com:3000/ qui permettra d’accéder au site avec les fichiers avec l’option watch qui permet de recompiler les sources lorsqu’un changement est détecté et de réinjecter les fichiers compilés lorsqu’ils changent.

Deux choses sont à remarquer ici :

  • Le user qui exécute le container node doit être le votre pour que les assets compilés soient accessibles correctement. Ce sont les id de votre utilisateur et votre groupe linux. Pour les connaître, les commandes respectives dans le terminal sont id -u et id -g
  • La commande donnée au service est la commande qui s’exécutera lors de l’instanciation du container. Celle-ci se coupant à la fin de l’exécution, le container sera détruit. Vous pouvez la remplacer par votre commande permettant de surveiller les fichiers : yarn run watch par exemple

Configuration de Webpack dev serveur

Webpack dispose d’un serveur interne qui permet de recharger la page lorsque des changements interviennent dans les fichiers compilés. Il dispose également d’un proxy qui nous sera utile pour permettre la prise en compte d’éventuelles requêtes ajax. Voici donc la configuration du devServer uniquement, qui est expliquée ensuite.

devServer: {
  publicPath: '/path/to/assets/',
  contentBase: path.join(__dirname, 'path/to/dist'),
  disableHostCheck: true,
  host: '0.0.0.0',
  port: 8089,
  proxy: {
    '*': 'http://nginx',
    autoRewrite: true,
    changeOrigin: true,
    ignorePath: false,
    secure: false,
  }
}

Les points importants sont la propriété host que l’on met à 0.0.0.0 qui permet d’accéder au serveur depuis l’extérieur. Le port également, qui doit correspondre au port exposé par le container, afin de pouvoir communiquer grâce aux sockets. Le dernier paramètre important est le proxy, en particulier la première propriété '*': 'http://nginx' qui précise que toutes les urls correspondantes au pattern défini en clé sont envoyées à l’url indiquée en valeur, ici http://nginx. Le nom de domaine doit absolument correspondre au nom du service docker correspondant au serveur web, ici nginx (ligne 3 de la configuration précédente), il pourrait être httpd ou apache par exemple.

Configuration BrowserSync

BrowserSync permet de surveiller certains fichiers et de synchroniser différents navigateurs lorsque ces derniers sont modifiés afin d’éviter de rafraîchir les pages manuellement. Cela est très utile lors du développement d’un thème afin de voir directement les changements effectués sur les feuilles de styles et les javascripts. Voici donc la configuration à mettre en place pour le plugin.

plugins: [
  new BrowserSyncPlugin({
    host: '0.0.0.0',
    port: 3000,
    proxy: 'localhost:8089',
    open: false,
  }, {
    reload: false,
    injectCss: true,
  })
]

À nouveau, les paramètres importants sont : host qui, comme pour le devServer, doit avoir pour valeur '0.0.0.0' afin de pouvoir y accéder de l’extérieur du container sans problème. Le port, qui doit correspondre à nouveau au port exposé par le container. Enfin, le proxy qui doit correspondre à localhost obligatoirement : BrowserSync doit envoyer à Webpack les requêtes qui lui sont envoyées, avant que Webpack ne transmette d’éventuelles requêtes au serveur nginx. Webpack s’exécutant dans le container node, il s’agit bien du localhost par rapport au process BrowserSync. Le port également doit absolument correspondre au port du proxy de Webpack afin que tout soit connecté correctement.

Conclusion

Cette configuration est applicable à n’importe quel projet, peu importe le framework ou CMS utilisé côté backend. Les paramètres à régler sont les urls qu’il faut intercepter ou non par le proxy de chacun des deux outils.
Enfin, vous pouvez exécuter vos commandes habituelles à l’intérieur du container node : dockcer-compose exec node yarn run watch, watch étant bien entendu un script faisant parti de votre package.json qui correspondant à la commande suivante : webpack-dev-server --color --hot --config webpack.config.js.

Note : Si votre container est éteint, il vous faudra exécuter docker-compose run --rm -it -p 8089:8089 -p 3000:3000 node yarn run watch.

Limitation : Je n’ai pas réussi à faire fonctionner cette configuration lorsque des sous domaines sont introduits. Si quelqu’un sait comment faire, je serais preneur. Je publierai un article si une solution est trouvée.

Bonus : configuration plus flexible

Les containers docker peuvent être configurés grâce à un fichier .env dans le quel sont définis des variables d’environnement. Ces variables peuvent être transmises à l’intérieur des containers et utilisées dans la configuration webpack. Voici par exemple le contenu du fichier .env.

WEBPACK_SERVER_PORT=8089
BROWSERSYNC_PORT=3000

Ensuite, il faut mettre à jour le fichier docker-compose.yml

services:
  node:
    # ...
    ports:
      - ${WEBPACK_SERVER_PORT}:8089
      - ${BROWSERSYNC_PORT}:3000

Le fichier .env ne doit évidemment pas être versionné, cela permet à chaque développeur de pouvoir choisir les port à utiliser sans perturber ses propres applications. Vous pouvez en revanche versionner un fichier .env.dist qu’il faudra copier à chaque fois que le projet est récupéré par un développeur.

Voir l’étude de cas
Lire l’article
Voir le témoignage
Fermer