器楽的緩怠

fuzzy note次郎

Nixでいい感じのdevShellを使うまで

devShell とは

NixにはdevShellという便利な機能があります。devShellはプロジェクトで定義した依存を読み込んだシェル環境(?)のことで、これを使うとプロジェクトの依存に基づいた、かつグローバルからは隔離され独立した環境を定義できます。

でも

便利そうだから使いたいな〜と思っていたものの、具体的にどうすればいいのかが私には全然わかりませんでした。 そもそもNixはまだ手探り状態だし、調べたら nix-shell とか nix develop とか色々出てくるし、いざnix develop してみたら bash しか立ち上がらないし...

devShellを実用するには、せめて普段使っているシェルの環境のままで使えるようにしたいですよね。 依然としてNixのことは全然わかっていませんが、devShellがいい感じに使える方法にたどり着いたのでその方法を記しておこうと思います。

Nixまわりはいろんな情報が散らばりまくっていてしんどいので、「こうしたほうがいいですよ〜」とか、「これ読むといいですよ〜」とかがあればぜひ教えてください。

こうすれば動く

次のようにやってみたらいい感じになりました。以下でそれぞれ説明していきます。

  1. direnv をインストールする
  2. プロジェクトに flake.nix を作り、依存・devShell を定義する
  3. devShell を立ち上げたいプロジェクトでuse flake と記した .envrc を用意する

direnv をインストールする

direnv は、環境ごとに読み込む環境変数などをいい感じにやってくれるツールです。 私はhome-managerでインストールしました:

{
  programs.direnv = {
    enable = true;
    nix-direnv.enable = true;
  };
}

プロジェクトに flake.nix を作り、依存やdevShell を定義する

対象となるプロジェクトにてflake.nixを作り、依存を定義しておきます。 たとえばNode.jsを扱うプロジェクトだと、flake.nixは次のようになります。

flake.nix

{
  description = "...";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = {nixpkgs, flake-utils, ...}:
    let
      utils = flake-utils;
    in
    utils.lib.eachDefaultSystem(system:
      let 
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        formatter = pkgs.nixpkgs-fmt;

        devShell = pkgs.mkShell {
          nativeBuildInputs = with pkgs; [
            nodejs-slim_20
            corepack_20
            yarn
          ];
        };
      }
    );
}

devShell を立ち上げたいプロジェクトでuse flake と記した .envrc を用意する

echo "use flake" > .envrc

すると

この設定ができると、cd でプロジェクトのディレクトリに入るだけでdevShellに定義した依存がactivateされ使えるようになり、シェルもzshのまま使えます。

番外編

devShellを用いた開発を運用するにあたり、次のような設定も行いました。

gitignore

グローバルで.direnv/.envrcをignoreするようにしました。

{
  programs.git = {
    # ...
    ignores = [ ".envrc" ".direnv/" ];
  };
}

VSCode

ファイルエクスプローラ及びファイル検索において、.direnvの内容を表示しないようにしました。

settings.json

{
    "files.exclude": {
        "**/.direnv": true
    },
    "search.exclude": {
        "**/.direnv": true
    }
}

おわりに

Nixは情報がいろんな場所に散らばっていて大変だと思いました。アドバイス等あればぜひ教えてください!!!