bdukes
bdukes

Reputation: 155925

How to output emoji to console in Node.js (on Windows)?

On Windows, there's some basic emoji support in the console, so that I can get a monochrome glyph if I type, e.g. β˜• or πŸ“œ. I can output a string from PowerShell or a C# console application or Python and they all show those characters fine enough.

However, from Node.js, I can only get a couple of emoji to display (e.g. β˜•), but not other (instead of πŸ“œ I see οΏ½). However, if I throw a string with those characters, they display correctly.

console.log(' πŸ“œ β˜• ');
throw ' πŸ“œ β˜• ';

If I run the above script, the output is

 οΏ½ β˜•

C:\Code\emojitest\emojitest.js:2
throw ' πŸ“œ β˜• '; 
^
 πŸ“œ β˜•

Is there anyway that I can output those emojis correctly without throwing an error? Or is that exception happening outside of what's available to me through the standard Node.js APIs?

Upvotes: 20

Views: 25932

Answers (4)

Arvin_m
Arvin_m

Reputation: 31

There is an easy way to log Emojis in the console:

console.log("\u{1F9E1} Do what you love or love what you do!");

console.log("\u{1F3AF}");

Emoji code in Hex format reference: https://www.w3schools.com/charsets/ref_emoji.asp

Upvotes: 3

Brian Nixon
Brian Nixon

Reputation: 9828

What you want may not be possible without a change to libuv. When you (or the console) write to stdout or stderr on Windows and the stream is a TTY, libuv does its own conversion from UTF‑8 to UTF‑16. In doing so it explicitly refuses to output surrogate pairs, emitting instead the replacement character U+FFFD οΏ½ for any codepoint beyond the BMP.

Here’s the culprit in 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;
  }

The throw message appears correctly because Node lets Windows do the conversion from UTF‑8 to UTF‑16 with MultiByteToWideChar() (which does emit surrogate pairs) before writing the message to the console. (See PrintErrorString() in src/node.cc.)

Note: A pull request has been submitted to resolve this issue.

Upvotes: 18

VonC
VonC

Reputation: 1324178

The next "Windows Terminal" (from Kayla Cinnamon) and the Microsoft/Terminal project should be able to display emojis.

This will be available starting June 2019. Through the use of the Consolas font, partial Unicode support will be provided.

The request is in progress in Microsoft/Terminal issue 387.
And Microsoft/Terminal issue 190 formally demands "Add emoji support to Windows Console".

But there are still issues (March 2019):

I updated my Win10 from 1803 to 1809 several days ago, and now all characters >= U+10000 (UTF-8 with 4 bytes or more) no longer display.
I have also tried the newest insider version(Windows 10 Insider Preview 18358.1 (19h1_release)), unfortunately, this bug still exists.

Upvotes: 1

Hugues M.
Hugues M.

Reputation: 20467

(Disclaimer: I don't have a solution, I explored what makes exception handling special with regards to printing emoji, with the tools I have on Windows 10 -- With some luck that might sched some light on the issue, and perhaps someone will recognize something and come up with a solution)

Looks like Node's exception reporting code for Windows calls to a different Windows API, that happens to support Unicode better.

Let's see with Node 7.10 sources:

ReportException β†’ AppendExceptionLine β†’ PrintErrorString

In PrintErrorString, the Windows-specific section detects output type (tty/console or not): - For non-tty/console context it will print to stderr (e.g. if you redirect to a file) - In a cmd console (with no redirection), it will convert text with MultiByteToWideChar() and then pass that to WriteConsoleW().

If I run your program using ConEmu (easier than getting standard cmd to work with unicode & emoji -- yes I got a bit lazy here), I see something similar as what you saw: console.log fails to print emoji, but the emoji in exception message are printed OK (even the scroll glyph).

If I redirect all output to a file (node test.js > out.txt 2>&1, yes that works in Windows cmd too), I get "clean" Unicode in both cases.

So it seems when a program prints to stdout or stderr in a Windows console, the console does some (bad) reencoding work before printing. When the program uses Windows console API directly (doing the conversion itself with MultiByteToWideChar then write to console with WriteConsoleW()), the console shows the glorious unaltered emoji.

When a JS program uses console API to log stuff, maybe Node could try (on Windows) to detect console and do the same thing as it does for reporting exceptions. See @BrianNixon's answer that explains what is actually happening in libuv.

Upvotes: 2

Related Questions