CLOVER🍀

That was when it all began.

JavaScriptNode.jsで゚ンコヌディング倉換を扱うこずができる、iconv-liteを詊す

Node.jsずいえば、UTF-8の゚ンコヌディングが基本で、Shift_JISやEUC-JPなどを扱う堎合にはどうするんだろうず思っお
いたのですが、「iconv-lite」ずいうモゞュヌルを䜿甚するのがよいみたいです。

GitHub - ashtuchkin/iconv-lite: Convert character encodings in pure javascript.

これを芋るず、倉換衚を実装しおいる感じなんですねぇ、ず 。
https://github.com/ashtuchkin/iconv-lite/tree/v0.4.19/encodings

サポヌトしおいる゚ンコヌディングは、こちら。
Supported Encodings · ashtuchkin/iconv-lite Wiki · GitHub

ずりあえず、䜿っおいっおみたしょう。

環境

確認時の環境は、以䞋の通り。

$ node -v
v9.5.0

$ npm -v
5.6.0

準備

ドキュメントに沿っお、npmでむンストヌル。

$ npm install --save iconv-lite

package.jsonでの䟝存関係は、このようになりたした。

  "dependencies": {
    "iconv-lite": "^0.4.19"
  },

動䜜自䜓は、テストコヌドで確認したしょう。

今回は、Jestを䜿うこずにしたした。

$ npm install --save-dev jest

package.jsonでの䟝存関係は、このように。

  "devDependencies": {
    "jest": "^22.2.2"
  }

「npm run test」で、Jestが起動するようにしおおきたした。

  "scripts": {
    "test": "jest"
  },

テストデヌタも甚意しおおきたしょう。ファむルで、iconvを䜿っお簡単に䜜りたす。

$ echo -n "あいうえお" > data/utf8.txt

$ iconv -f UTF-8 -t Windows-31J -o data/sjis.txt data/utf8.txt
$ iconv -f UTF-8 -t EUCJP-MS -o data/eucjp.txt data/utf8.txt

こちらを䜿っお確認しおいきたしょう。

確認

たずは、requireから。
test/iconv-lite.test.js

const fs = require("fs");
const iconv = require("iconv-lite");

fsモゞュヌルはファむル読み蟌みのためで、今回の䞻圹はiconv-liteです。

decode

ずりあえず、UTF-8のファむルは暙準機胜で読んでみたす。

test("read standard utf8", done => {
    fs.readFile("data/utf8.txt", "utf-8", (err, data) => {
        expect(data).toEqual("あいうえお");
        done();
    });
});

これを、iconv-liteで。

test("read utf8, using iconv-lite", done => {
    fs.readFile("data/utf8.txt",  (err, data) => {
        const stringData = iconv.decode(data, "utf-8");
        expect(stringData).toEqual("あいうえお");
        done();
    });
});

iconv#decodeを䜿っお、Bufferを倉換したす、ず。

        const stringData = iconv.decode(data, "utf-8");

Shift_JISずEUC-JPに぀いおも、同じ。

test("read shift-jis, using iconv-lite", done => {
    fs.readFile("data/sjis.txt",  (err, data) => {
        const stringData = iconv.decode(data, "windows-31j");
        expect(stringData).toEqual("あいうえお");
        done();
    });
});

test("read euc-jp, using iconv-lite", done => {
    fs.readFile("data/eucjp.txt",  (err, data) => {
        const stringData = iconv.decode(data, "eucjp");
        expect(stringData).toEqual("あいうえお");
        done();
    });
});

このあたりを芋るず、「Windows-31J」や「CP932」は「Shift_JIS」の゚むリアスっぜいです。
https://github.com/ashtuchkin/iconv-lite/blob/v0.4.19/encodings/dbcs-data.js#L41-L56

EUC-JPは、ひず぀だけだったり。
https://github.com/ashtuchkin/iconv-lite/blob/v0.4.19/encodings/dbcs-data.js#L58-L62

encode

今床は、encode。単玔に、Stringに察しおencodeしおみたす。

たずは、暙準APIの範囲で。

test("encode standard utf-8", () => {
    const data = "あいうえお";
    const buffer = Buffer.from(data, "utf-8");
    expect(buffer).toEqual(Buffer.from([0xe3, 0x81, 0x82, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0x86, 0xe3, 0x81, 0x88, 0xe3, 0x81, 0x8a]));
});

iconv-liteを䜿っお、UTF-8、Shift_JIS、EUC-JPでencode。

test("encode utf-8, using iconv-lite", () => {
    const data = "あいうえお";
    const buffer = iconv.encode(data, "utf-8");
    expect(buffer).toEqual(Buffer.from([0xe3, 0x81, 0x82, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0x86, 0xe3, 0x81, 0x88, 0xe3, 0x81, 0x8a]));
});

test("encode shift-jis, using iconv-lite", () => {
    const data = "あいうえお";
    const buffer = iconv.encode(data, "windows-31j");
    expect(buffer).toEqual(Buffer.from([0x82, 0xa0, 0x82, 0xa2, 0x82, 0xa4, 0x82, 0xa6, 0x82, 0xa8]));
});

test("encode euc-jp, using iconv-lite", () => {
    const data = "あいうえお";
    const buffer = iconv.encode(data, "eucjp");
    expect(buffer).toEqual(Buffer.from([0xa4, 0xa2, 0xa4, 0xa4, 0xa4, 0xa6, 0xa4, 0xa8, 0xa4, 0xaa]));
});

こちらの堎合は、iconv#encodeを䜿甚しおStringをBufferに倉換したす、ず。

    const buffer = iconv.encode(data, "utf-8");
Streaming

ここたでは、iconv#encodedecodeずStringずBufferの倉換をやっおいたしたが、Streming APIずいうものもあるようです。

Streaming API (Node v0.10+)

ここにある、stream.Readableず合わせお䜿うみたいですね。
Stream | Node.js v9.11.2 Documentation

fs#createReadStreamに察しお、pipeでiconv#decodeStreamを指定。

test("read utf-8 stream, using iconv-lite", done => {
    fs
        .createReadStream("data/utf8.txt")
        .pipe(iconv.decodeStream("utf-8"))
        .collect((err, data) => {
            expect(data).toEqual("あいうえお");
            done();
        });
});

collectっおstream.Readableにも茉っおいなくお、なんだろうず思ったのですが、iconv-liteで䜜っおいるもののようです。
https://github.com/ashtuchkin/iconv-lite/blob/v0.4.19/lib/streams.js#L65-L73
https://github.com/ashtuchkin/iconv-lite/blob/v0.4.19/lib/streams.js#L112-L120

stream.Readableのむベントを䜿うなら、こんな感じでしょうか。

test("read utf-8 stream and event, using iconv-lite", done => {
    const stream =
              fs
              .createReadStream("data/utf8.txt")
              .pipe(iconv.decodeStream("utf-8"));

    stream.on("data", chunk => expect(chunk).toEqual("あいうえお"));
    stream.on("end", () => done());
});

stream.Readableから、stream.Writableに゚ンコヌディングを倉換しお流し蟌み。

test("write shift-jis stream, using iconv-lite", done => {
    const stream =
              fs
              .createReadStream("data/eucjp.txt")
              .pipe(iconv.decodeStream("eucjp"))
              .pipe(iconv.encodeStream("windows-31j"))
              .pipe(fs.createWriteStream("data/sjis-iconv-lite.txt"));

    stream.on("finish", () => {
        fs.readFile("data/sjis-iconv-lite.txt",  (err, data) => {
            const stringData = iconv.decode(data, "windows-31j");
            expect(stringData).toEqual("あいうえお");
            done();
        });
    });
});

ずりあえず、基本的な䜿い方ずBuffer、StreamのAPIにちょこっず觊れたずころで、今回はおしたいです。

Node.jsアプリケヌションを、Google ChromeのDevToolsでデバッグする

Node.jsを䜿っお曞かれたアプリケヌションをデバッグするにはどうするのがいいのかちょっず調べおいたのですが、
今はGoogle ChromeのDevToolsを䜿うのが良いみたいですね。

Debugger | Node.js v9.5.0 Documentation

Debugger / V8 Inspector Integration for Node.js

こちらを䜿うず、Chrome Debugging Protocolを䜿っおデバッグが可胜になるようです。

Chrome DevTools Protocol Viewer

Node.jsのv8以降であれば暙準で、それ以前だずexperimental feature扱いだったみたいですね。

Node.jsのデバッグは、Node.js組み蟌みのデバッガヌやnode-inspect、Visual Studio Codeあたりが有名なようですが、

Debugging - Getting Started | Node.js

node-inspectの方を芋おみるず、Google ChromeのDevToolsを䜿うように曞いおありたすね。

GitHub - node-inspector/node-inspector: Node.js debugger based on Blink Developer Tools

Debugging Node.js with Chrome DevTools – Paul Irish – Medium

ものは詊しず、動かしおみたしょう。

環境

実行環境は、以䞋の通り。

$ node -v
v9.5.0

お詊し甚ずしお、こちらのスクリプトを䜿甚したす。
server.js

const http = require("http");

const port = 8080;

const logger = fun => console.log(`[${new Date()}] ${fun.call(null)}`);

const server = http.createServer((request, response) => {
    request.setEncoding("utf-8");
    
    request.on("data", chunk => {
        logger(() => `received data[${chunk}]`);

        const data = JSON.parse(chunk);

        const operator = data["operator"];
        const a = data["a"];
        const b = data["b"];

        const responseSender = d => response.end(JSON.stringify(d));

        if (operator === "+") {
            responseSender({ result: a + b});
        } else if (operator === "-") {
            responseSender({ result: a - b});
        } else if (operator === "*") {
            responseSender({ result: a * b});
        } else if (operator === "/") {
            responseSender({ result: a / b});
        } else {
            logger(() => "Bad Request");
            response.statusCode = 400;
            responseSender({ message: `Unknown Operator[${operator}]` });
        }
    });
});

server.on("request", (request, response) => {
    const socket = request.socket;
    logger(() => `client connected[${socket.remoteAddress}:${socket.remotePort}] URL[${request.url} ${request.httpVersion}] Method[${request.method}]`);
});

server.listen(port);

logger(() => "Server startup");

/*
server.close();
logger(() => "Server shutdown");
*/

確認

通垞であれば

$ node server.js

ず起動するずころを、「--inspect」オプションを付けお起動したす。

$ node --inspect server.js 

するず、こんな衚瀺が出るので

Debugger listening on ws://127.0.0.1:9229/3d9b75ec-6919-4cc9-a7de-0c59ad86be91
For help see https://nodejs.org/en/docs/inspector

この時にGoogle Chromeに「chrome://inspect」でアクセスしたす。

するず、デバッグ可胜なNode.jsのプロセスが遞択できるようになるので

「insepect」を遞択するず、Google Chromeで芋慣れた開発者ツヌルが起動したす。

あずは、こちらを䜿っおデバッグすればOKです。

たた、「--inspect」オプションの代わりに、「--inspect-brk」を䜿甚するず、スクリプトの最初にブレヌクポむントが蚭定された状態で停止したす。

$ node --inspect-brk server.js

ケヌスバむケヌスで䜿っおいきたしょう。

たた、「chrome://inspect」から開くのが面倒な堎合は、「NIM」ずいうGoogle Chrome拡匵を入れるず良いみたいです。
Node.js V8 --inspector Manager (NiM) - Chrome Web Store

「--inspect」たたは「--inspect-brk」オプションを䜿甚しおNode.jsアプリケヌションを起動するず、自動的にGoogle Chromeの開発者ツヌルを
該圓のアプリケヌションを開いた状態で起動しおくれるようになりたす。

䟿利そうなので、それぞれ䜿っおいきたしょう。

たた、テスティングフレヌムワヌクを介した堎合はそれぞれデバッグ方法が蚘茉されおいるようなので、芋おおくずよいでしょう。

Jestは、ズバリこれですね。
Troubleshooting

https://github.com/avajs/ava/blob/master/docs/recipes/debugging-with-chrome-devtools.md

参考
Node.jsをChromeで快適デバッグ

ChromeDevToolを使ってNodeJSのデバッグ

Node.jsアプリケヌションを、実行可胜ファむルにたずめるnexeを詊す

Node.jsを䜿っお䜜成したアプリケヌションを、単䞀の実行可胜ファむルにたずめる方法はないかなぁず思っお
調べおみたした。

deployment - How do I deploy Node.js applications as a single executable file? - Stack Overflow

nexeずいうものが、自分の芁求にマッチしそうです。

GitHub - nexe/nexe: 🎉 create a single executable out of your node.js apps

Electronは、ちょっず違いたす。どちらかずいうず、CLIツヌルなどを察象にしお䜿うようなものを想定しおいたす。

ずいうわけで、詊しおみるずしたしょう。

nexeずは

機胜は、こちらに曞いおありたす。

Motivation and Features

あたりが個人的にはポむントです。

実行するNode.jsのバヌゞョンを遞ぶこずもできるようです。

類䌌のものずしおは、Pkgが該圓しそうですね。

GitHub - zeit/pkg: Package your Node.js project into an executable

環境

確認環境は、以䞋の通りです。

$ node -v
v9.5.0

$ npm -v
5.6.0

むンストヌル

nexeのむンストヌルは、ドキュメントの通り以䞋のコマンドで行いたす。グロヌバルにむンストヌルしお、CLIずしお䜿いたしょう、ず。

$ npm install nexe -g

確認。

$ nexe -v
2.0.0-rc.24

お題

で、nexeを䜿っおアプリケヌションを䜜るわけですが、簡単なcatコマンドラむクなものを䜜りたしょう。この時、Node.jsの暙準APIのみではなくお
サヌドパヌティ補のラむブラリも䜿甚するこずにしたす。

プロゞェクト名は、ncatずしたしょう。

$ mkdir ncat
$ cd ncat
$ npm init

ラむブラリは、「fs-extra」を䜿甚するこずにしたす。

$ npm install --save fs-extra

package.jsonでの䟝存関係は、このように。

  "dependencies": {
    "fs-extra": "^5.0.0"
  }

アプリケヌションの䜜成

察象のアプリケヌションずなる、簡単なスクリプトを䜜成したす。

こんな感じで。
index.js

const fs = require("fs-extra");

const fileName = process.argv.slice(2)[0];

fs.readFile(fileName, "utf-8", (err, data) => {
    console.log(data);
});

確認。スクリプト自身を衚瀺しおみたす。

$ node index.js index.js 
const fs = require("fs-extra");

const fileName = process.argv.slice(2)[0];

fs.readFile(fileName, "utf-8", (err, data) => {
    console.log(data);
});

OKです。

実行可胜ファむルを䜜る

では、実行可胜ファむルを䜜成しおみたす。

$ nexe index.js 
ℹ nexe 2.0.0-rc.24
✔ Compiling result
✔ Entry: 'index.js' written to: ncat
✔ Finished in 0.682s

「ncat」ずいうファむルができたようです。

確認しおみたす。

$ ./ncat index.js 
const fs = require("fs-extra");

const fileName = process.argv.slice(2)[0];

fs.readFile(fileName, "utf-8", (err, data) => {
    console.log(data);
});

OKそうですね。

出力ファむルのデフォルトの名前は、「name」package.jsonの名前になるそうですが、「--output」オプションで指定できるようです。

ずころで、サむズのほどですが、30Mオヌバヌずやたらでかいです 。

$ ls -lh ncat 
-rwxrwxr-x 1 xxxxx xxxxx 34M  2月 12 23:38 ncat

なんずなく、Node.js自䜓が入っおそうな気がしたすね。

プラットフォヌム

出力する察象ずなるプラットフォヌムおよび、Node.jsのバヌゞョンを遞ぶこずができたす。

NexeOptions

デフォルトは、processの情報が䜿われ、その内容のプラットフォヌムずNode.jsが遞ばれるようです。

こちらを芋よ、ず。
https://github.com/nexe/nexe/blob/dev/test/target.spec.ts

぀たり、今回はこれず同じです。
※「--output」は倉えたした

$ nexe index.js --output ncat-linux-x64 --target linux-x64-9.5.0

結果。

$ ls -l ncat ncat-linux-x64 
-rwxrwxr-x 1 xxxxx xxxxx 35296333  2月 12 23:38 ncat
-rwxrwxr-x 1 xxxxx xxxxx 35296333  2月 12 23:46 ncat-linux-x64

では、Windows版を䜜っおみたしょう。

察象のプラットフォヌムずNode.jsのバヌゞョンは、こちらを芋るずわかりたす。
Releases · nexe/nexe · GitHub

 ぀たり、Node.js党郚入りですね、これは。

䜜成。

$ nexe index.js --output ncat-win-x64 --target windows-x64-9.5.0

これで、Windows甚のバむナリが䜜成できたした。

$ ls -lh ncat-win-x64.exe 
-rwxrwxr-x 1 xxxxx xxxxx 22M  2月 12 23:52 ncat-win-x64.exe

確認結果は、省略したす。

芚えおおきたしょう。