chore(ops): build with bun and ship v2's .output/standalone
v2 replaces pnpm with bun and moves the standalone build to apps/nextjs/.output/standalone, which already carries static assets, public and next.config.ts. Next still writes an incomplete .next/standalone, so the assembler now refuses to run without the v2 output rather than silently shipping that one. The notes now list v2's registration points, the tests that already fail on the upstream tag, and the one-way v1 to v2 database migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dd5a3c83a8
commit
95df5af7cf
3 files changed
+71
-29
No files matched your search
+49
-15
@@ -24,6 +24,13 @@ Après déploiement, le contrôle qui compte n'est pas que le nouveau widget
|
||||
s'affiche : c'est que les intégrations **préexistantes** fonctionnent encore.
|
||||
C'est la seule preuve que `SECRET_ENCRYPTION_KEY` n'a pas bougé.
|
||||
|
||||
Le premier déploiement d'une v2 sur une base v1 est **à sens unique** : Homarr
|
||||
migre la base au démarrage, et une v1 ne sait plus la lire. Le retour arrière
|
||||
passe alors par la copie `/root/homarr-db-<horodatage>.sqlite` que fait le
|
||||
script, pas par la seule archive de `/opt/homarr`. La v2 change aussi l'échelle
|
||||
des tableaux (cellules fixes de 200 × 200) : les widgets paraîtront plus petits,
|
||||
ce qui se règle avec le nombre de colonnes, pas avec un retour en v1.
|
||||
|
||||
## Déplacer l'état hors de /appdata
|
||||
|
||||
`/appdata` vient de l'image Docker, où c'est un point de montage. Sur une
|
||||
@@ -77,18 +84,47 @@ git rebase v1.78.0 feat/unifi-os-integration # remplace par la version vis
|
||||
|
||||
Puis, dans cet ordre — chaque étape a déjà attrapé quelque chose :
|
||||
|
||||
Depuis la v2, le dépôt se construit avec **bun** et exige un Node récent, aux
|
||||
versions fixées dans `mise.toml` (bun 1.4.2, Node ≥ 24.18). Sur ce poste :
|
||||
|
||||
```bash
|
||||
pnpm install # le lockfile bouge presque à chaque version
|
||||
pnpm turbo typecheck # les 37 paquets
|
||||
pnpm test packages/integrations/ packages/widgets/
|
||||
pnpm test packages/widgets/src/manifest.spec.ts # les points d'enregistrement
|
||||
export PATH="$HOME/.local/share/nvm/v24.21.0/bin:$PATH"
|
||||
npm i -g bun@1.4.2 # une fois, dans le préfixe de ce Node
|
||||
```
|
||||
|
||||
```bash
|
||||
bun install # le lockfile bouge presque à chaque version
|
||||
bun run turbo typecheck # les 38 paquets
|
||||
bun run test packages/integrations/ packages/widgets/ packages/definitions/
|
||||
bun run test packages/widgets/src/manifest.spec.ts # les points d'enregistrement
|
||||
ops/deploy-lxc.sh --dry-run
|
||||
```
|
||||
|
||||
`manifest.spec.ts` mérite sa ligne à part : il compare l'icône du catalogue à
|
||||
celle de la définition **par identité**, et c'est le seul test qui détecte un
|
||||
`manifest.spec.ts` mérite sa ligne à part : c'est le seul test qui détecte un
|
||||
point d'enregistrement perdu dans un conflit.
|
||||
|
||||
Après un passage de pnpm à bun, ou si le typecheck se plaint de deux copies
|
||||
d'une même dépendance, repartir d'un `node_modules` propre : pnpm laissait des
|
||||
copies imbriquées que bun ne nettoie pas.
|
||||
|
||||
#### Les échecs de tests à ne pas confondre avec une régression
|
||||
|
||||
Comparer avec l'étiquette amont, pas avec zéro. Sur v2.3.0, 19 tests échouent
|
||||
déjà sans ce fork (Unifi Controller, widgets Custom JSX, Pi-hole, et
|
||||
`manifest.spec.ts` lui-même, à cause d'une requête Immich absente de
|
||||
`refetch-intervals.ts`). Pour les lister :
|
||||
|
||||
```bash
|
||||
git worktree add /tmp/homarr-amont v2.3.0 && (cd /tmp/homarr-amont && bun install && bun run test packages/)
|
||||
```
|
||||
|
||||
Deux échecs sont propres au fork, et assumés :
|
||||
|
||||
- `api-key-url.spec.ts` exige une page de documentation homarr.dev pour chaque
|
||||
intégration ; les nôtres n'en ont pas (`documentationSlug: null`).
|
||||
- `widget-integration-map.spec.ts` exige que chaque widget accepte l'intégration
|
||||
`mock`, qui ne sert qu'à la galerie de démonstration de l'amont.
|
||||
|
||||
### Où les conflits vont tomber
|
||||
|
||||
Le gros du travail vit dans des dossiers neufs — `packages/integrations/src/unifi-os/`,
|
||||
@@ -101,24 +137,22 @@ ajoute une ligne dans une liste que l'amont fait vivre aussi :
|
||||
| `packages/definitions/src/integration.ts` | les deux genres d'intégration |
|
||||
| `packages/definitions/src/widget.ts` | les deux genres de widget |
|
||||
| `packages/definitions/src/widget-integration-map.ts` | l'association widget ↔ intégration |
|
||||
| `packages/definitions/src/docs/integration-doc-slugs.ts` | les slugs de documentation |
|
||||
| `packages/definitions/src/docs/widget-doc-slugs.ts` | idem, côté widgets |
|
||||
| `packages/integrations/src/base/creator.ts` | la construction des classes |
|
||||
| `packages/definitions/src/docs/widget-doc-slugs.ts` | le slug de documentation des widgets |
|
||||
| `packages/integrations/src/base/creator.ts` | la construction, en import différé |
|
||||
| `packages/integrations/src/index.ts` | les exports |
|
||||
| `packages/integrations/src/types.ts` | les types réexportés **côté client** |
|
||||
| `packages/api/src/router/widgets/index.ts` | les routeurs tRPC |
|
||||
| `packages/widgets/src/manifest.ts` | deux cartes distinctes, module et composant |
|
||||
| `packages/widgets/src/index.tsx` | l'import et l'entrée |
|
||||
| `packages/widgets/src/catalog.ts` | l'icône |
|
||||
| `packages/widgets/src/registry.ts` | quatre entrées : import de type, module, type, composant |
|
||||
| `packages/ui/src/widget-icons.ts` | l'icône |
|
||||
| `packages/widgets/src/refetch-intervals.ts` | l'intervalle de rafraîchissement |
|
||||
| `apps/nextjs/src/components/integration/integration-grid-shared.ts` | le libellé de catégorie |
|
||||
| `packages/ui/src/integration-select-grid/integration-grid-shared.ts` | le libellé de catégorie |
|
||||
| `apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts` | l'icône du secret |
|
||||
| `packages/translation/src/lang/en.json` | tous les libellés |
|
||||
|
||||
Deux de ces lignes ne sont vérifiées par **aucun** compilateur, et les perdre
|
||||
dans un conflit passerait tous les tests :
|
||||
|
||||
- `integration-grid-shared.ts` est typé `Record<string, string>` : une entrée
|
||||
- `integration-grid-shared.ts` (dans `packages/ui` depuis la v2) est typé `Record<string, string>` : une entrée
|
||||
manquante affiche `UNIFISITEMANAGER` en majuscules collées au lieu du nom.
|
||||
- `en.json` n'est pas typé du tout : une clé perdue affiche son chemin brut.
|
||||
|
||||
@@ -144,7 +178,7 @@ liste autour.
|
||||
|
||||
```bash
|
||||
SKIP_ENV_VALIDATION=true CI=true DISABLE_REDIS_LOGS=true \
|
||||
pnpm turbo build --concurrency=1 --filter=@homarr/nextjs... --filter=@homarr/cli
|
||||
bun run turbo run build --concurrency=1 --filter=@homarr/nextjs... --filter=@homarr/cli
|
||||
```
|
||||
|
||||
`SKIP_ENV_VALIDATION` n'est pas optionnel : le build charge `next.config.ts`, qui
|
||||
|
||||
+11
-11
@@ -3,7 +3,7 @@
|
||||
# Assemble l'arborescence d'exécution à partir d'un dépôt déjà construit.
|
||||
#
|
||||
# Le dépôt et l'instance qui tourne n'ont PAS la même forme : le clone contient
|
||||
# des sources et un `apps/nextjs/.next/standalone` ; l'instance attend
|
||||
# des sources et un `apps/nextjs/.output/standalone` ; l'instance attend
|
||||
# `apps/nextjs/server.js`, `db/migrations/`, `build/better_sqlite3.node` à sa
|
||||
# racine. Ce script fait la conversion — les mêmes COPY que le stage `runner`
|
||||
# du Dockerfile officiel, d'où vient la disposition de /opt/homarr.
|
||||
@@ -11,7 +11,7 @@
|
||||
# Usage : ops/assemble-standalone.sh <destination>
|
||||
#
|
||||
# Construire d'abord :
|
||||
# pnpm turbo build --filter=@homarr/nextjs... --filter=@homarr/cli
|
||||
# bun run turbo run build --filter=@homarr/nextjs... --filter=@homarr/cli
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
@@ -20,20 +20,20 @@ REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
cd "$REPO"
|
||||
|
||||
[ -d apps/nextjs/.next/standalone ] || {
|
||||
echo "apps/nextjs/.next/standalone absent — construis d'abord :" >&2
|
||||
echo " pnpm turbo build --filter=@homarr/nextjs... --filter=@homarr/cli" >&2
|
||||
# Depuis la v2, la sortie est .output/standalone. Next écrit encore un
|
||||
# .next/standalone intermédiaire, incomplet : ne jamais le prendre à la place.
|
||||
[ -f apps/nextjs/.output/standalone/apps/nextjs/server.js ] || {
|
||||
echo "apps/nextjs/.output/standalone absent — construis d'abord :" >&2
|
||||
echo " bun run turbo run build --filter=@homarr/nextjs... --filter=@homarr/cli" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$DEST"
|
||||
|
||||
# L'ordre suit le Dockerfile : le standalone d'abord, le reste par-dessus.
|
||||
cp -a apps/nextjs/.next/standalone/. "$DEST/"
|
||||
mkdir -p "$DEST/apps/nextjs/.next"
|
||||
cp -a apps/nextjs/.next/static "$DEST/apps/nextjs/.next/static"
|
||||
cp -a apps/nextjs/public "$DEST/apps/nextjs/public"
|
||||
cp -a apps/nextjs/next.config.ts apps/nextjs/package.json pnpm-workspace.yaml "$DEST/"
|
||||
# L'ordre suit le Dockerfile : le standalone d'abord, le reste par-dessus. En v2,
|
||||
# le standalone embarque déjà .next/static, public, next.config.ts et
|
||||
# package.json — le Dockerfile ne les copie plus à part.
|
||||
cp -a apps/nextjs/.output/standalone/. "$DEST/"
|
||||
|
||||
mkdir -p "$DEST/apps/cli"
|
||||
cp -a packages/cli/cli.cjs "$DEST/apps/cli/cli.cjs"
|
||||
|
||||
+11
-3
@@ -39,11 +39,19 @@ echo "Commit déployé : $(git log --oneline -1)"
|
||||
|
||||
# Le dépôt exige un Node récent (champ engines.node). Le Node par défaut du poste
|
||||
# est plus ancien que ça : sans ce contrôle, l'échec surviendrait au milieu du
|
||||
# build, avec un message de pnpm qui ne dit pas quoi faire.
|
||||
# build, avec un message de bun qui ne dit pas quoi faire.
|
||||
required_node="$(grep -oP '^node = "\K[^"]+' "$REPO/mise.toml" 2>/dev/null || echo '24.18.0')"
|
||||
if ! node -e "process.exit(process.versions.node.localeCompare('$required_node', undefined, { numeric: true }) < 0 ? 1 : 0)"; then
|
||||
echo "Node $(node -v) est trop ancien — il en faut au moins v$required_node." >&2
|
||||
echo "Par exemple : export PATH=\"\$HOME/.local/share/nvm/v24.20.0/bin:\$PATH\"" >&2
|
||||
echo "Par exemple : export PATH=\"\$HOME/.local/share/nvm/v24.21.0/bin:\$PATH\"" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Depuis la v2, le dépôt se construit avec bun (version fixée dans mise.toml).
|
||||
required_bun="$(grep -oP '^bun = "\K[^"]+' "$REPO/mise.toml" 2>/dev/null || echo '1.4.2')"
|
||||
if [ "$(bun --version 2>/dev/null)" != "$required_bun" ]; then
|
||||
echo "bun $required_bun requis (trouvé : $(bun --version 2>/dev/null || echo aucun))." >&2
|
||||
echo "Par exemple : npm i -g bun@$required_bun, avec le Node ci-dessus dans le PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -73,7 +81,7 @@ say "Build"
|
||||
# build valide les variables d'exécution — dont URL, qui n'a aucun sens à la
|
||||
# compilation — et échoue partout où il ne traîne pas un .env à la racine.
|
||||
SKIP_ENV_VALIDATION=true CI=true DISABLE_REDIS_LOGS=true \
|
||||
pnpm turbo build --filter=@homarr/nextjs... --filter=@homarr/cli
|
||||
bun run turbo run build --filter=@homarr/nextjs... --filter=@homarr/cli
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
say "Assemblage de l'arborescence à envoyer"
|
||||
|
||||
Reference in new issue
Block a user