Skip to content

Commit

Permalink
feat(flake): package leptos project in nix
Browse files Browse the repository at this point in the history
  • Loading branch information
johnbchron committed Nov 22, 2024
1 parent e40e6e2 commit 60f654d
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 61 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
use flake
watch_file flake-modules/
12 changes: 10 additions & 2 deletions flake-modules/devshell/default.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
localFlake: { ... }: {
perSystem = { pkgs, rust, inputs', ... }: let
perSystem = { pkgs, rust-toolchain, inputs', ... }: let
mkShell = pkgs.devshell.mkShell;

# note; there's a UTF-8 control character in the esc string below
Expand Down Expand Up @@ -46,7 +46,7 @@ localFlake: { ... }: {
devShells.default = mkShell {
packages = with pkgs; [
# rust dev toolchain (with RA), built from current nixpkgs
(rust.dev-toolchain pkgs)
(rust-toolchain.dev-toolchain pkgs)

# tools
mprocs # runs commands in parallel
Expand Down Expand Up @@ -75,6 +75,14 @@ localFlake: { ... }: {
help = "Runs nix flake checks.";
category = "[nix actions]";
}
{
name = "site-container";
command = ''
docker load -i $(nix build .#site-server-container --print-out-paths --no-link) && \
docker run --rm -p 3000:3000 site-server
'';
help = "Run the ${bin-hl "site-server"} in a container.";
}
]
++ tikv-docker-commands
;
Expand Down
63 changes: 5 additions & 58 deletions flake-modules/rust-builds/default.nix
Original file line number Diff line number Diff line change
@@ -1,59 +1,6 @@
localFlake: { inputs, ... }: {
perSystem = { pkgs, rust, ... }: let
filter = inputs.nix-filter.lib;

# configure the source
src = filter {
root = ../../.; # project root
include = [
"crates" "Cargo.toml" "Cargo.lock" # typical rust source
".cargo" # extra rust config
(filter.matchExt "toml") # extra toml used by other projects
"media" # static assets
];
};

# build arguments for the whole workspace
common-args = {
inherit src;
strictDeps = true;

pname = "picturepro";
version = "0.1";
doCheck = false;

# inputs assumed to be relevant for all crates
nativeBuildInputs = with pkgs; [
pkg-config
];
buildInputs = [ ];
};

# build the deps for the whole workspace
cargoArtifacts = rust.craneLib.buildDepsOnly common-args;


in {
checks = {
# run clippy, denying warnings
rust-cargo-clippy = rust.craneLib.cargoClippy (common-args // {
inherit cargoArtifacts;
cargoClippyExtraArgs = "--all-targets --no-deps -- --deny warnings";
});
# run rust-doc, denying warnings
rust-cargo-docs = rust.craneLib.cargoDoc (common-args // {
inherit cargoArtifacts;
cargoClippyExtraArgs = "--no-deps";
RUSTDOCFLAGS = "-D warnings";
});
# run rust tests with nextest
rust-cargo-nextest = rust.craneLib.cargoNextest (common-args // {
inherit cargoArtifacts;
partitions = 1;
partitionType = "count";
});
# run cargo fmt, failing if not already formatted perfectly
rust-cargo-fmt = rust.craneLib.cargoFmt common-args;
};
};
localFlake: { ... }: {
imports = [
./workspace.nix
./leptos.nix
];
}
127 changes: 127 additions & 0 deletions flake-modules/rust-builds/leptos.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{ inputs, ... }: {
perSystem = { pkgs, rust-toolchain, rust-workspace, system, ... }: let
inherit (rust-workspace.workspace-base-args) src;
inherit (rust-toolchain) craneLib;

workspace-cargo-manifest = builtins.fromTOML (builtins.readFile ../../Cargo.toml);
leptos-options = builtins.elemAt workspace-cargo-manifest.workspace.metadata.leptos 0;

js2nix = pkgs.callPackage (pkgs.fetchgit {
url = "https://github.com/canva-public/js2nix";
hash = "sha256-Bmv0ERVeb6vjYzy4MuCDgSiz9fSm/Bhg+Xk3AxPisBw=";
}) { };
style-root = ../../crates/site-app/style/tailwind;

style-node-env = (js2nix {
package-json = style-root + "/package.json";
yarn-lock = style-root + "/yarn.lock";
}).nodeModules;

common-args = {
inherit src;
pname = leptos-options.bin-package;
version = "0.1.0";

doCheck = false;

nativeBuildInputs = [
pkgs.pkg-config
pkgs.binaryen # provides wasm-opt for cargo-leptos
] ++ pkgs.lib.optionals (system == "x86_64-linux") [
pkgs.nasm # wasm compiler only for x86_64-linux
];
buildInputs = [
];
};
# build the deps for the frontend bundle, and export the target folder
site-frontend-deps = craneLib.mkCargoDerivation (common-args // {
pname = "site-frontend-deps";
src = craneLib.mkDummySrc common-args;
cargoArtifacts = null;
doInstallCargoArtifacts = true;

buildPhaseCargoCommand = ''
cargo build \
--package=${leptos-options.lib-package} \
--lib \
--target-dir=/build/source/target/front \
--target=wasm32-unknown-unknown \
--no-default-features \
--profile=${leptos-options.lib-profile-release}
'';
});
# build the deps for the server binary, and export the target folder
site-server-deps = craneLib.mkCargoDerivation (common-args // {
pname = "site-server-deps";
src = craneLib.mkDummySrc common-args;
cargoArtifacts = site-frontend-deps;
doInstallCargoArtifacts = true;

buildPhaseCargoCommand = ''
cargo build \
--package=${leptos-options.bin-package} \
--no-default-features \
--release
'';
});

# build the binary and bundle using cargo leptos
site-server = craneLib.buildPackage (common-args // {
# add inputs needed for leptos build
nativeBuildInputs = common-args.nativeBuildInputs ++ (with pkgs; [
cargo-leptos dart-sass tailwindcss
]);

# link the style packages node_modules into the build directory
preBuild = ''
ln -s ${style-node-env} \
./crates/site-app/style/tailwind/node_modules
'';

# enable hash_files again
buildPhaseCargoCommand = ''
LEPTOS_HASH_FILES=true cargo leptos build --release -vvv
'';

installPhaseCommand = ''
mkdir -p $out/bin
cp target/release/site-server $out/bin/
cp target/release/hash.txt $out/bin/
cp -r target/site $out/bin/
'';

doCheck = false;
cargoArtifacts = site-server-deps;
});

site-server-container = pkgs.dockerTools.buildLayeredImage {
name = leptos-options.bin-package;
tag = "latest";
contents = [ site-server pkgs.cacert ];
config = {
# runs the executable with tini: https://github.com/krallin/tini
# this does signal forwarding and zombie process reaping
# this should be removed if using something like firecracker (i.e. on fly.io)
Entrypoint = [ "${pkgs.tini}/bin/tini" "site-server" "--" ];
WorkingDir = "${site-server}/bin";
# we provide the env variables that we get from Cargo.toml during development
# these can be overridden when the container is run, but defaults are needed
Env = [
"LEPTOS_OUTPUT_NAME=${leptos-options.name}"
"LEPTOS_SITE_ROOT=${leptos-options.name}"
"LEPTOS_SITE_PKG_DIR=${leptos-options.site-pkg-dir}"
"LEPTOS_SITE_ADDR=0.0.0.0:3000"
"LEPTOS_RELOAD_PORT=${builtins.toString leptos-options.reload-port}"
"LEPTOS_ENV=PROD"
# https://github.com/leptos-rs/cargo-leptos/issues/271
"LEPTOS_HASH_FILES=true"
];
};
};
in {
packages = {
site-server = site-server;
site-server-container = site-server-container;
};
};
}
61 changes: 61 additions & 0 deletions flake-modules/rust-builds/workspace.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{ inputs, ... }: {
perSystem = { pkgs, rust-toolchain, ... }: let
filter = inputs.nix-filter.lib;

# configure the source
src = filter {
root = ../../.; # project root
include = [
"crates" "Cargo.toml" "Cargo.lock" # typical rust source
".cargo" # extra rust config
(filter.matchExt "toml") # extra toml used by other projects
"media" # static assets
];
};

# build arguments for the whole workspace
workspace-base-args = {
inherit src;
strictDeps = true;

pname = "picturepro";
version = "0.1";
doCheck = false;

# inputs assumed to be relevant for all crates
nativeBuildInputs = with pkgs; [
pkg-config
];
buildInputs = [ ];
};

# build the deps for the whole workspace
workspace-base-cargo-artifacts = rust-toolchain.craneLib.buildDepsOnly workspace-base-args;
in {
# pass back to the flake
config._module.args.rust-workspace = {
inherit workspace-base-args workspace-base-cargo-artifacts;
};
config.checks = {
# run clippy, denying warnings
rust-cargo-clippy = rust-toolchain.craneLib.cargoClippy (workspace-base-args // {
cargoArtifacts = workspace-base-cargo-artifacts;
cargoClippyExtraArgs = "--all-targets --no-deps -- --deny warnings";
});
# run rust-doc, denying warnings
rust-cargo-docs = rust-toolchain.craneLib.cargoDoc (workspace-base-args // {
cargoArtifacts = workspace-base-cargo-artifacts;
cargoClippyExtraArgs = "--no-deps";
RUSTDOCFLAGS = "-D warnings";
});
# run rust tests with nextest
rust-cargo-nextest = rust-toolchain.craneLib.cargoNextest (workspace-base-args // {
cargoArtifacts = workspace-base-cargo-artifacts;
partitions = 1;
partitionType = "count";
});
# run cargo fmt, failing if not already formatted perfectly
rust-cargo-fmt = rust-toolchain.craneLib.cargoFmt workspace-base-args;
};
};
}
3 changes: 2 additions & 1 deletion flake-modules/rust-toolchain/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ localFlake: { inputs, ... }: {
# build the CI and dev toolchains
toolchain = p: p.rust-bin.selectLatestNightlyWith (toolchain: toolchain.minimal.override {
extensions = [ "rustfmt" "clippy" ];
targets = [ "wasm32-unknown-unknown" ];
});
dev-toolchain = p: p.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override {
extensions = [ "rust-src" "rust-analyzer" ];
Expand All @@ -12,7 +13,7 @@ localFlake: { inputs, ... }: {
# configure crane to use the CI toolchain
craneLib = (inputs.crane.mkLib pkgs).overrideToolchain toolchain;
in {
config._module.args.rust = {
config._module.args.rust-toolchain = {
inherit toolchain dev-toolchain craneLib;
};
};
Expand Down

0 comments on commit 60f654d

Please sign in to comment.