--- options: command_prefix: "pr:" theme: name: tokyonight-storm override: default: # colors: # foreground: "4c4f69" # background: "ffffff" palette: colors: base00: "24283B" base01: "16161E" base02: "343A52" base03: "444B6A" base04: "787C99" base05: "A9B1D6" base06: "CBCCD1" base07: "D5D6DB" base08: "C0CAF5" base09: "A9B1D6" base0A: "0DB9D7" base0B: "9ECE6A" base0C: "B4F9F8" base0D: "2AC3DE" base0E: "BB9AF7" base0F: "F7768E" --- # Définition des environnements de développement du package * on défini un seul environnement (**default**) * la fonction **forEachSupportedSystem** à pour fonction de générer un élément pour chaque architecture supportée par le package * ces architectures sont définie à la ligne 8 et correspondent aux architectures supportée par nix. * Dans cet environnement, on fournis les packages suivants * **nodejs** c'est un projet vue.js, donc faut bien un runtime * **yarn** ici on préfèrera yarn pour pouvoir utiliser yarn2nix afin de générer les dépendances. * webstorm * je l'installe que pour ce projet, donc ça me permet de le garbage collecter quand j'en ai pas besoin (merci nix) * **yarn2nix** * yarn2nix est un outil qui vas lire notre fichier package.json et générer un fichier yarn.nix avec toutes nos dépendances packager pour nix, pour des question de reproductibilité, lors du build avec nix, les outils n'ont pas accès à internet, il n'est donc pas possible de juste faire un "yarn add". ```file +line_numbers {13-18} path: shoblog_code.nix language: nix ``` # Définition des packages * d'une manière similaire aux **devShells**, on vas ici générer un package par architecture supportée. Lors du build (qui se fait généralement localement), nix va néanmoins builder uniquement le package correspondant à l'architecture de la machine. * Pour ce faire, on utilise la fonction **mkYarnPackage** qui fournit diverses options pour générer un package manager par **Yarn** * **name**: assez explicite, le nom du package générer * **src**: les source sur lequel la fonction va se baser pour générer le package * **PackageJSON**: package.json * **yarnLock**: yarn.lock * **yarnNix**: Ah ! C'est ici qu'on retrouve notre fameux **yarn.nix**. * En fait, lors du process de build et pour pour des raisons de reproductibilité, les programmes n'ont pas accès à internet. Chez nix, toutes les dépendances doivent être connue et regroupée à l'avance. Pour ce faire, **yarn2nix** nous génère un fichier **yarn.nix** définissant sous forme de package nix toutes les dépendances de notre projet, ainsi lors du build, nix vas toutes les pull, donner le résultat à mkYarnPackage qui vas les installer dans son environnement de build. * Et pour finis, les phases de notre build. Par défaut, **mkYarnPackage** va juste chercher à build un binaire basée sur la configuration de notre package.json, dans notre cas ```file +line_numbers {20-45} path: shoblog_code.nix language: nix ``` ## buildPhase Le build d'un package sous nix est découpé en plusieurs phases, si la plupart sont généralement transparente, celons le cas, certaines ont besoin d'être override en fonction des besoins. Ici, l'on cherche à packager des assets statiques, donc: * première étape, appeler `runhook preBuild`, rien à voir avec notre affaire, mais cela permet à d'éventuel futur dev de venir surcharger notre package sans toucher à notre buildphase, chaque phase à des pré et post hook de la même manière. * `mkdir $TEMPDIR/dist`, on créer un dossier temporaire pour nos fichiers de build * `yarn run build --outDir $TEMPDIR/dist`, on run notre script de build en précisant notre dossier temporaire comme output * et on run le hook de postBuild ```file +line_numbers {29-34} path: shoblog_code.nix language: nix ``` ## installPhase Cette phase a pour rôle de placer les fichiers résultant du build dans le store de nix, je passe sur les hook qu'on à déjà vu précédemment * `mkdir -p $out/`, **$out** est une variable spécifique à cette phase de build qui pointe vers le dossier final attribué par nix pour notre package. * `cp -r $TEMPDIR/dist/ $out/`, on copie les fichiers de notre build dans le dossier ainsi créer et zou ! :3 ```file +line_numbers {36-41} path: shoblog_code.nix language: nix ``` ## Résultat Hop, un petit coup de `nix build` et sous vos yeux ébahis, nix nous pull toutes nos dépendances, build notre projet et le place au chaud dans son store. \ Bon c'est vachement bien tout ça, mais pourquoi faire ? On verra les avantages en détails dans d'autres articles (peut-être même dès demain ? mystère mystère...) mais voici déjà quelques bullet points * Reproductibilité * Nix nous assure que, pour des entrées données, le résultat sera toujours le même, ainsi, il nous est possible de pin un commit spécifique de nixpkgs pour figer la release de notre paquet dans le temps. Contrairement à un package manager plus classique (apt par exemple), lors du build de votre paquet, vous serez ainsi assurer de toujours pull la même version de node tant que l'on update pas le flake.lock du projet. * Isolation * Nix installe chaque dépendance dans un dossier appellé le **store**, chaque dépendance étant installer dans un dossier au hash unique basé sur le nom du package et sa version. Ce qui fait qu'il est parfaitement possible d'avoir deux projets utilisant deux versions de node différentes sans aucun problème, et ce sans avoir besoin de docker, d'environnement virtuel ou de faire mumuse avec des liens symboliques. Bonus, si un autre projet nécessite la même version de node, nix va simplement utiliser celle déjà installer, ce qui évite les duplicatas. * Tracking * étant donné que toutes les dépendances de chaque package sont déclarées dans le `flake.nix`, il suffit de lire ce dernier pour savoir quels paquets sont nécessaires à son déploiement. De plus, si l'on enlève un paquet de l'environnement, nix vas pouvoir checker si ses dépendances sont utiliser par d'autres paquets, et dans la négative, les supprimer pour économiser la place. * Configuration * Un peu hors du scope de cet exemple, mais il est possible de définir une fonction d'override pour un paquet afin de permettre à l'utilisateur final de ce dernier de spécifier des paramètres à ce dernier au moment du build. Que ce sois l'utilisation d'une version spécifique de node, ou une clé d'API par exemple. * en utilisant NixOS, il est possible de définir des **modules** que l'utilisateur peut importer dans la configuration de son système afin de déclarer des services, installer et configurer d'autres packages, configurer des interfaces réseaux, ect... Cela peut permettre d'automatiser grandement le déploiement de certains projets et de grandement organiser ses configurations (comme avec la déclaration de virtualhost nginx par exemple, teasing teasing...)