Node.js で簡単にtcpスキャンする

tcpスキャン


スキャンといいつつ、空いているポートを見つける用途ではありません。
知っているホスト、ポートに対して、生きているかどうかをチェックする用途です。

やりたかったこと:

  • Web Serverが生きているのかどうかをcronなどで定期的にチェックする。
  • HTTPでアクセスを飛ばすと、アクセスログが残ってしまうのでこれは避けたい。
  • とにかく軽く、早いものが良い。
  • ワンライナーでチェックしたい。

そういうライブラリは存在しませんでした。
 

ライブラリが無いなら作れば良いじゃない


というわけで、作りました。

simple-tcpscan
https://www.npmjs.com/package/simple-tcpscan
 

simple-tcpscan


詳しくは上記npmの公式ページに載せていますので、そちらを見ていただければと思います。


const tcpscan = require('simple-tcpscan');
tcpscan.run({'host': 'localhost', 'port': 3000}).then(() => console.log('OK'), () => console.log('NG'));

良い感じで生き死にの処理が書けるようになりました。

riotjs-loaderを3.0.0->4.0.0に変更するとscoped cssがデフォルトになる

riotjs-loaderの実態


別の記事で、riotjs-loaderを 3.0.0 から 4.0.0
に変更すると、真偽値属性が使えるようになると書きましたが、実際は riotjs-loader が依存している riot-compiler が 2.3.22 から 3.0.0 に変更になっただけでした。

つまり、どういうことかというと、自分のプロジェクトでriot v3を使っていたつもりだけど、今まではコンパイラがv2指定だったので、旧バージョンで動作していたということ。
件名の内容に戻ると、scoped css は riot v3 からデフォルトでした。
確かにコンポーネント志向なので、それで正しい動きですが、loaderから依存していたとは思っていませんでした…。

riot-compilerを最新版にする


riot-compiler の最新は現時点で 3.2.4 でした。
riotjs-loader は riot-compiler が dependencies に定義されている点が厄介で、自分のプロジェクトの node_modules\riot-compiler を使用してくれず、 node_modules\riotjs-loader\node_modules\riot-compiler が使用されます。

あまり自由が効かないので、この際自分でloaderを作ってみました。
ついでに、コンパイルオプションも使うつもりはなかったので、差別化としてシンプルなloaderにしました。

riot-simple-loader


riot-simple-loader
https://www.npmjs.com/package/riot-simple-loader

npmモジュールとして公開しているので、良かったら使ってやってください。

使い方は上記の公式npmページと、サンプルをgithubにあげていますので参考にしてください。
https://github.com/nekijak/riot-simple-loader-sample

Unexpected top-level property “ecmaFeatures”

VS Codeでのエラー


少し前に Sublime Text 2 から Visual Studio Code (VS Code) に乗り換えました。
VSCodeが出てすぐに使ったことはあったのですが、当初はどうにも使いづらくてほったらかしにしていました。
最近何気なしにVSCodeを使ってみると、ずいぶんと使いやすくなっている。見た目も良くなっているし、拡張機能もたくさん出ていた。
 
そして、いざ乗り換えようと使っていたら、JavaScriptファイルを編集すると、やたらと「Unexpected top-level property “ecmaFeatures”」が出る。
 
 

エラーが出るのはES Lint


ES-Lintを使っているんですが、どうもエラーはこのプラグインから出ている。
setting.jsonをいじっても、プロジェクトの.eslintrc.jsonをいじっても、全然エラーが鳴りやまない。
ecmaFeaturesの指定を消しても、挙句の果てに全部の設定を消しても出てくるという状態。
 
 

犯人はユーザーディレクトリの .eslintrc


大混乱の中、以下の記述を見付けた。

Maybe this will be helpful for someone: in my case wrong .eslintrc has been located in c:\Users\[username]\ directory (.tslintrc, .coffeelintrc and .csslintrc also been there – i think that these files were created automatically after esint installation).

Looks like eslint loaded it first and failed. After removing this file eslint works fine.

https://github.com/eslint/eslint/issues/8726
 
c:\users\{username}\.eslintrc…だと?
 
確かに存在しており、「ecmaFeatures」がトップレベルでプロパティ定義されていた。
…昔に使ったときに設定されたファイルだろうか。
 
どうやら、ES-Lintがバージョンアップされ、ecmaFeaturesがparserOptionsになったが、このユーザーフォルダ直下のファイルの中身が昔の状態のまま放置されていたことが原因のようだ。
ecmaFeaturesをparserOptionsに書き換えて解決。

1. Remove all ecmaFeatures that are specific to ES6. Replace with ecmaVersion. Things like globalReturn, jsx, and experimental features would remain. This would also be a change in Espree.

2. Introduce sourceType that is “script” by default and can be set to “module”.

3. Move these fields into a new parserOptions field in configuration.

https://github.com/eslint/eslint/issues/4641

webpack v1 から webpack v3 へ移行

npmモジュールの更新


まずはパッケージの更新から行きましょう。ついでに一緒に使用している他のモジュールも上げておくと吉です。
webpackのバージョンに依存していたりするのでね。
一括更新をするための便利なツールがあります。コマンドラインで使うのでグローバルにインストールしておきましょう。

npm install -g npm-check-updates

package.jsonがあるディレクトリまで移動して、ncuと打てばアップデートをチェック、一括ncu -aで、アップデートできます。
部分的に上げたければ、ncu [モジュール]でアップデートしてください。

私はこんな感じでした。

 babel-loader   ^6.2.10  →  ^7.1.1
riotjs-loader ^3.0.0 → ^4.0.0
webpack ^1.14.0 → ^3.4.1
riot ^3.0.7 → ^3.6.1
riot-route ^3.0.2 → ^3.1.2
babel ^6.5.2 → ^6.23.0
babel-core ^6.21.0 → ^6.25.0
concurrently ^3.1.0 → ^3.5.0
lite-server ^2.2.2 → ^2.3.0

その後、npm-check-updatesはpackage.jsonの変更しか行ってくれないので、npm updateを行ってください。

ちなみに、babel-loaderは、以下の通りwebpackに依存しているので注意です。最新に上げておけば問題ありません。

webpack 1.x | babel-loader <= 6.x
webpack 2.x | babel-loader >= 7.x (recommended) (^6.2.10 will also work, but with deprecation warnings)
webpack 3.x | babel-loader >= 7.1

https://github.com/babel/babel-loader
 
 

webpack.config.jsonの更新


モジュールのアップデートが終わったら、とりあえずそのまま起動してみてください。
エラーになるのが正解ですが、普通にwebpack出来てしまった方は、ログをよく見てください。
[0] [BS] File changed: app\scripts\bundle.js
[0] 17.08.07 02:16:13 304 GET /index.html
[1] Hash: dfe23fb8effda57760a2
[1] Version: webpack 1.14.0
[1] Time: 4458ms
[1] Asset Size Chunks Chunk Names
[1] bundle.js 293 kB 0 [emitted] main
[1] bundle.js.map 1.52 MB 0 [emitted] main
[1] + 35 hidden modules

上の例みたいに、Version: webpack 1.14.0 なんて古いものになっていませんか?
もしかしたらローカルじゃなくてグローバルにwebpackを入れていたら、そっちをアップデートするなり消すなりしてみてください。

さて、webpackがエラーになっていると思います。
理由はwebpack.config.jsの記載方法が変更になった為です。(v1->v2)
私はこんな感じに変更になりました。
 
・変更前(webpack.config.js)


const webpack = require('webpack');

module.exports = {
entry: './src/scripts/index.js',
output: {
path: __dirname + '/app/scripts',
filename: 'bundle.js',
publicPath: '/app/',
},
module: {
preLoaders: [
{
test: /\.tag$/,
exclude: /node_modules/,
loader: 'riotjs-loader',
query: {
type: 'babel'
}
}
],
loaders: [
{
test: /\.js$|\.tag$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
devtool: 'source-map',
resolve: {
extensions: ['', '.js', '.tag']
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new webpack.ProvidePlugin({
riot: 'riot'
})
]
};


 
・変更後(webpack.config.babel.js)
import webpack from 'webpack';

export default {
entry: './src/scripts/index.js',
output: {
path: __dirname + '/app/scripts',
filename: 'bundle.js',
publicPath: '/app/',
},
module: {
rules: [
{
enforce: "pre",
test: /\.tag$/,
exclude: /node_modules/,
use: [
{
loader: 'riotjs-loader',
options: {
type: 'none'
}
}
],
},
{
test: /\.(tag|js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {}
}
]
}
]
},
devtool: 'source-map',
resolve: {
extensions: ['*', '.js', '.tag']
},
plugins: [
new webpack.optimize.UglifyJsPlugin({sourceMap: true}),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.ProvidePlugin({
riot: 'riot'
})
]
};


 
ガラリと変わっていますね。ついでに、ES6な書き方に変更しています。
そのため、ファイル名もwebpack.config.jsからwebpack.config.babel.jsに変更しています。
さて、細かいところは公式サイト https://webpack.js.org/guides/migrating/ に任せるとして、
注意すべき点としては、extensionsの'''*'になったことと、
ソースマップを出すなら、UglifyJsPluginにも指定が必要になったことです。両方指定しないとソースマップは出ませんでした。

 
 

うまくいかない場合


ちゃんと設定しているにもかかわらず、エラーになる人は、一度node_modulesフォルダを消してから
npm i
で再度最新版のみをインストールしなおしてみましょう。

Riot.jsで真偽値属性(disabledなど)が「__disabled」になる問題

Riot.jsについて


最近のフロントエンド開発ではReactを使うことが多いですが、私は少数派ですので、「Riot.js」をよく使っています。
検索から来た人は、Riot.jsのことはよく知っているはずなので良いですが、そうでない人はぜひ使ってみてください。
 
 

__disabled問題


Riot.jsでは、disabled=”{ !data.reference[0] }”のように判定式でdisabledが出来る。と公式ガイドに書いてある。

真偽値属性 (checked, selected など) はテンプレート変数がfalse的であれば無視されます。
<input checked={ null }><input> になります。

http://riotjs.com/ja/guide/#真偽値属性

しかし、いざ使おうとすると、何故か「__disabled」になってしまい、全然機能してくれなかった。
どこで「__disabled」になっているかというと、コンパイル時に変換されているのだが、それでも普通はDOM評価時には「disabled」になるはずが、DOM評価されても、「__disabled」となっていた。
 
 

解決策


仕方がないのでdomReady後に無理やり「__disabled」を自前で置き換えて回避してましたが、別件でnpmモジュールを更新していたら、この問題が解決。
riotjs-loaderを3.0.0から4.0.0にしたら、ちゃんと「disabled」になりました。
単純な解決方法だけど、調べた限り全然情報が無かったので、同じようにハマっている人の救いになればと思います。

 
 

余談


これは私だけかもしれませんが、riotjs-loaderを4.0.0にしたら、webpack.config.jsの書き換えが必要でした。
type: 'babel'type: 'none' に変更。

{
enforce: "pre",
test: /\.tag$/,
exclude: /node_modules/,
use: [
{
loader: 'riotjs-loader',
options: {
type: 'none'
}
}
],
}