L'étage e2e lance next start, que Next déclare incompatible avec l'output: standalone du gabarit : il n'éprouve pas l'artefact que le Dockerfile déploie #30

Closed
opened 2026-09-17 06:11:55 +00:00 by nicolas-fryder · 1 comment

Ce qui ne va pas

playwright.config.ts du gabarit démarre le serveur sous test par :

webServer: {
  command: 'pnpm --filter web start',
  …
}

et apps/web/package.json fait de start un next start
(node scripts/next.mjs start). Or apps/web/next.config.mjs du même gabarit
pose output: 'standalone', et Next refuse la combinaison — à voix haute, à
chaque exécution :

[WebServer] ⚠ "next start" does not work with "output: standalone" configuration.
            Use "node .next/standalone/server.js" instead.

Le plus petit chemin pour le reproduire

Un clone du gabarit, @eqs/* en 0.11.2 :

pnpm install
pnpm --filter web build
pnpm test:e2e

L'avertissement sort au démarrage du webServer, avant le premier cas. Mesuré
le 2026-09-17 sur un satellite nest monté sur eqs-satellite-template@53e704c
(Node 24.15.0, pnpm 11.8.0, Windows 11) ; les deux fichiers en cause sont ceux
du gabarit, non modifiés.

Deuxième avertissement au même endroit, de la même famille :

[WebServer] ⚠ You are using a non-standard "NODE_ENV" value in your environment.

Ce que ça coûte

Pas bloquant aujourd'hui, et c'est précisément ce qui le rend gênant.
next start sert quand même depuis .next/, la page rend, le cas passe. Deux
conséquences :

  1. L'étage e2e n'éprouve pas ce qui est déployé. Le Dockerfile copie
    .next/standalone et lance server.js ; l'e2e, lui, lance un autre serveur,
    depuis un autre artefact, avec un autre traçage de fichiers
    (outputFileTracingRoot). Un défaut propre au bundle standalone — un fichier
    non tracé, un public/ absent, un chemin de workspace mal résolu — passe
    l'étage e2e en vert et se découvre en production. C'est exactement la classe
    de défauts que 2303777 (« L'étage e2e du gabarit devient vrai ») visait à
    fermer.
  2. Le jour où Next transforme l'avertissement en refus, les trente
    satellites perdent leur étage e2e le même matin, sur un message qui parle de
    configuration Next et pas du gabarit.

Il y a une ironie utile ici : le commentaire de playwright.config.ts dit
« Un étage e2e qui atteste de ce qu'il n'a pas regardé est pire que pas
d'étage » — à propos de reuseExistingServer. Le même raisonnement s'applique à
l'artefact servi.

Ce que je proposerais

Faire pointer le webServer sur le serveur standalone, celui que l'image
lance :

webServer: {
  command: 'node apps/web/.next/standalone/apps/web/server.js',
  env: { PORT: String(PORT), HOSTNAME: '127.0.0.1' },
  …
}

Avec une réserve mesurée : le serveur standalone ne sert pas .next/static ni
public/ tout seul — le Dockerfile les recopie à côté de lui (étages
web 2/3 et web 3/3). Il faudrait donc soit un petit script qui fait la même
copie avant de lancer (le pendant local des trois COPY), soit assumer que
l'e2e local teste le HTML et laisse les assets à la CI. Un script, plutôt :
c'est ce qui rend l'étage local et l'image comparables, ce qui est tout l'objet
de la demande.

Si cette voie est jugée trop lourde pour ce que le gabarit doit livrer, l'autre
réponse honnête est de l'écrire dans playwright.config.ts : « ce
webServer n'est pas l'artefact déployé, et voici ce que cet étage ne peut donc
pas voir ». Une limite nommée vaut mieux qu'un avertissement que trente dépôts
apprennent à ignorer.

Pour le second avertissement, NODE_ENV : le fixer explicitement à
production dans l'env du webServer suffit, et rapproche encore l'étage de
ce qui tourne en vrai.

Contournement posé

Aucun. L'étage e2e du satellite est vert tel quel ; c'est ce qu'il atteste qui
est plus étroit qu'il n'en a l'air.

## Ce qui ne va pas `playwright.config.ts` du gabarit démarre le serveur sous test par : ```ts webServer: { command: 'pnpm --filter web start', … } ``` et `apps/web/package.json` fait de `start` un `next start` (`node scripts/next.mjs start`). Or `apps/web/next.config.mjs` du même gabarit pose `output: 'standalone'`, et Next refuse la combinaison — à voix haute, à chaque exécution : ``` [WebServer] ⚠ "next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead. ``` ## Le plus petit chemin pour le reproduire Un clone du gabarit, `@eqs/*` en 0.11.2 : ``` pnpm install pnpm --filter web build pnpm test:e2e ``` L'avertissement sort au démarrage du `webServer`, avant le premier cas. Mesuré le 2026-09-17 sur un satellite `nest` monté sur `eqs-satellite-template@53e704c` (Node 24.15.0, pnpm 11.8.0, Windows 11) ; les deux fichiers en cause sont ceux du gabarit, non modifiés. Deuxième avertissement au même endroit, de la même famille : ``` [WebServer] ⚠ You are using a non-standard "NODE_ENV" value in your environment. ``` ## Ce que ça coûte **Pas bloquant aujourd'hui, et c'est précisément ce qui le rend gênant.** `next start` sert quand même depuis `.next/`, la page rend, le cas passe. Deux conséquences : 1. **L'étage e2e n'éprouve pas ce qui est déployé.** Le `Dockerfile` copie `.next/standalone` et lance `server.js` ; l'e2e, lui, lance un autre serveur, depuis un autre artefact, avec un autre traçage de fichiers (`outputFileTracingRoot`). Un défaut propre au bundle standalone — un fichier non tracé, un `public/` absent, un chemin de workspace mal résolu — passe l'étage e2e en vert et se découvre en production. C'est exactement la classe de défauts que `2303777` (« L'étage e2e du gabarit devient vrai ») visait à fermer. 2. **Le jour où Next transforme l'avertissement en refus**, les trente satellites perdent leur étage e2e le même matin, sur un message qui parle de configuration Next et pas du gabarit. Il y a une ironie utile ici : le commentaire de `playwright.config.ts` dit « Un étage e2e qui atteste de ce qu'il n'a pas regardé est pire que pas d'étage » — à propos de `reuseExistingServer`. Le même raisonnement s'applique à l'artefact servi. ## Ce que je proposerais Faire pointer le `webServer` sur le serveur standalone, celui que l'image lance : ```ts webServer: { command: 'node apps/web/.next/standalone/apps/web/server.js', env: { PORT: String(PORT), HOSTNAME: '127.0.0.1' }, … } ``` Avec une réserve mesurée : le serveur standalone ne sert pas `.next/static` ni `public/` tout seul — le `Dockerfile` les recopie à côté de lui (étages `web 2/3` et `web 3/3`). Il faudrait donc soit un petit script qui fait la même copie avant de lancer (le pendant local des trois `COPY`), soit assumer que l'e2e local teste le HTML et laisse les assets à la CI. Un script, plutôt : c'est ce qui rend l'étage local et l'image comparables, ce qui est tout l'objet de la demande. Si cette voie est jugée trop lourde pour ce que le gabarit doit livrer, l'autre réponse honnête est de **l'écrire dans `playwright.config.ts`** : « ce `webServer` n'est pas l'artefact déployé, et voici ce que cet étage ne peut donc pas voir ». Une limite nommée vaut mieux qu'un avertissement que trente dépôts apprennent à ignorer. Pour le second avertissement, `NODE_ENV` : le fixer explicitement à `production` dans l'`env` du `webServer` suffit, et rapproche encore l'étage de ce qui tourne en vrai. ## Contournement posé Aucun. L'étage e2e du satellite est vert tel quel ; c'est ce qu'il atteste qui est plus étroit qu'il n'en a l'air.
Author
Owner

Corrigé — et le défaut allait plus loin que ce que le ticket décrivait.

scripts/e2e.mjs lance eqs e2e up, qui construit l'image du Dockerfile et la lève derrière Caddy sur EQS_E2E_PORT. Pendant ce temps, playwright.config.ts démarrait son propre webServer sur un autre port et y pointait sa baseURL. La pile réelle était construite, attendue, payée — et jamais regardée.

Le webServer est donc retiré, pas remplacé : la baseURL vise le proxy de la pile. Retirer un serveur vaut mieux qu'en ajouter un second qui recopierait les trois COPY du Dockerfile — ce serait le même piège une couche plus haut, et c'est pourquoi votre proposition de script de copie n'a pas été retenue. Les deux avertissements disparaissent parce que leur cause disparaît : plus de next start, et NODE_ENV=production vient de l'image.

Ce que ça coûte, et c'est dit dans le fichier : npx playwright test seul ne démarre plus rien. pnpm test:e2e est la commande.

Mesuré : image construite, un cas passé contre le proxy, aucun avertissement Next dans la sortie, pile démontée. Voir reference/decisions.md L-002.

Deux suites, tirées de la même chasse (eqs-platform/reference/chasses.md, n°17) :

  • eqs-demo porte la même configuration, avec un commentaire qui affirme l'inverse de ce qui se passe (« on éprouve l'artefact construit, celui qui part en production »), et son test:e2e en && laisse la pile debout quand les tests échouent. À porter.
  • Aucun contrôle ne détecte « une configuration Playwright démarre un serveur alors que la pile e2e en publie un ». testing.etage-declare-vide sait déjà lire scripts et dépendances ; il pourrait refuser un webServer dans un dépôt dont le test:e2e appelle eqs e2e up.

Fermé le 2026-09-21. Ce ticket restait ouvert faute d'un Closes #30 dans le commit, pas faute de correctif.

Corrigé — et le défaut allait plus loin que ce que le ticket décrivait. `scripts/e2e.mjs` lance `eqs e2e up`, qui **construit l'image du `Dockerfile`** et la lève derrière Caddy sur `EQS_E2E_PORT`. Pendant ce temps, `playwright.config.ts` démarrait son propre `webServer` sur un autre port et y pointait sa `baseURL`. La pile réelle était construite, attendue, payée — **et jamais regardée**. Le `webServer` est donc **retiré**, pas remplacé : la `baseURL` vise le proxy de la pile. Retirer un serveur vaut mieux qu'en ajouter un second qui recopierait les trois `COPY` du `Dockerfile` — ce serait le même piège une couche plus haut, et c'est pourquoi votre proposition de script de copie n'a pas été retenue. Les deux avertissements disparaissent parce que leur **cause** disparaît : plus de `next start`, et `NODE_ENV=production` vient de l'image. Ce que ça coûte, et c'est dit dans le fichier : `npx playwright test` seul ne démarre plus rien. `pnpm test:e2e` est la commande. Mesuré : image construite, un cas passé contre le proxy, **aucun avertissement Next** dans la sortie, pile démontée. Voir `reference/decisions.md` L-002. Deux suites, tirées de la même chasse (`eqs-platform/reference/chasses.md`, n°17) : - `eqs-demo` porte la **même** configuration, avec un commentaire qui affirme l'inverse de ce qui se passe (« on éprouve l'artefact construit, celui qui part en production »), et son `test:e2e` en `&&` laisse la pile debout quand les tests échouent. À porter. - Aucun contrôle ne détecte « une configuration Playwright démarre un serveur alors que la pile e2e en publie un ». `testing.etage-declare-vide` sait déjà lire scripts et dépendances ; il pourrait refuser un `webServer` dans un dépôt dont le `test:e2e` appelle `eqs e2e up`. Fermé le 2026-09-21. Ce ticket restait ouvert faute d'un `Closes #30` dans le commit, pas faute de correctif.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Infrastructure/eqs-satellite-template#30
No description provided.