NuxtデフォルトサーバはCache-Controlできないので注意

まとめ

  • Nuxtは各種のサーバサイドフレームワークと組み合わせられるがNuxtだけでもサーバとして機能する
  • デフォルトで ETag は吐くが Cache-Control は吐かないのでそのまま CDN に食わせるといつまでもリフレッシュされない
    • この影響を受けるのはあくまで vue-router を経由する Page だけ
    • assets に関しては nuxt start で serve している場合は問答無用で max-age は 1 year になる1
  • optional な http response header を追加する middleware はどうもなさげ
    • 他のフレームワークと組み合わせてその middleware を使えば追加できる(Koa で確認済み)

そもそもWebのcacheって

  • private cache と public cache がある
  • CDN は public cache
  • ブラウザは private cache
  • Cache-Control を private にすると CDN は cache できない(したがって、リクエスト数も転送量も減らない)
  • とにかく Nuxt.js は何の情報も追加しない

※ public と private の話は恥ずかしながら CDN切り替え作業における、Web版メルカリの個人情報流出の原因につきまして - Mercari Engineering Blog にあるようにメルカリのやらかしで知りました。(ちなみに Rails はデフォルトで max-age=0, private, must-revalidate を付加するので特に何も考える必要なく CDN はスルーになる。)

CDN側では基本的にmax-ageを推奨してる

基本的には Cache-Control: max-age= を設定するのがよさげ。(Surrogate-Control や s-maxage だったりもしますが、細かいことは置いておく。)

しかし Nuxt.js にはサーバ側の設定の余地がない。(SSR用の MartinLG/nuxt-custom-headers: Nuxt module to add custom headers to SSR rendered pages. というものはある。)

NuxtではETagと304しか考えてない

具体的なコードは以下の部分。

lib/core/middleware/nuxt.js

  // Add ETag header
   if (!error && this.options.render.etag) {
     const etag = generateETag(html, this.options.render.etag)
     if (fresh(req.headers, { etag })) {
       res.statusCode = 304
       res.end()
       return
     }
     res.setHeader('ETag', etag)
   }

nuxt.config.js の render.etag option を見るこの辺以外に cache を考慮しているコードは存在しない。ETag を付けるか付けないかだけ。直接ブラウザとやりとりするならこれだけでも十分かもしれないが CDN を通す場合はそうはいかない。

そこでNode.jsのサーバサイドフレームワークと組み合わせる

nuxt-community/create-nuxt-app: Create Nuxt.js App in seconds.

を使えば Express, Koa, Hapi, … などなどからフレームワークを選べる。これらの middleware で custom header を吐いてあげればおk

具体的に効果的にcacheするには

例えば Koa であれば

を組み合わせて、./server/index.js で

const Koa = require('koa')

const app = new Koa()

require('koa-ctx-cache-control')(app)

app.use(async (ctx, next) => {
  ctx.cacheControl('max-age=0')

こんな感じ。

こうすると pages 以下の component を serve する時には Cache-Control: max-age=0 が付加されたうえで ETag でのキャッシュ内容のチェックが行われるので、origin サーバから直接転送されるものはコンテンツの鮮度チェックはしつつも転送はほぼエッヂサーバから行われるので速い。(はず)

  1. cache buster の効くファイルが生成されている 

DVCSというかcommitについてのメモ

一ヶ月前くらいにとてもひどい commit を見たときに説明用にメモしたものを発掘。

ちなみに現在の環境は中央が Subversion で、非エンジニア含めて TortoiseHG を入れてとりあえず作業がぶっ飛んでしまわないようにしているような状態。

  • DVCS のメリットは svn に commit しなくていいことじゃない
  • 大事なのは svn の commit(というかみんなが読む commit)
    • ここに分かりやすい log があればそれが資産になる
    • 分かりやすい commit とは変更点と変更の意図がちゃんと対応している commit

特に意図が大事。意図が抜けて作業しか書かれていない commit は後から見ても意味不明。commit メッセージに書くのが難しいなら ticket で補うのもあり。1

  • DCVS のメリットは svn に入れる前に commit を失敗できること(push の前に読み直す)

現状の試みは

  • 上のような commit の説明を全員にするのは難しいが、元に戻せる安心感を提供したいから

個人的には git-svn を使っていて、git を使っていると感じるのは rebase しやすいのは良い commit かもなぁという辺り。あとで順番を入れ替えたり message を書き換えたりしやすいし、忘れていたファイルを見つけてもあとで commit して rebase で寄せていくことができる。もちろんこれは作業上のメリットであって読み手のメリットではないけど、一度に複雑な変更を加えてしまった場合はこういう作業はできないので、読み手にとっても一つずつ分かりやすい commit になるんじゃないかなぁと感じている。

  1. 例えば例外的な何かに対応するためにあえてよくないコードに変更している場合があっても、後から見たら分からないからそれを「修正」して壊してしまう可能性も生まれる。そういうのはコードの中にコメントとして残しておかないとまた壊す可能性あるけど、それはまた別の話かな。 

PHP の get_class() は 5 以降引数不要だった

PHP 4 までは絶対にこう書かなきゃいけなかったんだけど、

class Klass() {
  function funktion() {
    get_class( $this );
  }
}

PHP 5 以降はこう書けるようになっていたってこと。

class Klass() {
  function funktion() {
    get_class();
  }
}

ただし、Klass::funktion() と static に呼ばれた場合はこの限りではない。

知らなかった。

PHP: get_class - Manual

class 名を判別して何かするのはオブジェクト指向的にはやっちゃダメなことになっているんだけど、class 名から自動的に別な何かを決定するみたいな処理は案外書きたくなる。その場合にこれが役に立つ。

そうか要らなかったか。なるほどなぁ。

pukiassist なんてのを作ってみました

wtnabe's pukiassist at master - GitHub

最近ちまちま作っていたのをようやく公開できました。

なんでこんなもの作ったの?ってのを含めてほぼ全部 README に書いてあるんですが、要するに

  • PukiWiki を使いつつ、
  • 定期、不定期に
  • その情報をメールなど Wiki 以外でも使いたい

という超個人的な要求に楽に応えられるように作りました。

最近の Wiki なら API や標準の管理ツール(trac-admin みたいなイメージ)で便利に使えると思うのですが、いかんせん PukiWiki は日本を代表する第1世代 Wiki なのでまったく楽な管理ができません。かといって PukiWiki はもうその内部構造の限界に達しているので大幅な機能強化も望めません。

そこで仕方なく

  • 外部から
  • URI の生成と
  • Mechanize でページの生成
  • URI やその内容をメールとかファイルで出力
  • ついでに(でも個人的には超重要)setext 化してしまう

なんてことをやっちゃうツールを作りました。

中身は PHP はほとんど関係なく、

  • Ruby
  • Rake
  • Mechanize
  • Hpricot

に依存しているという、最近の好みが色濃く反映されたツールになっています。

setext 化するツールだけは半年くらい前からあった1のですが、nkf で SJIS/CRLF にするとか、ごちゃごちゃした操作がたくさんあってよく間違えていたのがとても腹立たしく、カッとなってどうにかひとまとまりにしてみました。

gem は作ってないので git clone か Web の download からどうぞ。個人的にはくだらない作業をやっつけることができてとても満足していますが、イマドキそんなに多くの人には響かないような気もします。ま、これだけじゃページ管理とかそういうのには使えませんしね。

  1. あくまで適当ですよ、適当 

prototype.js の Element.update() が頼りにならない

IE の innerHTML を書き換えてもダメなことありますよエラーにハマったので、prototype.js に丸投げしちゃえーと思って Element.update() にしても同じ挙動をする。中を見ると自分のコードと基本的に同じ処理をしている。

うーん。

replace() の方は真面目にやってるっぽいので、自分と同じ element を create してそいつと replace() すればいいのかなと思ったけれど、同じ element を DOM で真面目に create するのは激しく面倒くさい。attributes の扱いが超メンドイ。いやベタ書きなら楽だけど、これを汎用の update() としてまとめるのは結構大変。

うーん。

attributes.keys().each()

みたいに書けるとすごい楽なんだけどね。

[2007-07-10 追記]Ajaxian » MooTools 1.1 Released からすると、実は MooTools ではこの時点で可能だったっぽい。Prototype.js は 1.5.1.1 以降のどこかの時点で DOM Builder が入るらしい。

Emacs で table が書けるのか

今まで知らなかったのかおまえシリーズ第?弾。

table-insert

で新しく表を作ると

+-----+-----+-----+
|     |     |     |
+-----+-----+-----+
|     |     |     |
+-----+-----+-----+
|     |     |     |
+-----+-----+-----+

こんなのができる。この中に文字を書いていくわけだけど、ちゃんと文字列がセルに対して長すぎたら自動でセルが伸びるし tab キーでセル間の移動もできる。うっかり C-d で文字を消してちょっとハマったけど、table として処理させないように切り替えて修正してから改めて table として処理させたらうまくいった。

ちょっと気をつければ結構便利に使えそう。というか今までメールで表を使いたかったときは Wiki 上に書いてそれを w3m で Terminal に文字として表示して、それからそれをコピペとか訳の分からない技を使っていたんだけど、これだけですべて解決するってことに気がついた。なんてこった。

こういうときに、起動時に tips が出るようなアプリならよかったのかなとか思わなくもないけど、あの機能って真っ先に外しちゃうからな。発見があった試しがない。

[追記] もしかして Fink の Emacs 22 じゃなくて CarbonEmacs に移行せよという天啓か?

まだまだ UTF-8 は悩ましい、のか?

Fink の screen はまだ 4.0.2 のままで、これにはあれこれバグが潜んでいるらしい。LANG を UTF-8 にしたのだが、screen 上でだけ画面がずれる。えーと、文字がずれると書いた方がいいのかな? カーソル位置の計算や文字の表示位置の計算がずれているので編集している文字がどれなのか分からないとか、表示が乱れ過ぎて使いものにならないといった現象が起きる。で、このずれはアプリによってマチマチ1だったりするので screen だけの問題なのかどうかがよく分からなかったりする。

うーん。まだ早かったか?

terminal が euc-jp のままだとせっかく utf-8 の編集ができても表示できない文字がいっぱい出てきてしまうので嬉しくないのだが、utf-8 の出力はまだうまく対応できないツールがいろいろあるみたいだ。Fedora や ports で最新版をガンガン使っていきます、みたいな世界ならそれなりに快適に過ごせそうな気がするんだけど、Fink は Debian 系だし、そういうわけには行かなそう。ドキュメントの充実ぶりはものすごくありがたいんだけどねぇ。

MacPorts に鞍替えか? どれどれパッケージは増えたのかな?

……。

どこ見りゃいいんだ。MacPorts になってからサイトが分かりにくいんだよなぁ。Trac のカスタマイズがすごいのは分かったからなんとかしてくれ。とりあえず Browse Source する。なんかものすごい増えたような気が。見慣れた本家 ports のような分類なので欲しいものがどこにあるのかはだいたい分かる。ふむふむ。問題の screen は 4.0.3 が入ってるな。しかしいつの間にこんなに増えたの? もしかして Intel 化の恩恵? だとすると、

これって PPC でテストされてるかどうか分かんなかったりする? てか Panther って対象外?

うぉう。こえー。どうすべ。もう少し調べてみっか。

[追記] 結局 screen の設定と w3m の設定を見直したらかなりまともに動くようになったのでこれでいくことにした。w3m の方でエンティティを ASCII に置き換えるようにしていたのがダメだったのかなーという感じがしている。あとは文字幅の変わる置換とかその辺の設定かな。あんまり細かく切り分けてないけど。

MacPorts については、一応 MacPorts 自体は 10.3 用のバイナリがあるので少し安心しているんだけど、まぁおいおいってことで。

  1. 今のところいちばんヒドイのは w3m 0.5.1 

JSDoc 1.9.9.2 を使ってみて大事だなと思ったこと

JSDoc をやっと真面目に使ってみた。実際に使ってみてハマったところを取り上げていく。基本的な使い方は自分で調べるなり試行錯誤するべし。

なお、以下はバージョン 1.9.9.2 について書いている。時間の経過とともにおかしな内容になっていく可能性大なので注意されたし。あと日本語のコメントは試してないんでどうなるか知らない。

正しく書く

値を取る attribute で値を書いてない1など、構文的に正しくないときに、よく HTML::Template の方でエラーを吐いて止まる。phpDocumentor みたいにエラーレポートは作ってくれないし、HTML::Template 段階でのエラーってことは当然パーサが吐いてるわけはなく、どこの何の記述(あるいは記述不足)がエラーなのかさっぱり分からないので、あとでまとめてドキュメントを生成するのではなく、こまめに作るようにした方がよさげ。

書き方は JSDoc のサイトにもあるけど、細かいものは JavaDoc のものを探してくるといい感じかも。

コンストラクタの書き方

きちっと対応しているのは

function Object() {
  ..
}

のみっぽい。

var Object = new function() {
  return function() {
  };
};

はコンストラクタは解釈できるが、中のメンバ変数(JSDoc の出力では Field ってやつ)が解釈できなかった。

あとこのコンストラクタ関数のコメントの中に @constructor を書いておいた方がよい。書かないと Field の解釈に失敗しやすいみたい。

フィールド(メンバ変数)の書き方

JavaScript 的には単にコンストラクタで初期化されるプロパティなんだと思うんだけど、まぁ要するに

function Constructor() {
  this.prop1 = 'foo';
  this.prop2 = undefind;
  this.prop3;
}

のところ。中身のない状態で初期化するのは 3 ではなく 2 の方法、つまり明示的に undefined をセットする方法が正しい。JSDoc 的には。

明示してないものは Field Summary にも当然 Field Detail にも現れない。

メソッドにも @type を

@return に型を書いてもメソッドの型としては認識してくれない。ちょっと面倒だけど、

/**
 * @type   boolean
 * @return boolean
 */
method: function() {
}

にしないといけない。まぁ気にしなきゃいいって話もあるかもしんないけど、それだと Method Summary のところで戻り値の型が分からないのよね。

うっかり : が書けない。

/**
 * summary
 *
 * detail: foo bar hoge
 */
method: function() {
}

てなことをすると

detail: foo

の部分が

Class.prototype.detail = foo;

に展開され、結果として

Class.prototype.detail = foo;bar hoge

になる。

※ ただ、必ずなるかというとそうでない場合もある。よく分からん。

組み込みオブジェクトの拡張には @addon

@member を書くと二重に出力されるのでうざい。例えば以下のような感じ。

/**
 * @addon
 */
Array.prototype.include = function() {
}

ただ、ないとエラーになっていたような気がしていたのに、なくてもそのまま通ったりもする。あっれ?

メソッドの書き方

できないと思っていたが、

Class.prototype = {
  method: function() {
  }
}

の書き方も

Class.prototype.method = function() {
}

の書き方も両方いけた。

夜中は嘘書いてごめんなさい。

感想として

JavaScript の構文解釈の精度は意外と悪くないと言ったら失礼だけど、自分の書き方だとほぼ思った通りに解釈してくれる。ただそのうえでコメントの記述がその後押しをしていて、正しくコメント付けするとよりよいドキュメントが生成できる、という感じ。まぁコメント付けは正しい方がいいのは言うまでもないことなんだけど、phpDocumentor のエラーレポートみたいなものは期待できないので、若干人間の側の負荷が高いかなって気はする。

あと、こまめにドキュメント生成しろって辺りか。複数のファイルを一気に処理するとどこでおかしなことになってるのかなかなか分からないんで。

最後に、これは使えると思う。

  1. 例えば @return のあとを空にしちゃうとか 

scp って帯域制限できるようになってたんだ

Tools: OpenSSH 3.6

によると 3.6 から -l オプションで指定することができるようになったと。実際使うときは単位が kbits/s なので注意すること

吉野家豚丼は意外とうまい

豚丼の登場は知っていたが、牛丼消滅以来すっかり吉野家から足が遠のいていた。しかし一念発起(てことはないが)して今日行ってみた。行ってみたら50円引きでラッキー。320円の豚丼にみそ汁をつけても320円。

これがサッパリした豚肉で意外にというか個人的にはかなりの好印象。もともと豚肉が好きな方なのかもしれないが、牛丼の濃い味付けよりもむしろ好きかもしれない。今回は卵などのオプションをつけなかったが、牛丼が復活しても豚丼+卵辺りが自分の中で定番になるかもしれないくらいにうまいと感じた。

帰り際に角煮きのこ丼なんてものも発見!なんだそりゃうまそうだぞ、おい。マーボー丼だってオレは好きだぞ。まいったな、おい。

scponly で ssh の設定を細かくいじりたかった → Zebedee 勉強しろってことらしい

まぁ shell なんだからそんなに様々なことができる方が変なんだけど、やっぱ ssh は自由すぎてこえーな。chroot はともかく、port forward を許可するユーザーと許可しないユーザー、許可するポート、とか細かく設定できると嬉しいんだが。1

OpenBSD 的にはそんなものは必要ないものなのかな? port forward の制限は(Remote Forward を除いて)Zebedee で手軽にできるが、一部の port forward とデータ転送の両方を許可したい、でも shell の解放はいや、って場合はどうしたらいいのかなぁ。

なんでこんなことを思うかというと、scponly は対話的 shell での作業はできないが、セッションは維持できるので port forward が可能なのである。まぁ今はそれを逆に便利に使わせてもらっているんだけど、そうさせたくないユーザもいる。でも ssh はグループやユーザー別に細かい設定ができるわけじゃない。

もう一つの方法は .bash_profile(など)にいきなり exit を書いておく。これは目的のセッションが終了すればたぶん問答無用で切れるので、ファイル転送が終わったら切れるとか、そういう都合のいい動きをしてくれないだろうか。

ユーザーのアクセスできる資源を細かくコントロールしたいならやっぱフロントエンドに立つサーバとそうでないサーバを分けるべきか。そういうことだろうなぁ。ファイル転送を受け付けるサーバだけ分ける。これがよさげだ。

それかファイル転送はもう ssl + WebDAV 限定か。あーそれが楽なのか。と、いうことは、やっぱ port forward 目的の ssh はやめて可能な限り Zebedee で実現するのがいいんだな。なるほど。

あ。一つは port forwarder をやめて Zebedee にできそうな気がしてきた。もう一つも Zebedee の逆向き接続ができれば不要だ。結局ここにたどり着いたか。。。

Zebedee 逆流できた

以前できないできないと思っていたのは VNC の loopback 接続を許可していなかったからだった。(実験を VNC 以外それっぽいサービスの動いていない Windows でやっていたので。)

今回 RealVNC から TightVNC に変更して確認。まだ鍵認証を試していないので、それを試して、listen port がどのように設定の影響を受けるのかよく確認して記事を書こう。とりあえず port forward は Zebedee 一本でイケるってことは確実になった。嬉しい。

  1. OpenSSH 4.4 以降は PermitOpen で port の制限を、4.7 以降は Match によってユーザーなどの制限を行うことができるようになっている。 

Web家計簿 MoBo にバグ発見

ついでだから開発にコミットしてしまおう。帰ってからの宿題。

バグじゃなかった

勢いこんで ML に入ったが、再現性の確認をしていたら、少しもバグではなかった。ただの勘違いだった。何やってんだ、おれは。。。

tracker プラグイン別解

思ったんだけど、これ $sciprt = で PHP の機能をフル稼働してホスト名とかポート番号の補完をうまいことやればいいんじゃねーか?

InterWikiName はともかく、プラグインそのものをいじるのを毎回やるのはうざいんだよなぁ。

goods Wiki の無限地獄原因判明

1行に2つ変数を展開しているページをリストアップするときに無限地獄に落ちていた。具体的には :config/tracker/digicam/page の

*[maker] [model]

フォームへ戻る→ [_refer]

|~機種|[model]|

の1行目。これを

*[model]

だけにして対処。よーしこれであれこれチェックしやすくなってきた。

ビール券販売停止

from asahi.com

うぎゃぁ。まだなんぼか持ってるんだよなぁ。早めに使わないと。でも、年内ってのは販売停止なだけで利用は停止じゃないんだよな。利用停止期限はいつだ?

eclipse ミラー

ring が始めましたね。

About

例によって個人のなんちゃらです