Ce qui se passe
Node.js 27, en phase alpha, embarque V8 15.6, contre V8 14.6 pour Node.js 26. Joyee Cheung en détaille les
changements notables sur le blog du projet. Le contexte compte : avec le nouveau calendrier de Node.js, les phases
Alpha et Current peuvent recevoir des ruptures de V8 ; celles qui touchent l'ABI des modules natifs s'accompagnent d'un
saut de NODE_MODULE_VERSION. Une fois la ligne 27 en LTS, sa version de V8 est censée ne plus bouger.
Sérialisation : compatible dans un seul sens
v8.serialize(), structuredClone() et postMessage adoptent un nouveau format. Node 27 relit les données écrites
par les versions précédentes, mais l'inverse échoue, sur une erreur « invalid or unsupported version ». Tout ce qui
persiste la sortie de v8.serialize() — cache sur disque, file de messages, état partagé pendant un déploiement
progressif où deux versions tournent côte à côte — casse dès que l'ancienne version lit ce que la nouvelle a écrit.
Le nouveau format accepte, dans structuredClone() et postMessage, des typed arrays et des ArrayBuffer
redimensionnables de plus de 4 Go ; v8.serialize() garde la limite de 4 Go. Autre effet de bord :
v8.cachedDataVersionTag() change désormais à chaque patch que Node applique sur V8, si bien que le cache de
compilation des modules et les données en cache de vm.Script sont invalidés plus souvent d'une version à l'autre.
Mémoire : les défauts bougent
- Limite de l'old generation : la moitié de la mémoire physique ou de la limite cgroup, bornée entre 256 Mo et
4 Go. Avant : la moitié plafonnée à 2 Go, ou 4 Go à partir de 15 Go de RAM. Une machine de 8 Go passe de 2 à 4 Go,
une de 6 Go de 2 à 3 Go. Qui comptait sur l'ancien plafond doit fixer
--max-old-space-size. - La mémoire des
Bufferet desArrayBufferentre dans la limite globale d'allocation de V8 : le ramasse-miettes se déclenche à d'autres moments dans les applications qui en allouent beaucoup. - Le bytecode d'une fonction inutilisée depuis environ 3 minutes peut être jeté au GC majeur, puis recompilé.
- Chaque objet qui enveloppe une ressource native (socket, fichier, flux, blob) prend environ 16 octets de plus sur le tas et 50 hors du tas ; chaque isolate, environ 180 Ko de plus. À surveiller avec beaucoup de workers.
Comportements JavaScript qui changent
Mathpasse par la libm de LLVM :Math.sin(18)donne-0.750987246771676(avant-0.7509872467716762). Les tests qui comparent à des valeurs figées peuvent rougir sur le dernier chiffre.Math.random()sous--random-seedproduit une autre séquence.Array.prototype.sort()utilise PowerSort au lieu de TimSort sur les grands tableaux : même résultat stable, mais un nombre d'appels au comparateur différent.error.stackne remonte plus la chaîne de prototypes : lu surObject.create(err), il vautundefined.getTimezoneOffset()n'est plus tronqué à la minute pour les dates historiques en temps moyen local.take()etdrop()avec une limite finie au-delà de 2^53-1 lèvent uneRangeError.
Outillage et diagnostics
- Les instantanés du tas sont environ deux fois plus longs à produire et deux fois plus gros. Ils contiennent désormais le source complet des scripts (avant : les 1 024 premiers caractères), donc les secrets qui y sont écrits. Traitez-les comme des données sensibles.
- L'édition à chaud par l'inspecteur est supprimée :
Debugger.setScriptSourceéchoue toujours. - WebAssembly : asm.js n'est plus compilé en Wasm, et les drapeaux
--experimental-wasm-<nom>deviennent--wasm-<nom>, l'ancien nom n'étant plus accepté.
Ce qui arrive
Math.sumPrecise([0.1, 0.2, 0.3]); // 0.6, sans erreur d'arrondi cumulée
[1, 2, 3].values().map((x) => x * 2).join('-'); // '2-4-6'
Iterator.zip([[1, 2], ['a', 'b']]).toArray(); // [[1, 'a'], [2, 'b']]S'y ajoutent Iterator.prototype.includes(), Iterator.zipKeyed() et Intl.Locale.prototype.variants. Côté
performance, les pires pauses du ramasse-miettes passent d'environ 45 ms à 10 ms dans les bancs de V8, et les
expressions régulières sont compilées en code machine dès leur premier usage.
Comment s'y prendre
- Ajoutez Node 27 alpha à votre CI, en tâche non bloquante.
- Recensez ce qui relit des données produites par
v8.serialize()sur une autre version de Node. - Fixez
--max-old-space-sizelà où la mémoire doit rester contenue. - Nettoyez vos scripts de lancement des drapeaux
--experimental-wasm-*.
Source : blog Node.js, billet de Joyee Cheung. Source en anglais.