のらねこの気まま暮らし

技術系だけど、Qiita向きではないポエムとかを書くめったに更新されないヤツ

grunt-contrib-connectのmiddlewareの順序による挙動について

grunt-contrib-connectgrunt-connect-proxystubcellを設定したが POSTDELETE のリクエストが method not allowed で弾かれてしまって嵌ったのでメモ。

middlewareの設定順序が不適切

最初に正しい方法。middlewaresの先頭にproxyを挟む必要がある。

connect: {
  server: {
    options: {
      base: ["htdocs"],
      middleware: (connect, options, middlewares) ->
        middlewares.unshift(require("grunt-connect-proxy/lib/utils").proxyRequest);
        return middlewares;
      }
    },
    proxies: [
       // ... proxyの設定 ...
    ]
  }
}

middlewares.unshiftする必要性

引数で middlewares を受け取った時、connect.staticconnect.directoryIndex のmiddlewareがデフォルトで設定され、それらは GET , HEAD, OPTIONS のMethodしか許可していないため。

今回の僕のような POSTDELETE のようなRESTな感じのリクエストを投げたい場合にこれらよりあとにmiddlewareを設定してしまうとプロキシに到達する前に method not allowed となる。

middlewares.unshift のように先頭に middlewareを追加するか、 引数で middlewares を取らず、空の配列から新しくmiddlewaresを生成してしまうかするのが良いと思う。

背景

grunt-contrib-connect で静的ファイル(htmlとかjsとか)を配信し、RESTFulなAPIサーバーのモックとして stubcell を立てて、 grunt-connect-proxy でプロキシしてアプリ開発を行っていた。

が、proxyしているRESTFulなサーバに DELETEPOST を投げても 405 のレスポンスが返ってくる。

その時のGruntfileはこんな感じで、middlewaresにproxyRequestをpushしていた。 この時、middlewaresの配列が空の配列であるという錯覚が僕の3時間を無駄にした。

connect: {
  server: {
    options: {
      base: ["htdocs"],
      middleware: (connect, options, middlewares) ->
        middlewares.push(require("grunt-connect-proxy/lib/utils").proxyRequest);
        return middlewares;
      }
    },
    proxies: [
       // ... proxyの設定 ...
    ]
  }
}

調べた過程

ChromeのdevToolsを見ると、allowのヘッダが某かで付与されていた。 とりあえずmiddlewaresにallowを突っ込むヘッダを付与してみる。

moddleware.push(function (req, res, next) {
  res.setHeader('allow', 'GET, DELETE');
  next();
});

しかし通らない。

stubcellやproxiesのソースを読み、console.logを直で仕込みどこまでリクエストが伝播しているのかを調べているうちに、そもそも grunt-connect-proxy にリクエストが届いていないことが判明。

grunt-contrib-connect の某かで405を投げてるっぽい。 grunt-contrib-connect の中の node-connect のコードを読むが、 405 を投げている箇所が見当たらない。

検討がまったくつかないけれど、とりあえず障碍の範囲は絞れたので、grunt-contrib-connect の nextの実装に console.log をかまして様子を見る。

その過程で、どうやら、middlewareがproxyの前に幾つか処理されているらしいことがわかる。

gruntfile上で console.log(middleware) するとすでに配列にstaticとdirectoryIndexのmiddlewareが入っているではないか!

push辞めてunshiftして解決。

grunt-init で jquery-plugin を作って travisCIに上げるまでのメモ

準備

以下をインストール

$ npm install -g grunt-init
$ git clone https://github.com/gruntjs/grunt-init-jquery.git ~/.grunt-init/jquery

プロジェクトの作成

grunt-init jqueryをプロジェクトディレクトリで走らせるとplugin用のアセットを生成してくれる。 なお、既にルートディレクトリにpackage.jsonが存在するとエラーになる模。様l

$ mkdir eg-grunt-init
$ cd eg-grunt-init
$ grunt-init jquery

生成されたコード

.
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE-MIT
├── README.md
├── eg-grunt-init.jquery.json
├── libs
│   ├── jquery
│   │   └── jquery.js
│   ├── jquery-loader.js
│   └── qunit
│       ├── qunit.css
│       └── qunit.js
├── package.json
├── src
│   └── eg-grunt-init.js
└── test
    ├── eg-grunt-init.html
    └── eg-grunt-init_test.js

とりあえず動かす

なにもオリジナルなコードは書かずに、そのまま動かす。

$ npm install
$ npm test

すでにもうテストが動くという親切っぷり。 テストはqunitを使っている。そのまま使うか、mochaでも入れるか、は各自の自由なのかな。 また、jshintも設定されてるので、これに従えばjqueryの規約に沿ったコードになる様子。

サンプルコードは2indentで書かれているが、jshint的には特に規定はなく、そのまま4indentで書いてしまったが、好きに設定して良いのかもしれない。 まあ、minifyするか

pluginを実装する

かく。 テスト通らせる

travisCIに上げる

ここでちょっとあれこれしたのでメモ。

  • grunt-cliをinstallする
    • デフォルトではgrunt-cliが無いので、npm install --save-dev grunt-cliした
  • vesionかえる
    • package.jsonに定義されているversionが0.0.0-ignoredだったので、npmとれなかった気配
    • versionやnpmの流儀についてはちゃんと調べずここまで来ているので、なんか勘違いしてるきもするけど、とりあえず動いたので。

おしまい

grunt-initはべんりだなーって思った。 でもqunitは使いにくい。

あ、あと。jquery-formize on Githubというpluginを書きました。form要素にデータ入れたりデータ取ったりエラーのスタイル当てるのにいい感じにしてくれる子がほしかった。 この子を書くときにgrunt-initに入門したので、色々勉強になった。まる。