LoginSignup
41
41

More than 5 years have passed since last update.

Node.js のための ESLint プラグイン紹介

Last updated at Posted at 2016-12-17

こんにちは。
ESLint のメンテナ1npm-run-all 等 npm-scripts 向け CLI ツールの開発をしている @mysticatea です。
今回は Node.js アドベント カレンダーということで、eslint-plugin-node を紹介したいと思います。

eslint-plugin-node は、Node.js 向けに特化した ESLint の追加ルールを定義しているプラグインです。
ESLint 本体に付属しているルール群 (通称コアルール) にも Node.js に特化したものがありますが、このプラグインのルールは諸事情2によりコアに入れなかったルールたちです。

ESLint 自体についてはこちらの記事をご覧ください。

:cd: インストール

ESLint プラグインですので、npm を利用してインストールします。
ESLint をグローバル (--global) にインストールしている場合は、同じくグローバルへ。ESLint をローカル (--save-dev) にインストールしている場合は、同じくローカルへインストールしてください。

Shell
$ npm install --save-dev eslint eslint-plugin-node
  • Node.js 4.0.0 以降が必要です。
  • ESLint 3.1.0 以降が必要です。

なお、推奨はローカル インストールです。

:wrench: 設定の書き方

.eslintrc.json 等の設定ファイルにプラグインの情報を書く必要があります。

.eslintrc.json_の例
{
    "extends": ["eslint:recommended"],
    "plugins": ["node"],
    "env": {
        "es6": true,
        "node": true
    },
    "rules": {
        "node/exports-style": "error",           //`module.exports`と`exports.*`を混ぜて使うと警告します。
        "node/no-deprecated-api": "error",       //Node.jsの非推奨APIを使用すると警告します。
        "node/no-missing-import": "error",       //`import`構文で存在しないファイルを読もうとすると警告します。
        "node/no-missing-require": "error",      //`require()`で存在しないファイルを読もうとすると警告します。
        "node/no-unpublished-bin": "error",      //CLIのエントリポイントが無視リストに入っていた場合に警告します。
        "node/no-unpublished-import": "error",   //`import`構文で公開後に読めなくなるモジュールを読もうとすると警告します。
        "node/no-unpublished-require": "error",  //`require()`で公開後に読めなくなるモジュールを読もうとすると警告します。
        "node/no-unsupported-features": "error", //指定したNode.jsのバージョンでサポートされていない構文を使おうとすると警告します。
        "node/process-exit-as-throw": "error",   //`process.exit()`の実行パスを修正します。
        "node/shebang": "error",                 //シバンの誤りを指摘します。
    }
}

:bulb: ルール説明

node/exports-style

Node.js でクラスや関数をファイル外にエクスポートするとき、module.exportsexports を混在させて使おうとすると、予期せぬ事態になる可能性があります。

module.exports = function foo() {
    // do something.
}

exports.foo = 1

この時、exports.fooはエクスポートされず消えてしまいます。
こういった事態を抑止するために、module.exportsexports のうち、指定した方だけを利用するように設定することができます。

設定例
{
    "node/exports-style": ["error", "module.exports"],
    //または
    "node/exports-style": ["error", "exports"]
}
例(module.exports)
//✔ GOOD
module.exports = {
    foo: 1,
    bar: 2
}
module.exports.baz = 3

//✘ BAD
exports.qiz = 4
例(exports)
//✔ GOOD
exports.foo = 1
exports.bar = 2
exports.baz = 3

//✘ BAD
module.exports = {}

node/no-deprecated-api

Node.js の非推奨 API を利用しようとすると警告します。

設定例
{
    "node/no-deprecated-api": "error",
}
//✘ BAD
fs.exists(fileName, (b) => {})
const b = new Buffer(text)

非推奨 API には、将来的に削除される予定のものや、セキュリティ リスクのあるもの等が存在します。
ぜひ避けましょう。

警告される API の一覧はこちら

node/no-missing-require

require()式で存在しないファイル/モジュールをインポートしようとすると警告します。
モジュール名やファイルパスの打ち間違えに素早く気がつくことができます。

設定例
{
    "node/no-missing-require": "error",
}
//✘ BAD
const typoFile = require("./typo-file");
const typoModule = require("typo-module");

node/no-missing-import

node/no-missing-requireと同じですが、require()式の代わりにimport構文をチェックします。

:warning: ECMAScript 2015 (ES6) ではファイルの検索ロジックは定義されておらず、Node.js はまだ ES Modules 構文をサポートしていません。そのため、このルールは将来的に変更される可能性があります。

node/no-unpublished-bin

CLI のエントリポイントが無視リストに入っていた場合に警告します。

  • npm publishでモジュールを公開する時、不要なファイルは含めないように設定しておくことが望ましいです。package.jsonfiles フィールドや .npmignore ファイルを利用して、モジュールに含めるファイル・含めないファイルを指定することができます。
  • 各モジュールは package.jsonbin フィールドを使って CLI コマンドを公開することができます (例えば eslint コマンドはこの機能で公開されています)。

さて、npm は package.jsonbin フィールドで指定されているファイルを自動的にモジュールに含めてくれません。そのファイルが files フィールドに含まれていなかったり、.npmignore ファイルに含まれていたりすると除外され、利用者がモジュールをインストールしようとしたときにエラーになります。

package.json_例
{
    "name": "my-module",
    "version": "1.0.0",
    "bin": "bin/index.js",
    "files": ["lib"]        //※binディレクトリを含めていない
}

このようなエラーを事前に見つけて報告してくれます。

node/no-unpublished-require

モジュール公開後に読めなくなるファイルをrequire()式でインポートしようとすると警告します。
このルールは、次のようなシチュエーションを防ぎます。

  • 開発環境では動くが、モジュール公開後に読み込もうとしたファイル・モジュールが存在せずエラーになる
  • あなたのローカル環境では動くが、チームメンバーが clone すると読み込もうとしたファイル・モジュールが存在せずエラーになる

これらを回避するために、次のようなrequire()式を警告します。

  • require()式が公開されるファイル3に書かれている場合
    • インポート対象が公開されないファイル4である
    • インポート対象がpackage.jsondependenciesフィールドに含まれないモジュールである
  • require()式が公開されないファイルに書かれている場合
    • インポート対象がpackage.jsondependencies/devDependencies両フィールドに含まれないモジュールである

babel 等のトランスパイラを利用している場合、ソースコードの位置とトランスパイル後のファイルの位置が異なる可能性があります。この場合は convertPath オプションを使うと適切な警告を生成できます。

node/no-unpublished-import

node/no-unpublished-requireと同じですが、require()式の代わりにimport構文をチェックします。

:warning: ECMAScript 2015 (ES6) ではファイルの検索ロジックは定義されておらず、Node.js はまだ ES Modules 構文をサポートしていません。そのため、このルールは将来的に変更される可能性があります。

node/no-unsupported-features

指定した Node.js のバージョンでサポートされていない ECMAScript 構文を使おうとすると警告します。

例えば、Node.js 4 は (strict モードの外では) let,const,classをサポートしていません。一方で、"use strict"が適切に書かれていればlet,const,classを使うことができます。

  • より詳しくは node.green をチェックしてください。

このルールを使うと、未サポートの構文を使おうとしてしまった場合に素早く気がつくことができます。

どのバージョンを対象にするか? は、package.jsonengines フィールドによって指定します。

package.json_例
{
    "name": "my-module",
    "version": "1.0.0",
    "engines": {
        "node": ">=4.0.0"
    }
}

node/process-exit-as-throw

process.exit()の実行パスを修正します。

実行パス解析を利用した静的検証を改善するメタルールです。
このルール自体は何も警告しませんが、process.exit()式がthrow文と同等に扱われるように実行パス解析を修正することにより、実行パス解析を利用するルールの誤検出を軽減します。

例えば、次のコードにこのメタルールを有効にすることで consistent-return ルールの誤検出が修正されます。

function foo(a) { //※ error 値を返さない実行パスがあります (Expected to return a value at the end of this function.)
    if (a) {
        return "ok"
    } else {
        process.exit(1)
    }
}

node/shebang

シバンの誤りを指摘します。

各モジュールは package.jsonbin フィールドを使って CLI コマンドを公開することができます。
この時、CLI コマンドとして実行される .js ファイルにはシバンを書くことになります。

シバンの例
#!/usr/bin/env node

console.log("hello")

このようにすると、npm はこのファイルを Linux でも Windows でも実行できるように適切にインストールしてくれます。

このルールは、eslint --fix による自動修正でシバンを自動的に追加します。

:pencil: あとがき

エディタに連携させてリアルタイムで警告が表示されるようにしたら、作業がより捗るのではないでしょうか。私見ですが、ESLint と相性が良いエディタはずばり Visual Studio Code です。
ESLint は起動が遅いのですが、Visual Studio CodeNode.js を内蔵しているために ESLint をエディタ内で実行できます。毎回起動しなくて良いので驚くほど軽快です。おすすめ。

それでは、良き開発ライフを :wave:



  1. https://github.com/eslint/eslint/graphs/contributors 

  2. ファイルシステムを使う必要があったり、メンテナンス コストが高かったり 

  3. package.jsonfiles フィールドに含まれていて、かつ .npmignore ファイルに含まれていないファイル 

  4. package.jsonfiles フィールドに含まれていないか、または .npmignore ファイルに含まれているファイル 

41
41
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
41