ESLint で「is not defined? たりめーだ」なケースをだまくらかす

順序だててドキュメントを順に読んでいけや、そもそも、つー話ではある。

アタシみたいに「まずはテキトーに始めてみる」のは(多分)良くない。ドキュメントの指示通りに始めてれば、こんな話は出てこない。と言いたくなるほど ESLint のドキュメントは親切だ。後でちゃんと読み直すと、今のところ「読んでもなおわからん」ことは一つもない。すはらしい。


何の話だ、てのは。

まぁ色んな始め方があるんだろうけれど、ワタシの「ESLint 対象コードを含むアプリケーション全体」というのはだいたいこんな管理をしている:

  1. ブラウザに読み込むことになる html 全体となる「テンプレート」
    • <script type='text/javascript' src="...">で取り込む以外のスクリプトを、これ自身には含まない
    • ただし「プレイスホルダー」だけが埋め込んであって、ここに「自分のスクリプト」が取り込まれる
  2. スクリプト1: ユーザインターフェイス(ビュー)に強く依存したコード
    • いずれやりたいがまだ mocha でのテスト対象に出来ていない
  3. スクリプト2: ビューに依存せずテストがしやすいコード(ページパーサ等)
    • node.js で簡単に動かせて、mocha でのテストが出来ている

「テンプレート」なんてかっちょいい言い方をしてるが、面倒だったので Python の最も原始的な「%s」で埋め込んでるだけの話。まぁ管理しづらくなってきたら高等なテンプレートエンジンを使ってもいいかなと思うが、まだそこまでの必要性は感じてないのでやってない。

「スクリプト2」は最終的にはちゃんと「javascript ファイルとして <script type='text/javascript' src="..."> で取り込める形にする」予定ではあるものの、今のところは「いいファイル名も思いついてないし、色んな機能の分割のポリシー等々もろもろ決めてないので」、上で説明した「%s」に直接埋め込むようにしてる。

「スクリプト1」についても「<script type='text/javascript' src="..."> で取り込める形にする」かどうかはそもそも微妙で、別にずっと本体の html に埋め込みの script のままでもええんちゃうか、て気分なので、多分このまま。

で、そういう構造なので、「is not defined? たりめーだ」なものがどうしてもいくつか出てきてしまう。つまり ESLint が露知らぬところで「スクリプト1」が「スクリプト2」に依存しているので。それだけでなく「jQuery」「$」、あとワタシのヤツだと「cytoscape」が「is not dedined」に「ESLint には」見えてしまう。繰り返すけど「そういうアホな構造なので」ね。ESLint には何の罪もないんだよ。


まず「jQuery, $」は、ワタシの「Get Started」がそもそもちょっと雑だったのと、「eslint --init」でもしかしたら選びミスしたかもしんない。「browser: true」は気付いていたんだけれど、Specifying Environments にしっかり「jquery」が入ってた。ので例えばワタシの .eslintrc.js ではこんな感じ:

1 module.exports = {
2     "env": {
3         "browser": true,
4         "jquery": true,
5         "es6": true
6     },
7     // ...
8 };

で、ワタシの例での「cytoscape」。これはつまり、「アホな構造で管理してる」と説明した「html テンプレート」では当然 <script type='text/javascript' src="..."> の形で取り込んでいるわけなので、ほんとに「eslint xxx.js」として各々スクリプトを渡してるだけでは永遠に ESLint が知らぬ世界なので「見えるはずがない」、と。こういうのは Specifying Globals れよ、だってさ。例えば:

 1 module.exports = {
 2     "env": {
 3         "browser": true,
 4         "jquery": true,
 5         "es6": true
 6     },
 7     "globals": {
 8         "cytoscape": "__dummy__",
 9     },
10     // ...
11 };

で、「ワタシのスクリプト1がスクリプト2に依存してる件」に関しては、この cytoscape と同じ流儀でやっちゃうと「あっちを立てればこっちが立たない」てことになっちゃう(片や未定義となり片や二重定義になる)ので、これは「同じことをコマンドラインから」やることにする。ワタシはそもそも上で説明した「テンプレートに埋め込む」ということをしているので、そうやって「js スクリプトを生成して、eslint かけて、mocha でテストする」という一連の流れをシェルスクリプトにしてる。だいたいこんな感じ:

1 #! /bin/sh
2 # -*- coding: utf-8 -*-
3 py -2 build_page.py && (
4     eslint _page_parsers_code.js > _page_parsers_code.js.eslint
5     eslint _cv_relations_ui.js \
6         --global="MalPageParser: 'dummy', MalUrlBuilder: 'dummy', AjaxHtmlGetter: 'dummy', Interval: 'dummy'" \
7         > _cv_relations_ui.js.eslint
8     mocha page_parse.js --reporter landing
9 )

ちょっとややこしいが「build_page.py」は、「node.js、mocha で動かせるようにコードを補ったコードを生成」してて、その「node.js、mocha で動かせるようにコードを補ったコードを生成」前の未加工のものが _page_parsers_code.js で、mocha のテスト実装が入ってるのが page_parse.js。で、今回の本題の話はこれ:

1     eslint _cv_relations_ui.js \
2         --global="MalPageParser: 'dummy', MalUrlBuilder: 'dummy', AjaxHtmlGetter: 'dummy', Interval: 'dummy'"

この4つの「class のようなもの」が「スクリプト1 (_cv_relations_ui.js)」内では未定義なので、「なんでもいいからいることにしてまえ(dummy)」としてる、てこと。

まぁ「jquery, $」の件はともかく、ほかのやつはこの措置をしなくてもトータルで10程度のエラーにしかならないので、「気にしない」という手もないでもないんだけれど、ただ元々「grep -v」で「jQuery, $」の方は無理やりフィルタして取り除いてて、「それをやめたいなぁ」が動機だったので、はっきりいって「ついで」。なんであれ邪魔は邪魔なわけだし。


それよりもな、「このアホな管理の仕方」を早くなんとかしたいんだけどねぇ。少なくとも「とてつもなくアホ」から「結構アホ」くらいには改善したいもんである。