A merge-introduced runtime regression from FKITDEV-9059: the MJML v4→v5 major upgrade (MJML v5 is ESM-only) turned some cofidis email-template files into ESM, where require is undefined, so a letter type failed to register and its email silently never sent. Green CI, broken runtime — unit tests never boot the email service. Generalises to any ESM migration of a loader.

What triggered it

The devel → customization/cofidis merge included commit c9602a519eBREAKING!!! FKITDEV-8727 MJML update to v5. MJML v5 is ESM-only, so it changed server/e-mail/EmailService.js in vuer_oss to load letter templates via await import(...) instead of require(...).

The mechanism (why a .js template becomes ESM)

Node 22’s automatic module-syntax detection parses any .js file that contains a top-level import statement as ESM — and in ESM, require is undefined. This happens even though the repos have no "type": "module" (the same Node module-handling surface described in typescript-in-vuer-repos).

Cofidis letter templates live at customization/email/*/*.letter.data.js. Any such file that mixes an ESM import with a CommonJS require() therefore throws:

ReferenceError: require is not defined

…at EmailService.init. The letter type never registers, so that email is never sent — no crash loop, no obvious failure, just a missing email type.

The debugging trap (this is the load-bearing nuance)

The naive scope was “41 of 49 email/letter files contain require( → all at risk.” That is wrong. A pure-CommonJS file (only require, no import) still loads fine as CJS. Only files that MIX import + require actually break.

Real broken set = 6 files:

  • e-mail-invite
  • e-mail-archive
  • e-mail-audit-log-alarm
  • e-mail-auto-archive-summary
  • e-mail-cert-expiry
  • e-mail-xml-report-send

And of those 6, 5 already had a createRequire(import.meta.url) shim (so their require worked despite ESM parsing). Only e-mail-invite (the registration invite) had a bare require with no shim, so it was the only one that actually failed at boot — matching the fk-dev box log, which showed only e-mail-invite erroring.

Don't scope by "contains require()"

The at-risk set after an ESM-loader migration is files that contain both a top-level import and a require() — not every file that contains require(). Of that mixed set, only the ones without a createRequire shim crash at boot; the shimmed ones are latent (correct today, fragile).

The fix

Convert the remaining require() calls in those 6 files to ESM import:

  • Relative paths need an explicit .js extension in the import specifier.
  • customization/util/util.js is module.exports = { ...named }named ESM imports work against it via Node’s CJS named-export detection (import { foo } from '...util.js').

Committed solo-author 52a0843a1e on the vuer_oss branch chore/FKITDEV-9059-cofidis-update-2026-07-13-fixes (parent = the pushed CI-fix 6fac58ba4b), NOT pushed.

Verified on fk-dev: after deploy + restart, letter-type registration errors dropped from 3 per boot to 0.

Why CI missed it

Unit tests never boot EmailService or load the letter templates — this is a runtime-only failure. Same “green CI / broken runtime” class as the other FKITDEV-9059 findings (the registration innerHTML null bug, the web/ build EACCES 404). Green build/tests mask a step that only runs when the service actually starts.

General lesson (reusable)

After any ESM migration of a loader, grep customization/ for mixed import+require

An MJML major upgrade — or any change that makes a shared loader ESM-only (forcing await import(...)) — can silently break every customization file that used CommonJS syntax. After such a merge, grep customization/ for files that contain both a top-level import and a require(. Each partner branch forks its own email/letter templates, so this recurs per partner.

This is the ESM-migration cousin of the nusz-devel-update-2026-06-16-lint-merge-fix gotcha (after a .js.ts rename merge, grep for extensionless require()s of the renamed modules).

For Agents

  • Trigger: an ESM-only major upgrade of a shared loader merged via devel → customization/* (here: MJML v4→v5, c9602a519e, FKITDEV-8727).
  • Symptom: ReferenceError: require is not defined at EmailService.init; the affected letter type never registers → that email never sends. No crash loop.
  • Root cause: Node 22 auto-detects any .js with a top-level import as ESM (no "type":"module" needed); require is undefined in ESM.
  • At-risk set: customization/email/*/*.letter.data.js (per partner) containing both import and require(. Files with a createRequire(import.meta.url) shim survive; a bare require crashes at boot.
  • Fix: convert require()import (explicit .js on relative specifiers; named imports work against module.exports = {} CJS files).
  • Cofidis facts: 6 mixed files, only e-mail-invite crashed; fix 52a0843a1e on chore/FKITDEV-9059-cofidis-update-2026-07-13-fixes, unpushed; verified on fk-dev (3/boot → 0).