まとめ
- 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を推奨してる
- CloudFront エッジキャッシュにオブジェクトを保持する時間の指定(有効期限切れ) - Amazon CloudFront
- チュートリアル: キャッシュ制御 - チュートリアル | Fastly Help Guides
基本的には 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 であれば
- Koa - next generation web framework for node.js
- koajs/ctx-cache-control: Augment Koa with ctx.cacheControl(maxAge)
を組み合わせて、./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 サーバから直接転送されるものはコンテンツの鮮度チェックはしつつも転送はほぼエッヂサーバから行われるので速い。(はず)
cache buster の効くファイルが生成されている ↩
一ヶ月前くらいにとてもひどい 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 になるんじゃないかなぁと感じている。
例えば例外的な何かに対応するためにあえてよくないコードに変更している場合があっても、後から見たら分からないからそれを「修正」して壊してしまう可能性も生まれる。そういうのはコードの中にコメントとして残しておかないとまた壊す可能性あるけど、それはまた別の話かな。 ↩
PHP 4 までは絶対にこう書かなきゃいけなかったんだけど、
class Klass() {
function funktion() {
get_class( $this );
}
}
PHP 5 以降はこう書けるようになっていたってこと。
class Klass() {
function funktion() {
get_class();
}
}
ただし、Klass::funktion() と static に呼ばれた場合はこの限りではない。
知らなかった。
class 名を判別して何かするのはオブジェクト指向的にはやっちゃダメなことになっているんだけど、class 名から自動的に別な何かを決定するみたいな処理は案外書きたくなる。その場合にこれが役に立つ。
そうか要らなかったか。なるほどなぁ。
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 からどうぞ。個人的にはくだらない作業をやっつけることができてとても満足していますが、イマドキそんなに多くの人には響かないような気もします。ま、これだけじゃページ管理とかそういうのには使えませんしね。
あくまで適当ですよ、適当 ↩
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 が入るらしい。
今まで知らなかったのかおまえシリーズ第?弾。
table-insert
で新しく表を作ると
+-----+-----+-----+
| | | |
+-----+-----+-----+
| | | |
+-----+-----+-----+
| | | |
+-----+-----+-----+
こんなのができる。この中に文字を書いていくわけだけど、ちゃんと文字列がセルに対して長すぎたら自動でセルが伸びるし tab キーでセル間の移動もできる。うっかり C-d で文字を消してちょっとハマったけど、table として処理させないように切り替えて修正してから改めて table として処理させたらうまくいった。
ちょっと気をつければ結構便利に使えそう。というか今までメールで表を使いたかったときは Wiki 上に書いてそれを w3m で Terminal に文字として表示して、それからそれをコピペとか訳の分からない技を使っていたんだけど、これだけですべて解決するってことに気がついた。なんてこった。
こういうときに、起動時に tips が出るようなアプリならよかったのかなとか思わなくもないけど、あの機能って真っ先に外しちゃうからな。発見があった試しがない。
[追記] もしかして Fink の Emacs 22 じゃなくて CarbonEmacs に移行せよという天啓か?
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 用のバイナリがあるので少し安心しているんだけど、まぁおいおいってことで。
今のところいちばんヒドイのは w3m 0.5.1 ↩
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 のエラーレポートみたいなものは期待できないので、若干人間の側の負荷が高いかなって気はする。
あと、こまめにドキュメント生成しろって辺りか。複数のファイルを一気に処理するとどこでおかしなことになってるのかなかなか分からないんで。
最後に、これは使えると思う。
例えば @return のあとを空にしちゃうとか ↩
によると 3.6 から -l オプションで指定することができるようになったと。実際使うときは単位が kbits/s なので注意すること。
豚丼の登場は知っていたが、牛丼消滅以来すっかり吉野家から足が遠のいていた。しかし一念発起(てことはないが)して今日行ってみた。行ってみたら50円引きでラッキー。320円の豚丼にみそ汁をつけても320円。
これがサッパリした豚肉で意外にというか個人的にはかなりの好印象。もともと豚肉が好きな方なのかもしれないが、牛丼の濃い味付けよりもむしろ好きかもしれない。今回は卵などのオプションをつけなかったが、牛丼が復活しても豚丼+卵辺りが自分の中で定番になるかもしれないくらいにうまいと感じた。
帰り際に角煮きのこ丼なんてものも発見!なんだそりゃうまそうだぞ、おい。マーボー丼だってオレは好きだぞ。まいったな、おい。
まぁ 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 一本でイケるってことは確実になった。嬉しい。
OpenSSH 4.4 以降は PermitOpen で port の制限を、4.7 以降は Match によってユーザーなどの制限を行うことができるようになっている。 ↩
ついでだから開発にコミットしてしまおう。帰ってからの宿題。
バグじゃなかった
勢いこんで ML に入ったが、再現性の確認をしていたら、少しもバグではなかった。ただの勘違いだった。何やってんだ、おれは。。。
思ったんだけど、これ $sciprt = で PHP の機能をフル稼働してホスト名とかポート番号の補完をうまいことやればいいんじゃねーか?
InterWikiName はともかく、プラグインそのものをいじるのを毎回やるのはうざいんだよなぁ。
1行に2つ変数を展開しているページをリストアップするときに無限地獄に落ちていた。具体的には :config/tracker/digicam/page の
*[maker] [model]
フォームへ戻る→ [_refer]
|~機種|[model]|
の1行目。これを
*[model]
だけにして対処。よーしこれであれこれチェックしやすくなってきた。
from asahi.com
うぎゃぁ。まだなんぼか持ってるんだよなぁ。早めに使わないと。でも、年内ってのは販売停止なだけで利用は停止じゃないんだよな。利用停止期限はいつだ?
ring が始めましたね。