Electron経由で出力したlogが文字化けして困ったときにすること

## 前置き
はいどうも、たねだです。
最近野暮用でまともにjavascriptを触ったこともないのに
ノリで使えると信じてElectronを使用しています。

構造としてはElectron(index.html)にある入力フィールドへ文字列を入力して送信ボタンを押すと
そのデータを取得してPython(FastAPI)に渡すというシンプルな仕組みです。
ところが、何度やっても受け取った値が<b>コンソール上でのみ</b>文字化けしてしまい困ったという話。

この<b>コンソール上でのみ文字化けしていた</b>というのが
今回の問題の最大のポイントでしたので
同じような悩みで右往左往している方のヒントになれば幸いです。
ではやっていきましょう！

## 環境
- Windows11 24H2
- VSCode 1.95.1
- npm 10.9.0
- node v22.11.0


## 試したこと

当然ですが問題が生じてからは
送受信する文字列が関わる処理に片っ端から`console.log()`をおいて確認しました。

コードを全て載せると煩雑になるので
ひとまず重要っぽいところだけ載せて進めていきます。

```renderer.js
document.getElementById('sendButton').addEventListener('click', async () => {
    const message = document.getElementById('inputField').value;
    const response = await window.electronAPI.sendData(message);
    document.getElementById('responseField').innerText = `Response from Python: ${response}`;
});
```
まずは、`index.html`にある送信ボタンを押したときの動作です。
sendButtonがクリックされるとipcMainにvalueを渡します。
そして後述の`main.js`にデータが渡り、そこからさらにPythonサーバーへ送られた後
なんやかんやあって`index.html`のresponseFieldに
`Response from Python: ${response}`が表示されるというわけですね。
このとき、確認したいのは<b>message</b>と<b>response</b>がどうなっているかです。
この時点で文字化けないし何かおかしなことになっている場合は
そもそも`index.html`からの受け渡しに失敗している可能性があります。

今回は該当しなかったので
`renderer.js`および`index.html`は問題なさそうとひとまず判断。
```main.js
// ～その他の記述

// Renderer.jsからデータを受け取って、Pythonサーバーに送信するコード
ipcMain.handle('send-data', async (event, message) => {
    const encodedMessage = encodeURIComponent(message);
    const response = await fetch(`http://127.0.0.1:8000/receive-data?message=${encodedMessage}`);
    const data = await response.json();
    console.log(`Response: ${data.response}`);
    return data.response;
});
```

続いて`main.js`です。
こちらでまず`send-data`から受け取った<b>message</b>が
果たして問題ないのか確認したいところですね。

…すると今回はまずここで文字化けしていることがわかりました。
ここから長らく沼にはまるのですが、
Pythonサーバーにはこの後の`encodedMessage`をもって処理を行うので
Pyhtonの問題でもないだろうと考えました。
(というかそもそもターミナルをnpmで立ち上げているのでPythonからのログは直接出ない)

エンコードやデコードを`renderer.js`と`main.js`にかませて
確認してみるも効果なし…。

ここまでで、ipcMainでの文字列の受け渡しがなんかうまいこといっていないのだろう。
つまり問題は`main.js`にあると考えていました。

ところが文字化けしているはずの`encodedMessage`ですが、
Pythonサーバーを経由したのちに`renderer.js`によって
`responseField`に表示されているのに文字化けしていない…。

念のためPythonサーバーから`renderer.js`へ返される前に
tikinterを立ち上げてラベルとして送られてきた文字列を表示させてみると
やはり文字化けしていない…！

ということでいよいよコンソール上でのみ
文字化けが発生しているという判断に至ったわけですが、ここからも長かった。

これも色々やりましたがほぼ全てが徒労に終わりましたので
一瞬希望が見えた方法だけ１つ残しておきます。

ターミナル上(cmdでもPowerShellでも)にて
`chcp 65001`を実行するという方法ですね。
詳しいことはよくわかりませんが
コンソールのエンコーディングを65001(utf-8)にするというコマンドです。
実は上記はまだ`main.js`が問題だと思っていた時に試してダメだったので
「やっぱり`main.js`に問題があるんだ」
という執着心が高まり解決に時間がかかったような気がします。

皆さんがこの記事をどういう経緯で見ているのかわかりませんが、
もしかすると上記で直る方もいるかもしれないですね。

## そして解決へ…

長々と戦ってきたこの問題もいよいよ終着点です。
まだこの問題に悩んでいるそこのあなた、
とりあえず下記をターミナルで実行してください。
```bash
[Console]::OutputEncoding
```
上記を実行すると、こんな感じの内容が出力されるはずです。
```bash
BodyName          : utf-8
EncodingName      : Unicode (UTF-8)
HeaderName        : utf-8
WebName           : utf-8
WindowsCodePage   : 1200
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
IsSingleByte      : False
EncoderFallback   : System.Text.EncoderReplacementFallback
DecoderFallback   : System.Text.DecoderReplacementFallback
IsReadOnly        : False
CodePage          : 65001
```
上記はすでに設定済みのものですが、
ここで`utf-8`以外のものが表示された場合
以下を実行してください。
```bash
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
```
実行したら、ターミナルを再起動して再度文字化けしないかを確認してください。
私はここまででひとまず解決しました。

ただ上記では暫定対応になってしまうので、
恒久的に設定を適応する場合は
```bash
echo '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8' >> $PROFILE
```
上記を実行して`PROFILE`に直接設定を追加します。
同じくVSCodeの再起動を行い、`[Console]::OutputEncoding`で再度
エンコードが`utf-8`になっているかを確認して下さい。

:::note info
もしもうまくいかない場合は`echo $PROFILE`を実行して、
`$PROFILE`ファイルの位置を確認します。
ない場合は`Microsoft.PowerShell_profile.ps1`を、
`C:\Users\YourName\Documents\PowerShell\`の直下に作成した上で
`[Console]::OutputEncoding = [System.Text.Encoding]::UTF8`を記述し
PowerShellを再起動することで解消される可能性があります。
:::

## 補足
上記を行うにあたりファイルの実行ができないなどのエラーが出た場合は
ポリシーが関係している場合があります。
```bash
Get-ExecutionPolicy
```
ターミナルで上記を実行してステータスが`Restricted`になっている場合は
スクリプトの実行が制限されていますので、
ローカル上のスクリプトを実行可能にするため管理者権限でPowerShellを開き、
```bash
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
```
上記を実行することでポリシーの変更ができます。
その後再度ターミナルを再起動して`[Console]::OutputEncoding`にて
エンコーディングが`utf-8`になっていれば成功です。

説明するまでもないとは思いますが、
今回変更したポリシーの説明は割愛させていただきますので
詳細を知りたい方は以下MicroSoftが公開している
実行ポリシーについての記事をご覧ください。

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4

以上、お疲れさまでした！