{"id":3734,"date":"2023-02-01T14:23:44","date_gmt":"2023-02-01T13:23:44","guid":{"rendered":"https:\/\/blog.alwaysdata.com\/?p=3734"},"modified":"2023-02-06T08:58:29","modified_gmt":"2023-02-06T07:58:29","slug":"devops-react-we-can-be-heroes-just-for-one-app","status":"publish","type":"post","link":"https:\/\/blog.alwaysdata.com\/fr\/2023\/02\/01\/devops-react-we-can-be-heroes-just-for-one-app\/","title":{"rendered":"Devops React&nbsp;: \u00ab&nbsp;We can be Heroes, just for one&nbsp;app&nbsp;\u00bb"},"content":{"rendered":"\n<p>Dans un \u00e9cosyst\u00e8me <em>front-end<\/em> toujours plus avanc\u00e9, toujours plus riche en <em>frameworks<\/em>, avec un <em>tooling<\/em> toujours plus exigeant, on peut parfois se retrouver dans une situation cocasse&nbsp;: comment g\u00e9rer un d\u00e9ploiement fiable et efficace&nbsp;? Cas d\u2019\u00e9cole avec <strong>Create React App<\/strong>, c\u2019est&nbsp;parti&nbsp;!<\/p>\n\n\n<figure class=\"embed-media__giphy\" style=\"width:65%; padding-bottom:calc(65% * (368 + 12) \/ (480 + 12))\">\n    <video id=\"giphy-${token}\" autoplay loop muted playsinline>\n        <source src=\"https:\/\/media.giphy.com\/media\/3o6MbsFDtuAOwPdBxC\/giphy.mp4\" type=\"video\/mp4\">\n        <img decoding=\"async\" src=\"https:\/\/media.giphy.com\/media\/3o6MbsFDtuAOwPdBxC\/giphy.gif\" alt=\"Simpsons GIF, Lisa telling Bart : Bart, with these powers, we can be superheroes. @Giphy\">\n    <\/video>\n<\/figure>\n\n\n<div class=\"inset\" data-title=\"Note lexicale\">Ce guide se d\u00e9roulera dans deux environnements&nbsp;:\n<ul>\n<li><i>Local<\/i>&nbsp;: ces commandes sont \u00e0&nbsp;ex\u00e9cuter sur votre environnement de d\u00e9veloppement local (Probablement&nbsp;: votre laptop)&nbsp;;<\/li>\n<li><i>Serveur<\/i>&nbsp;: sur votre compte d\u2019h\u00e9bergement. Chez <b>alwaysdata<\/b>, vous pouvez vous connecter en <i>SSH<\/i> pour ex\u00e9cuter ces commandes.<\/li>\n<\/ul>\n<p>Dans le cas d\u2019un h\u00e9bergement chez <b>alwaysdata<\/b>, les mentions <code>&lt;account&gt;<\/code> dans les chemins\/URLs\/etc. font r\u00e9f\u00e9rence \u00e0&nbsp;votre nom de compte (<i>i.e.<\/i> si votre nom de compte est <code>superman<\/code>, remplacez <code>&lt;account&gt;<\/code> par <code>superman<\/code>)<br>\n<\/p><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><em>Create React App<\/em>, c\u2019est&nbsp;quoi&nbsp;?<\/h2>\n\n\n\n<p>Que vous ayez manqu\u00e9 les derni\u00e8res ann\u00e9es du d\u00e9veloppement <em>front-end<\/em>, ou que vous soyez un peu perdu dans vos premiers pas avec <em>React<\/em>, petit rappel&nbsp;: <strong>React<\/strong> est un framework <em>JS\/TypeScript<\/em> qui vous offre un environnement de d\u00e9veloppement pour vos sites et applications Web. J\u2019insiste sur la partie <em>front-end<\/em> du sujet&nbsp;: m\u00eame s\u2019il est possible d\u2019utiliser <em>React<\/em> avec une partie de rendu c\u00f4t\u00e9 serveur, son cas d\u2019usage premier est bien de g\u00e9n\u00e9rer des <em>assets front<\/em>&nbsp;: <em>HTML<\/em>, <em>CSS<\/em>, <em>JavaScript<\/em>. Rien de&nbsp;plus.<\/p>\n\n\n\n<p>Puisqu\u2019une app <em>React<\/em> n\u2019est qu\u2019un ensemble de fichiers statiques, pas besoin d\u2019avoir une architecture <em>backend<\/em> complexe pour servir votre <em>front-end<\/em>. Ni serveur <em>Node.js<\/em>, ni rien. Un simple serveur Web HTTP&nbsp;suffit. Comme l\u2019indique la <a href=\"https:\/\/create-react-app.dev\/docs\/deployment\/\">documentation de d\u00e9ploiement de <em>Create React App<\/em><\/a>&nbsp;:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Set up your favorite HTTP server so that a&nbsp;visitor to your site is served <code>index.html<\/code>, and requests to static paths like <code>\/static\/js\/main.&lt;hash&gt;.js<\/code> are served with the contents of the <code>\/static\/js\/main.&lt;hash&gt;.js<\/code> file.<\/p>\n<\/blockquote>\n\n\n\n<p>J\u2019en profite pour ajouter un mot sur <em>Create React App<\/em>. Si <em>React<\/em> est un framework d\u00e9di\u00e9 \u00e0&nbsp;la conception d\u2019applications Web, la mise en place de tout son <em>tooling<\/em> peut s\u2019av\u00e9rer complexe. Des outils encaspulant toute cette logique sont donc apparus pour vous faciliter les choses.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Le dev vs. la&nbsp;prod<\/h2>\n\n\n\n<p>Commen\u00e7ons notre tutoriel en cr\u00e9ant une nouvelle application bas\u00e9e sur <em>React<\/em> en utilisant <em>Create React App<\/em>. Dans votre environnement local, lancez la commande&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:sh\"><code>$ npx create-react-app my-app\n$ cd my-app<\/code><\/pre>\n\n\n\n<p>F\u00e9licitations, voici votre premi\u00e8re application <em>React<\/em> fonctionnelle (et sans avoir cod\u00e9 quoi que ce soit !). <em>Create React App<\/em> a&nbsp;g\u00e9n\u00e9r\u00e9 les fichiers de base, et install\u00e9 les diff\u00e9rents modules n\u00e9cessaires au d\u00e9veloppement et \u00e0&nbsp;la compilation de votre projet.<\/p>\n\n\n\n<p>La compilation&nbsp;? Eh oui&nbsp;! Votre application <em>front<\/em> ne va pas \u00eatre directement servie \u00e0&nbsp;vos clients, mais va devoir \u00eatre transpil\u00e9e vers JavaScript. <em>Create React App<\/em> a&nbsp;dot\u00e9 votre projet de deux commandes&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>npm start<\/code>&nbsp;: c\u2019est votre commande en mode d\u00e9veloppement&nbsp;; elle va lancer un serveur web sur votre machine pour vous permettre de travailler sur votre application confortablement (avec du <em>hot-reloading<\/em>, etc.) ;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>npm run build<\/code>&nbsp;: c\u2019est la commande d\u00e9di\u00e9e \u00e0&nbsp;la <em>transpilation<\/em>, celle qui va produire les <em>assets<\/em> statiques que vous devrez ensuite d\u00e9ployer c\u00f4t\u00e9 serveur.<\/li>\n<\/ul>\n\n\n\n<p>C\u00f4t\u00e9 serveur \u00e0&nbsp;pr\u00e9sent&nbsp;: dans votre interface d\u2019administration <em>alwaysdata<\/em>, cr\u00e9ez un nouveau site de type <strong>Fichiers statiques<\/strong>, avec les informations suivantes&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>adresse&nbsp;: <code>&lt;account&gt;.alwaysdata.net\/my-app<\/code><\/li>\n\n\n\n<li>r\u00e9pertoire de travail&nbsp;: \/<code>www\/my-app\/build<\/code><\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-statique.png\"><img decoding=\"async\" src=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-statique-1024x879.png\" alt class=\"wp-image-3743\" width=\"725\" height=\"659\"><\/a><figcaption class=\"wp-element-caption\">Cr\u00e9ation du site \u00ab&nbsp;Fichiers statiques&nbsp;\u00bb<\/figcaption><\/figure><\/div>\n\n\n<p>Comme ce r\u00e9pertoire n\u2019existe pas encore, cr\u00e9ez-le depuis votre environnement local via <em>SSH<\/em>&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:sh\"><code>$ ssh &lt;account&gt;@ssh-&lt;account&gt;.alwaysdata.net mkdir -p www\/my-app\/build<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">D\u00e9ploiement manuel&nbsp;: l\u2019option simple et rapide<\/h2>\n\n\n\n<p>Tout est pr\u00eat c\u00f4t\u00e9 serveur pour recevoir votre site <em>React<\/em>&nbsp;!&nbsp;En-avant pour le d\u00e9ploiement.<\/p>\n\n\n\n<p>Vous devez d\u2019abord indiquer l\u2019<em>URL<\/em>&nbsp;final de votre projet dans le fichier <code>package.json<\/code> pour permettre \u00e0&nbsp;la t\u00e2che de <em>build<\/em> de g\u00e9n\u00e9rer les <em>assets<\/em> avec les bons chemins de fichiers. Ajoutez l\u2019entr\u00e9e suivante&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:json\"><code>\"homepage\": \"\/\/&lt;account&gt;.alwaysdata.net\/my-app\"<\/code><\/pre>\n\n\n\n<p>Toujours depuis votre environnement local, lancez la t\u00e2che de <em>build<\/em>&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:sh\"><code>$ npm run build<\/code><\/pre>\n\n\n\n<p>Votre obtenez un r\u00e9pertoire <code>build<\/code> qui contient vos <em>assets<\/em> statiques. Pour les d\u00e9ployer, utilisez <em>rsync<\/em> <em>via<\/em> <em>SSH<\/em>&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:sh\"><code>$ rsync -rz build &lt;account&gt;@ssh-&lt;account&gt;.alwaysdata.net:www\/my-app<\/code><\/pre>\n\n\n\n<p>Vous pouvez vous rendre \u00e0&nbsp;l\u2019adresse de votre site, et admirer la premi\u00e8re mise en prod. de votre application&nbsp;!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">D\u00e9ploiement automatis\u00e9 depuis Github&nbsp;: la solution des&nbsp;pros<\/h2>\n\n\n\n<p>Ce d\u00e9ploiement manuel fonctionne parfaitement, mais il fait reposer la charge sur vos \u00e9paules. \u00c0&nbsp;chaque fois que vous voudrez d\u00e9ployer votre projet, vous devrez lancer la t\u00e2che de <em>build<\/em> puis lancer le d\u00e9ploiement des fichiers <em>via<\/em> <em>rsync\/SSH<\/em>.<\/p>\n\n\n\n<p>Entrons dans la partie <em>DevOps<\/em> en automatisant le processus via des <em>Webhooks<\/em> <em>GitHub<\/em>&nbsp;!<\/p>\n\n\n<figure class=\"embed-media__giphy\" style=\"width:65%; padding-bottom:calc(65% * (304 + 12) \/ (540 + 12))\">\n    <video id=\"giphy-${token}\" autoplay loop muted playsinline>\n        <source src=\"https:\/\/media.giphy.com\/media\/xT9DPCU60mRbtGw7Ys\/giphy.mp4\" type=\"video\/mp4\">\n        <img decoding=\"async\" src=\"https:\/\/media.giphy.com\/media\/xT9DPCU60mRbtGw7Ys\/giphy.gif\" alt=\"Sponge Bob Thumbs Up @Giphy\">\n    <\/video>\n<\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><em>Webhooks<\/em>, le lien automagique<\/h3>\n\n\n\n<p>Avec les <em>webhooks<\/em>, c\u2019est d\u00e9sormais <em>GitHub<\/em> qui va pr\u00e9venir votre site qu\u2019une nouvelle version est disponible chaque fois que vous pousserez de nouveaux <em>commit<\/em>s sur la branche <code>main<\/code> principale.<\/p>\n\n\n\n<p>Pour \u00e7a, il va falloir doter votre compte <em>alwaysdata<\/em> d\u2019un service de <em>webhooks<\/em> qui ex\u00e9cutera la t\u00e2che de d\u00e9ploiement \u00e0&nbsp;votre place. Le projet <a href=\"https:\/\/github.com\/adnanh\/webhook\/\" target=\"_blank\" rel=\"noreferrer noopener\">adnanh\/webhook<\/a> fera tr\u00e8s bien l\u2019affaire. Connectez-vous sur votre compte via <em>SSH<\/em> et installez-le&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:sh\"><code>$ mkdir webhook\n$ wget -O- https:\/\/github.com\/adnanh\/webhook\/releases\/download\/2.8.0\/webhook-linux-amd64.tar.gz \\\n  | tar -xz --strip-components=1 -C webhook<\/code><\/pre>\n\n\n\n<p>Cr\u00e9ez ensuite un nouveau site dans votre interface d\u2019administration <em>alwaysdata<\/em> de type <strong>Programme utilisateur<\/strong> avec les informations suivantes&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>adresse&nbsp;: <code>&lt;account&gt;.alwaysdata.net\/webhook<\/code><\/li>\n\n\n\n<li>r\u00e9pertoire de travail&nbsp;: <code>webhook<\/code><\/li>\n\n\n\n<li>commande \u00e0&nbsp;ex\u00e9cuter&nbsp;: <code>.\/webhook -port $PORT -hooks .\/hooks.yaml -logfile webhook.log<\/code><\/li>\n\n\n\n<li>pensez \u00e9galement \u00e0&nbsp;cocher les cases <em>Forcer le HTTPS<\/em> et <em>Exclure le chemin<\/em>.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-utilisateur.png\"><img decoding=\"async\" src=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-utilisateur-967x1024.png\" alt class=\"wp-image-3749\" width=\"725\" height=\"768\" srcset=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-utilisateur-967x1024.png 967w, https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-utilisateur-283x300.png 283w, https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-utilisateur-768x813.png 768w, https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_creation-site-utilisateur.png 1170w\" sizes=\"(max-width: 725px) 100vw, 725px\"><\/a><figcaption class=\"wp-element-caption\">Cr\u00e9ation du site \u00ab&nbsp;Programme utilisateur&nbsp;\u00bb<\/figcaption><\/figure><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_forcer-ssl-site.png\"><img decoding=\"async\" src=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_forcer-ssl-site-1024x186.png\" alt class=\"wp-image-3751\" width=\"725\" height=\"140\"><\/a><figcaption class=\"wp-element-caption\">Forcer le SSL\/HTTPS<\/figcaption><\/figure><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_trim-path-site.png\"><img decoding=\"async\" src=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/fr_trim-path-site-1024x281.png\" alt class=\"wp-image-3753\" width=\"725\" height=\"211\"><\/a><figcaption class=\"wp-element-caption\">Exclure le chemin<\/figcaption><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\"><em>GitHub<\/em>, le Central Perk<\/h3>\n\n\n\n<p>C\u00f4t\u00e9 <em>GitHub<\/em> \u00e0&nbsp;pr\u00e9sent, nous allons configurer un nouveau d\u00e9p\u00f4t pour notre projet. <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/new\" target=\"_blank\">Cr\u00e9ez-le comme d\u2019habitude<\/a> en lui donnant le nom de votre projet.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-create-repo.png\"><img decoding=\"async\" width=\"725\" height=\"845\" src=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-create-repo.png\" alt class=\"wp-image-3755\" srcset=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-create-repo.png 725w, https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-create-repo-257x300.png 257w\" sizes=\"(max-width: 725px) 100vw, 725px\"><\/a><figcaption class=\"wp-element-caption\">Cr\u00e9ation d\u2019un d\u00e9p\u00f4t GitHub \u00ab&nbsp;my-app&nbsp;\u00bb<\/figcaption><\/figure><\/div>\n\n\n<p>Puis rendez-vous dans la partie <em>Settings<\/em> pour ajouter un nouveau <em>webhook<\/em> vers votre serveur&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>payload URL&nbsp;: <code>https:\/\/&lt;account&gt;.alwaysdata.net\/webhook\/hooks\/deploy<\/code><\/li>\n\n\n\n<li>secret&nbsp;: <em>un mot de passe al\u00e9atoire<\/em><\/li>\n\n\n\n<li>content-type&nbsp;: <code>application\/json<\/code><\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-add-webhook.png\"><img decoding=\"async\" src=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-add-webhook-1024x701.png\" alt class=\"wp-image-3757\" width=\"725\" srcset=\"https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-add-webhook-1024x701.png 1024w, https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-add-webhook-300x205.png 300w, https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-add-webhook-768x526.png 768w, https:\/\/blog.alwaysdata.com\/wp-content\/uploads\/2023\/01\/en_github-add-webhook.png 1110w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/a><figcaption class=\"wp-element-caption\">Ajout d\u2019un webhook dans le d\u00e9p\u00f4t GitHub<\/figcaption><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Nono, le petit&nbsp;robot<\/h3>\n\n\n\n<p>Notre d\u00e9p\u00f4t <em>GitHub<\/em> est configur\u00e9, il va maintenant d\u00e9clencher des requ\u00eates vers votre serveur <em>webhooks<\/em> lors de nouveaux \u00e9v\u00e8nements, comme les <code>git push<\/code>. Il ne nous reste plus qu\u2019\u00e0 automatiser le d\u00e9ploiement.<\/p>\n\n\n\n<p>Connectez-vous en <em>SSH<\/em> et cr\u00e9ez le fichier <code>webhook\/hooks.yaml<\/code> pour configurer vos <em>webhooks<\/em>  :<\/p>\n\n\n\n<pre class=\"wp-block-code lang:yaml\"><code>- id: deploy\n  execute-command: \/home\/&lt;account&gt;\/webhook\/deploy.sh\n  command-working-directory: \/home\/&lt;account&gt;\n  pass-arguments-to-command:\n    - source: payload\n      name: repository.name\n    - source: payload\n      name: repository.clone_url\n    - source: payload\n      name: head_commit.id\n  trigger-rule:\n    and:\n      - match:\n          type: payload-hmac-sha1\n          secret: &lt;github_webhook_secret&gt;\n          parameter:\n            source: header\n            name: X-Hub-Signature\n      - match:\n          type: value\n          value: refs\/heads\/main\n          parameter:\n            source: payload\n            name: ref<\/code><\/pre>\n\n\n\n<p><em>Note<\/em>&nbsp;: pensez \u00e0&nbsp;remplacer les valeurs de <code>&lt;account&gt;<\/code> et de <code>&lt;github_webhook_secret&gt;<\/code> dans cette configuration, puis \u00e0&nbsp;<a href=\"https:\/\/admin.alwaysdata.com\/site\/\">red\u00e9marrer le site <em>webhook<\/em><\/a> dans l\u2019interface d\u2019aministration une fois termin\u00e9.<\/p>\n\n\n\n<p>Ce <em>webhook<\/em> <code>deploy<\/code> d\u00e9finit l\u2019action \u00e0&nbsp;ex\u00e9cuter lors d\u2019une notification <em>GitHub<\/em>. Il va appeler le script <code>webhook\/deploy.sh<\/code> avec plusieurs param\u00e8tres, uniquement quand il s\u2019agit d\u2019un <em>push<\/em> sur la branche <code>main<\/code>.<\/p>\n\n\n\n<p>Il ne manque plus que le script de d\u00e9ploiement proprement-dit, celui qui sera ex\u00e9cut\u00e9 par le serveur de <em>webhooks<\/em> lors de la notification. Il aura les t\u00e2ches suivantes \u00e0&nbsp;r\u00e9aliser&nbsp;:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Cloner le repository dans un r\u00e9pertoire temporaire&nbsp;;<\/li>\n\n\n\n<li>R\u00e9cup\u00e9rer la derni\u00e8re version indiqu\u00e9e par <em>GitHub<\/em> dans sa notification&nbsp;;<\/li>\n\n\n\n<li>R\u00e9aliser la t\u00e2che de <em>build<\/em>&nbsp;;<\/li>\n\n\n\n<li>Tout nettoyer derri\u00e8re-lui.<\/li>\n<\/ol>\n\n\n\n<p>Toujours via <em>SSH<\/em>, ajoutez le script <code>webhook\/deploy.sh<\/code> sur votre compte serveur&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:sh\"><code>#!\/bin\/bash\n\nNAME=$1\nURL=$2\nCOMMIT=$3\n\nCLONE_DIR=$(mktemp -d)\nDEST_DIR=${HOME}\/www\/${NAME}\n\nmkdir -p ${DEST_DIR}\n\ngit clone --bare ${URL} ${CLONE_DIR}\ngit --work-tree ${DEST_DIR} --git-dir=${CLONE_DIR} checkout --force ${COMMIT}\nnpm --prefix=${DEST_DIR} install\nnpm --prefix=${DEST_DIR} run build\nrm -rf ${CLONE_DIR}<\/code><\/pre>\n\n\n\n<p><em>Note<\/em>&nbsp;: pensez \u00e0&nbsp;rendre le fichier ex\u00e9cutable avec la commande <code>chmod +x webhook\/deploy.sh<\/code>.<\/p>\n\n\n\n<p>Vous y&nbsp;\u00eates&nbsp;! Plus qu\u2019\u00e0 laisser l\u2019ensemble se d\u00e9rouler. Retournez dans votre environnement local, et ajoutez le d\u00e9p\u00f4t <em>GitHub<\/em> \u00e0&nbsp;votre projet avant de pousser la branche principale&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code lang:sh\"><code>$ git remote add origin https:\/\/github.com\/&lt;gh_name&gt;\/my-app.git\n$ git push -u origin main<\/code><\/pre>\n\n\n\n<p>Ce push va d\u00e9clencher la notification via les <em>webhooks<\/em>&nbsp;; le serveur c\u00f4t\u00e9 <em>alwaysdata<\/em>, une fois pr\u00e9venu, va d\u00e9rouler le script de d\u00e9ploiement, et votre site sera mis \u00e0&nbsp;jour. Vous pouvez v\u00e9rifier le bon d\u00e9roulement en consultant c\u00f4t\u00e9 serveur le fichier <code>webhook\/webhook.log<\/code>.<\/p>\n\n\n<figure class=\"embed-media__giphy\" style=\"width:65%; padding-bottom:calc(65% * (267 + 12) \/ (400 + 12))\">\n    <video id=\"giphy-${token}\" autoplay loop muted playsinline>\n        <source src=\"https:\/\/media.giphy.com\/media\/6HOkD1pSCne4E\/giphy.mp4\" type=\"video\/mp4\">\n        <img decoding=\"async\" src=\"https:\/\/media.giphy.com\/media\/6HOkD1pSCne4E\/giphy.gif\" alt=\"Happy End Rant Gif @Giphy\">\n    <\/video>\n<\/figure>\n\n\n\n<p>Faites des modifications sur votre site, poussez sur <em>GitHub<\/em>, rechargez votre site \u00e0&nbsp;l\u2019adresse <code>http:\/\/&lt;account&gt;.alwaysdata.net\/my-app<\/code>, et admirez&nbsp;!&nbsp;Vous n\u2019avez plus rien \u00e0&nbsp;faire pour g\u00e9rer vos d\u00e9ploiements.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Le bon <em>PaaS<\/em>, c\u2019est celui qui vous convient<\/h2>\n\n\n\n<p>Pas besoin de solutions comme <em>Netlify<\/em>, <em>Heroku<\/em>, ou autre pour g\u00e9rer la partie <strong>DevOps<\/strong> de vos d\u00e9ploiements. M\u00eame si ces plate-formes proposent de nombreux outils pratiques pour faciliter vos mises en production (comme les d\u00e9ploiements atomiques, etc), rien ne vous contraint \u00e0&nbsp;les utiliser.<\/p>\n\n\n\n<p>Nous avons ici mis en place une solution simple pour automatiser du d\u00e9ploiement d\u2019applications <em>front-end<\/em> statiques sur votre compte <em>alwaysdata<\/em> sans passer par des outils tiers. Notre outil de d\u00e9ploiement \u00e9tant ind\u00e9pendant de l\u2019application en elle-m\u00eame, vous pouvez d\u00e8s maintenant vous en servir pour d\u00e9ployer d\u2019autres projets&nbsp;: dans un autre d\u00e9p\u00f4t <em>GitHub<\/em>, configurez un <em>webhook<\/em> pointant vers le m\u00eame <em>endpoint<\/em> avec le m\u00eame <code>secret<\/code>, et observez vos d\u00e9ploiements se faire seuls dans votre r\u00e9pertoire <code>www<\/code>.<\/p>\n\n\n\n<p>Libre \u00e0&nbsp;vous maintenant d\u2019adapter la solution \u00e0&nbsp;des cas plus complexes, int\u00e9grant des t\u00e2ches de migration, de mise \u00e0&nbsp;jour de bases de donn\u00e9es, de <em>build<\/em> atomique pour pr\u00e9venir les interruptions de services le temps du red\u00e9ploiement\u2026 la liste est longue. \u00c0&nbsp;vos claviers&nbsp;\ud83e\udd13&nbsp;!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ne perdez plus de vue votre d\u00e9ploiement React&nbsp;: automatisez le process, sur n\u2019importe quel h\u00e9bergeur, sans effort&nbsp;!<\/p>\n","protected":false},"author":12,"featured_media":3791,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"wp_typography_post_enhancements_disabled":false,"footnotes":""},"categories":[],"tags":[273,169,266,272],"class_list":["post-3734","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-ci-cd-fr","tag-devops-fr","tag-frontend-fr","tag-react-fr"],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/posts\/3734","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/comments?post=3734"}],"version-history":[{"count":0,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/posts\/3734\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/media\/3791"}],"wp:attachment":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/media?parent=3734"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/categories?post=3734"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/tags?post=3734"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}