refactor: delegate webapp build to flake.lib.mkWebapp
Drops the local stdenv.mkDerivation + fetchPnpmDeps in favor of calling the webapp flake's own lib.mkWebapp (added in aiolabs/webapp#97). The hub build now runs through the same builder as the per-standalone builds in server-deploy, which means ONE pnpmDepsHash lives in webapp's flake.nix and no other repo carries one. Options changed: - ADDED flake (required): the webapp flake input. Server-deploy hosts pin this to inputs.webapp (main) or inputs.webapp-dev (staging channel). - ADDED brandDir: path to the brand kit. Defaults to the flake's committed aiolabs default. Override for per-host branding (logo, manifest name, theme colors). - REMOVED src: replaced by flake (which carries the source). - REMOVED gitUrl, gitRef: replaced by flake input ref selection. - REMOVED pnpmDepsHash: managed inside webapp's flake.nix now. - REMOVED appName: per #99/#100's strict policy, VITE_APP_NAME is brand-controlled. Custom names flow through brandDir + brand.json, not env vars. Hosts that today set appName must either accept the default brand's name or supply a per-host brandDir. Other options (nostrRelays, lnbitsBaseUrl, hubXUrl, …) flow into the build via lib.mkWebapp's extraEnv. nginx root moves from \$out/share/webapp to \$out/dist (lib.mkWebapp's output layout). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9d82016399
commit
fe13f3b283
1 changed files with 71 additions and 144 deletions
163
webapp.nix
163
webapp.nix
|
|
@ -1,72 +1,44 @@
|
|||
# NixOS module for building and serving the Vue 3 webapp
|
||||
# NixOS module for serving the Vue 3 webapp.
|
||||
#
|
||||
# Build is delegated to the webapp flake's lib.mkWebapp (since
|
||||
# aiolabs/webapp#97). This module owns:
|
||||
# - the nginx vhost
|
||||
# - the per-deployment VITE_* env vars (relays, LNbits URL, hub
|
||||
# tile URLs, …) that get baked into the bundle
|
||||
# - brand kit selection via `brandDir`
|
||||
#
|
||||
# Per-deployment name customization flows through brand.json under
|
||||
# `brandDir`, NOT through a `VITE_APP_NAME` knob — see strict policy
|
||||
# landed in aiolabs/webapp#99 / #100.
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.webapp;
|
||||
|
||||
# Build the Vue 3 webapp using stdenv + pnpm.configHook
|
||||
webapp = pkgs.stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "aio-webapp";
|
||||
version = "1.0.0";
|
||||
|
||||
# Use src option if provided (flake input), otherwise fetch from git
|
||||
src = if cfg.src != null then cfg.src else builtins.fetchGit {
|
||||
url = cfg.gitUrl;
|
||||
ref = cfg.gitRef;
|
||||
};
|
||||
|
||||
# Fixed-output derivation of the pnpm offline store.
|
||||
# On first build / lockfile change, set hash = lib.fakeHash and rebuild;
|
||||
# Nix will report the correct hash to substitute.
|
||||
pnpmDeps = pkgs.fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
hash = cfg.pnpmDepsHash;
|
||||
fetcherVersion = 3;
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ pkgs.nodejs_20 pkgs.pnpm pkgs.pnpmConfigHook ];
|
||||
|
||||
# Skip Electron binary download (we're building a web app, not desktop)
|
||||
webapp = cfg.flake.lib.mkWebapp {
|
||||
inherit pkgs;
|
||||
brandDir = cfg.brandDir;
|
||||
extraEnv = {
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
|
||||
NODE_ENV = "production";
|
||||
|
||||
# Environment variables for Vite build (VITE_* are embedded at build time)
|
||||
# App Configuration
|
||||
VITE_APP_NAME = cfg.appName;
|
||||
|
||||
# Nostr Configuration
|
||||
VITE_NOSTR_RELAYS = builtins.toJSON cfg.nostrRelays;
|
||||
VITE_ADMIN_PUBKEYS = builtins.toJSON cfg.adminPubkeys;
|
||||
|
||||
# API Configuration
|
||||
VITE_LNBITS_BASE_URL = cfg.lnbitsBaseUrl;
|
||||
VITE_LNBITS_DEBUG = if cfg.lnbitsDebug then "true" else "false";
|
||||
VITE_WEBSOCKET_ENABLED = if cfg.websocketEnabled then "true" else "false";
|
||||
VITE_LNBITS_NOSTR_TRANSPORT_PUBKEY = cfg.lnbitsNostrTransportPubkey;
|
||||
VITE_WEBSOCKET_ENABLED = if cfg.websocketEnabled then "true" else "false";
|
||||
|
||||
# Lightning Address Domain
|
||||
VITE_LIGHTNING_DOMAIN = cfg.lightningDomain;
|
||||
|
||||
# Push Notifications
|
||||
VITE_VAPID_PUBLIC_KEY = cfg.vapidPublicKey;
|
||||
VITE_PUSH_NOTIFICATIONS_ENABLED = if cfg.pushNotificationsEnabled then "true" else "false";
|
||||
|
||||
# Image Upload Configuration (pict-rs)
|
||||
VITE_PICTRS_BASE_URL = cfg.pictrsBaseUrl;
|
||||
|
||||
# Market Configuration
|
||||
VITE_MARKET_NADDR = cfg.marketNaddr;
|
||||
|
||||
# Demo Mode
|
||||
VITE_DEMO_MODE = if cfg.demoMode then "true" else "false";
|
||||
|
||||
# Hub → standalone navigation URLs.
|
||||
# The chakra tiles in src/pages/Hub.vue build <a href> from these. With
|
||||
# path-mode deployment, set these to canonical trailing-slash URLs:
|
||||
# hubMarketUrl = "https://demo.example.com/market/";
|
||||
# With subdomain deployment:
|
||||
# hubMarketUrl = "https://market.example.com";
|
||||
# When unset (empty string), the corresponding chakra renders ghosted
|
||||
# (non-link) — useful for hosts that don't deploy a given module.
|
||||
VITE_HUB_EVENTS_URL = cfg.hubEventsUrl;
|
||||
VITE_HUB_LIBRA_URL = cfg.hubLibraUrl;
|
||||
VITE_HUB_WALLET_URL = cfg.hubWalletUrl;
|
||||
|
|
@ -75,60 +47,35 @@ let
|
|||
VITE_HUB_MARKET_URL = cfg.hubMarketUrl;
|
||||
VITE_HUB_TASKS_URL = cfg.hubTasksUrl;
|
||||
VITE_HUB_RESTAURANT_URL = cfg.hubRestaurantUrl;
|
||||
|
||||
# Additional env vars
|
||||
NODE_ENV = "production";
|
||||
|
||||
# pnpm.configHook sets up the offline store and runs
|
||||
# `pnpm install --offline --frozen-lockfile` before buildPhase.
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
pnpm run build
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
# Install the built static files (Vite outputs to ./dist)
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/share/webapp
|
||||
cp -r dist/* $out/share/webapp/
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
# Don't run pnpm test
|
||||
doCheck = false;
|
||||
|
||||
meta = with lib; {
|
||||
description = "AIO Community Hub - Vue 3 webapp";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
in {
|
||||
options.services.webapp = {
|
||||
enable = lib.mkEnableOption "AIO webapp";
|
||||
|
||||
src = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
flake = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
example = lib.literalExpression "inputs.webapp";
|
||||
description = ''
|
||||
Source tree for the webapp. When set, this is used directly instead of
|
||||
fetching via builtins.fetchGit. Use this with flake inputs for pure evaluation.
|
||||
The webapp flake (as a flake input, not raw source). The module
|
||||
calls `flake.lib.mkWebapp` to build. Pin per-host to pick the
|
||||
right channel — `inputs.webapp` for main, `inputs.webapp-dev`
|
||||
for the dev/staging channel.
|
||||
'';
|
||||
};
|
||||
|
||||
gitUrl = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "https://git.atitlan.io/aiolabs/webapp";
|
||||
description = "Git repository URL for the webapp source";
|
||||
};
|
||||
|
||||
gitRef = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "main";
|
||||
example = "demo";
|
||||
description = "Git branch or tag to build from";
|
||||
brandDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "${cfg.flake}/branding/default";
|
||||
defaultText = lib.literalExpression ''"\${cfg.flake}/branding/default"'';
|
||||
description = ''
|
||||
Path to the brand kit directory consumed by the build. Defaults
|
||||
to the webapp flake's committed aiolabs brand. Override to a
|
||||
per-host directory in server-deploy (e.g.
|
||||
`./../branding/cfaun`) for per-host logo + manifest name +
|
||||
theme colors. See `branding/README.md` in the webapp repo.
|
||||
'';
|
||||
};
|
||||
|
||||
domain = lib.mkOption {
|
||||
|
|
@ -137,23 +84,6 @@ in {
|
|||
description = "Domain name for the webapp";
|
||||
};
|
||||
|
||||
pnpmDepsHash = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = lib.fakeHash;
|
||||
description = ''
|
||||
SRI hash of pnpm dependencies fetched from `pnpm-lock.yaml`.
|
||||
Initially set to `lib.fakeHash`; on first build with a new lockfile,
|
||||
Nix will fail with the correct hash to substitute in.
|
||||
'';
|
||||
};
|
||||
|
||||
# App Configuration
|
||||
appName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "MyApp";
|
||||
description = "Application name displayed in the UI";
|
||||
};
|
||||
|
||||
# Nostr Configuration
|
||||
nostrRelays = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
|
|
@ -308,24 +238,21 @@ in {
|
|||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# Nginx virtualHost for webapp (global nginx settings are in config/nginx.nix)
|
||||
# lib.mkWebapp's output layout is `$out/dist/`, not `$out/share/webapp/`,
|
||||
# so the vhost root points directly at dist/.
|
||||
services.nginx.virtualHosts.${cfg.domain} = {
|
||||
# SSL configuration
|
||||
forceSSL = cfg.enableSSL;
|
||||
enableACME = cfg.enableSSL;
|
||||
|
||||
# Serve the built webapp
|
||||
root = "${webapp}/share/webapp";
|
||||
root = "${webapp}/dist";
|
||||
|
||||
locations = {
|
||||
"/" = {
|
||||
# Try files, fallback to index.html for SPA routing.
|
||||
# Everything matching this prefix ultimately serves the SPA
|
||||
# shell (index.html), which must revalidate on every load so
|
||||
# new deploys are picked up without the browser holding a
|
||||
# stale shell pointing at deleted hashed assets. The more-
|
||||
# specific regex location below overrides this for hashed
|
||||
# static assets, which stay immutable.
|
||||
# SPA shell must revalidate on every load so new deploys are
|
||||
# picked up without the browser holding a stale shell pointing
|
||||
# at deleted hashed assets. The more-specific regex location
|
||||
# below overrides this for hashed static assets, which stay
|
||||
# immutable.
|
||||
tryFiles = "$uri $uri/ /index.html";
|
||||
extraConfig = ''
|
||||
add_header Cache-Control "no-cache";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue