CasperJSを拡張したライブラリをローカルに置こうとして苦戦した記録
CasperJSを使っていて大変苦労したのでその記録。
やりたかったコト
CasperJSを継承した独自拡張のライブラリを複数のファイルでrequireして個別にプログラムを実行したかった。
grunt-casperのようなライブラリをから使う場合と、単体のファイルをcasperjs
コマンドで実行する二通りの用途を想定していた。
継承
継承自体は簡単に可能。 coffee-scriptを使っているならなおのこと。
Casper = require("casper").Casepr class MyCasper extends Casper start: -> console.log "start my casper!" super
外部ファイルとしてrequireする
辛かったのはここから。
上記のクラスをmodule.exports
で吐き出し、他のファイルからrequire
で参照しようとした。
"use strict" Casper = require("casper").Casper class MyCasper extends Casper start: -> console.log "start my casper!!" super module.exports = MyCasper
"use strict" MyCasper = require("my-casper.coffee") casper = new Casper() casper.start "https://www.google.com/", -> @echo "open #{ @getTitle() }" casper.run()
上記のようなサンプルコードを用意して、コマンドを叩く。
vimshell% casperjs runner.coffee Error: Cannot find module 'casper' phantomjs://bootstrap.js:289 phantomjs://bootstrap.js:254 in require /home/mizuki/project/casper-sample/my-casper.coffee:8 /home/mizuki/project/casper-sample/my-casper.coffee:29 /home/mizuki/project/casper-sample/my-casper.coffee:30 ReferenceError: Can't find variable: Casper runner.coffee:8 runner.coffee:16
Cannot find module 'casper'
requireしようととしているcasperが見つからない。
bootstrap.js:289
このファイルをまず見に行く。
情報がほとんど無いので、エスパーで回答すると、
- casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
どう見てもずれている・・・
ここからPrintDebugタイムに突入し以下の情報を仕入れた。
- PhantomJSの
require
にpatchを当てている - casperなる(CasperJSに関連した)node_modulesはなく、
patchedRequire
の中でCasperJSのmodules
のディレクトリを見に行くようにになっている
patchedRequire
のコード
casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
その中で呼ばれているcasperBuiltinPath
メソッドがcasperの内部のmodulesさんからcasper
を探してきている。
function casperBuiltinPath(path) { return resolveFile(path, fs.pathJoin(phantom.casperPath, 'modules')); }
さて、ここらへんにprintデバッグのコードを埋め込むわけだが端的に結論を行ってしまうと、 呼 ば れ て い な いのだ。
require先のライブラリの中ではcasperjsのpatchが当たらないらしい。 どういう仕組でそうなっているのかは、PhantomJSも含めて周辺コードを追跡しないといけないので、ひとまずはこの仕組を諦めることにした。
いずれリベンジしたいところである。
余談
ローカルパスの検索
phantom.casperScriptBaseDir
もしくはfs.workingDirectory
を基準にrequire
に指定したパスを走査する。
function localModulePath(path) { return resolveFile(path, phantom.casperScriptBaseDir || fs.workingDirectory); }
casperScriptBaseDirはどこで設定されるのかというと、
- casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
- casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
コマンドラインのtest
サブコマンドを除く第一パラメーターである。
すなわち、下記のrunner.coffee
のディレクトリである。
vimshell% casperjs runner.coffee
今回示した例ならさほど問題はないが、src/runner.coffee
の様なケースだと、若干面倒になる。
これはnodeJSも同様だが、相対パスと実行ディレクトリを意識しなくてはならない。
casperScriptBaseDir
を書き換えることでこの問題を回避することもできるがオススメしない。
Nodeであれば、NODE_PATHを追加することで、そのディレクトリをnode_modulesの走査対象とするが、CasperJSについてはそこまで確認していない。
この辺りのソースを追っていけばヒントは得られそう。 casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
ともあれ、非常に苦戦したので、とりあえずその調査の記録だった。