Luego de de esta prolongada búsqueda de información dimos con la solución este contratiempo que presentan muchos usuarios. Te ofrecemos la solución y deseamos resultarte de gran ayuda.
Solución:
Lo que desea puede no ser posible sin un cambio en libuv. Cuando tú (o la consola) escribes en stdout
o stderr
en Windows y la transmisión es un TTY,
libuv hace su propia conversión de UTF‑8 a UTF‑16. Al hacerlo, se niega explícitamente a generar pares suplentes, emitiendo en su lugar el carácter de reemplazo
U+FFFD
para cualquier punto de código más allá del BMP.
Aquí está el culpable en uv/src/win/tty.c:
/* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
/* windows console doesn't really support UTF-16, so just emit the */
/* replacement character. */
if (utf8_codepoint > 0xffff)
utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
El throw
El mensaje aparece correctamente porque Node permite que Windows realice la conversión de UTF‑8 a UTF‑16 con MultiByteToWideChar()
(que emite pares sustitutos) antes de escribir el mensaje en la consola. (Ver
PrintErrorString()
en src/node.cc.)
Nota: Se envió una solicitud de extracción para resolver este problema.
(Descargo de responsabilidad: no tengo una solución, exploré qué hace que el manejo de excepciones sea especial con respecto a la impresión de emoji, con las herramientas que tengo en Windows 10: con un poco de suerte, eso podría arrojar algo de luz sobre el problema, y quizás alguien reconozca algo y encuentre una solución)
Parece que el código de informe de excepción de Node para llamadas de Windows a una API de Windows diferente, que resulta ser compatible con Unicode mejor.
Veamos con las fuentes de Node 7.10:
ReportException → AppendExceptionLine → PrintErrorString
En PrintErrorString
, la sección específica de Windows detecta el tipo de salida (tty/consola o no): – Para el contexto que no es tty/consola, se imprimirá en stderr
(por ejemplo, si redirige a un archivo): en una consola cmd (sin redirección), convertirá el texto con MultiByteToWideChar()
y luego pasar eso a WriteConsoleW()
.
Si ejecuto su programa usando ConEmu (más fácil que obtener estándar cmd
para trabajar con Unicode y emoji, sí, me dio un poco de pereza aquí), veo algo similar a lo que viste: console.log
no puede imprimir emoji, pero los emoji en el mensaje de excepción se imprimen correctamente (incluso el glifo de desplazamiento).
Si redirijo toda la salida a un archivo (node test.js > out.txt 2>&1
, sí, eso también funciona en Windows cmd), obtengo Unicode “limpio” en ambos casos.
Entonces parece que cuando un programa se imprime en stdout
o stderr
en una consola de Windows, la consola realiza algún (mal) trabajo de recodificación antes de imprimir. Cuando el programa usa la API de la consola de Windows directamente (haciendo la conversión en sí mismo con MultiByteToWideChar
luego escribe en la consola con WriteConsoleW()
), la consola muestra el glorioso emoji inalterado.
Cuando un programa JS usa console
API para registrar cosas, tal vez Node podría intentar (en Windows) detectar la consola y hacer lo mismo que hace para informar excepciones. Vea la respuesta de @BrianNixon que explica lo que realmente está sucediendo en libuv.
Reseñas y puntuaciones
Recuerda dar visibilidad a esta sección si te ayudó.