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 c9602a519e — BREAKING!!! 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-invitee-mail-archivee-mail-audit-log-alarme-mail-auto-archive-summarye-mail-cert-expirye-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
importand arequire()— not every file that containsrequire(). Of that mixed set, only the ones without acreateRequireshim 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
.jsextension in theimportspecifier. customization/util/util.jsismodule.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, grepcustomization/for files that contain both a top-levelimportand arequire(. 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 definedatEmailService.init; the affected letter type never registers → that email never sends. No crash loop.- Root cause: Node 22 auto-detects any
.jswith a top-levelimportas ESM (no"type":"module"needed);requireis undefined in ESM.- At-risk set:
customization/email/*/*.letter.data.js(per partner) containing bothimportandrequire(. Files with acreateRequire(import.meta.url)shim survive; a barerequirecrashes at boot.- Fix: convert
require()→import(explicit.json relative specifiers; named imports work againstmodule.exports = {}CJS files).- Cofidis facts: 6 mixed files, only
e-mail-invitecrashed; fix52a0843a1eonchore/FKITDEV-9059-cofidis-update-2026-07-13-fixes, unpushed; verified on fk-dev (3/boot → 0).
Related
- FKITDEV-9059 — Cofidis devel-update ticket this surfaced in
- typescript-in-vuer-repos — same Node
.jsmodule-handling surface (files stay CommonJS, do not add"type":"module") - nusz-devel-update-2026-06-16-lint-merge-fix — the
.js→.tsrename-merge cousin (grep for stalerequire()s) - customization-branch-ci-pipeline-inheritance — sibling reusable finding from this same ticket
- cve-2025-7783-form-data-via-request — the other reusable finding extracted from FKITDEV-9059
- customization-branches — cofidis is the “MJML email templates” partner in the customization matrix
- vuer_oss — owns
server/e-mail/EmailService.js(Nodemailer + MJML) - dev-build-host — fk-dev, where the fix was deployed and verified