アイコンリサイズ用のnpmパッケージを作ってみた その2

ChainZ(クリエイター)
いろいろやってます。

前回の記事ではiconcというパッケージの基本機能を実装しましたが、今回の記事はそれをコマンドツールにしてみます。

前回と同じようにテストを書いてみます:

// test/index.test.js
// spawnを使ってコマンドを発行する
const spawn = require('child_process').spawn;
...
it('iconc command', (done) => {
// サンドボックスパス ./test/sandbox
const sandbox = path.join(__dirname, './sandbox');
// サンドボックスは毎回リセット
fs.removeSync(sandbox);
fs.ensureDirSync(sandbox);
// ../bin/iconc -f ../file/_icon_.png -d ./gen -s icon1:w100, icon2:w120, icon:p150というコマンドになります。
// -f 対象ファイル
// -d 生成したファイルの保存先
// -s リサイズ設定
// 前回の実装だと、-s引数ファイルのパス、JSON内容、yaml内容やJSコードのいずれかに対応していますが、さすがにコマンドラインでJSONとyaml書くのが大変なので、
// <ファイル名>:<リサイズタイプ(pかw)><サイズ>, ...というフォーマットにします
const child = spawn(path.join(__dirname, '../bin/iconc'), ['-f', '../file/_icon_.png', '-d', './gen', '-s', 'icon1:w100, icon2:w120, icon:p150'], {
cwd: sandbox,
stdio: 'inherit'
});
// 終了時に実行結果を検証。
child.on('close', () => {
Object.keys({
icon1: { w: 100 },
icon2: { w: 120 },
icon: { p: 150 }
}).forEach(name => {
fs.existsSync(path.join(sandbox, `gen/${name}.png`)).should.be.true();
});
done();
});
});
...

そして、./bin/iconcを実装します:

引数を取得するyargsを使用しています:npm install yargs --saveで追加します

#!/usr/bin/env node
const path = require('path');
const argv = require('yargs').argv;
const Iconc = require('../');
const async = require('async');
const fs = require('fs');
const colors = require('colors');
const assert = require('assert');
const SPACE = 8;
const NODE_ENV = process.env.NODE_ENV;
if (NODE_ENV == 'testing') {
console.log = function() {};
}
async.waterfall([
(done) => {
var opt = opt || {};
// コマンドラインから渡された引数をアサインする
opt.file = argv.f || argv.file || opt.file;
opt.dest = argv.d || argv.dest || opt.dest;
opt.schema = argv.s || argv.schema || opt.schema;
// メッセージ表示
console.log(`${'-'.repeat(SPACE-2)}> Source:`.blue, path.join(process.cwd(), opt.file));
console.log(`${'-'.repeat(SPACE-2)}> Target:`.green, path.join(process.cwd(), opt.dest));
console.log('');
try {
const iconc = new Iconc(opt);
iconc.run(done);
} catch (e) {
return done(e);
}
}
], err => {
if (err) return console.error(err.message.red);
});

npm testコマンドを叩くと:

もし実行権限のエラーが表示されたら、chmod +x ./bin/iconcで実行権限を与えてください。

やはりエラーになります。schemaはコマンドライン専用のフォーマットにまだ対応していないので、実装します:

// ./index.js
...
// schemaがstringタイプの場合はファイルパスと認識し、読み込みの試しをする
if (typeof(self.schema) == 'string') {
// コマンドライン専用フォーマットを優先
if (/([^\:]+)\:(w|p)\d+\,?\s?/g.test(self.schema)){
const found = self.schema.split(',').map(i => i.trim());
// schemaを既存フォーマットに変換
self.schema = found.reduce((a, b) => {
const f = b.match(/([^\:]+)\:(w|p)(\d+)/);
a[f[1]] = {};
a[f[1]][f[2]] = parseInt(f[3]);
return a;
}, {});
return done();
}
return fs.exists(self.schema, exists => {
if (!exists) {
return done(new Error(`schema: ${self.schema} not found`));
}
...

もう一度npm testすると:

通りました!次は、今のコマンドをnpmのグローバルbinに入れてみます。package.jsonを開いて、キーを追加:

...,
"bin": "bin/iconc",
...

で、cdでプロジェクトのルートに移動し、npm install . -gを実行すると、iconcというツールはグロバールにインストールされ、iconcだけで呼び出せるようになりました。

例えば:

iconc -f ./src_icon.png -d . -s some_img:w100

実行結果は:

あれ?何のメッセージも表示されていません。実際ファイルは作成されています。確かに、ファイル処理の進捗の情報はどこにも出してないので、ちょっと怖いんですね。 今度はEventEmitterというクラスを継承してメッセージを出してみます。いよいよツールとして成立する形になりつつあるので、次回頑張ります〜

次の記事:http://befool.co.jp/blog/chainzhang/creating-npm-package-3/