Chormeのmanifest version2から eval
が禁止になった。
使おうとすると Uncaught Error: Code generation from strings disallowed for this context
とエラーが出る。
eval
なんか使わないという人が大多数だと思うが、実はほとんどのテンプレートエンジンが内部で eval
ないし new Function()
を使っているので、意外とこの制限にひっかかる場合が多い。
もともとUnderscore.jsのテンプレートエンジンを使っていたのを、version2でも動くようにした時の方法を紹介する。
ちなみにGoogle謹製のAngular.js には eval
も new Function()
も使わないテンプレートエンジンがあるそうだが、Angular.jsは巨大過ぎて使う気がしない。
_.template source
Underscore.js version 1.3.3からコンパイルしたテンプレートオブジェクトに source
プロパティが追加された。
これを使うと new Function()
に渡される文字列を参照できる。
例えば
console.log(_.template("<b><%= name %></b>").source);
を実行すると
function(obj){
var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};
with(obj||{}){
__p+='<b>'+
((__t=( name ))==null?'':__t)+
'</b>';
}
return __p;
}
となる。仮にこれを JST
という名前の変数に代入したとすると
console.log(JST({name: 'hello'}));
は <b>hello</b>
になる。ようするにこいつを予め開発環境で作ってやり、extension ではこの関数を使えばいいわけだ。
変換する
だんだん書くのが面倒になってきたので詳細は省くが、要約すれば次のようなスクリプトを用意する。
var _ = require('underscore');
var fs = require('fs');
// テンプレート
var templates = {
foo: "<b><%= name %></b>"
}
var data = "var JST = {};\n";
for (var name in templates) {
data += "JST['" + name + "'] = " + _.template(templates[name]).source + ";\n";
}
fs.writeSync("path/to/jst.js", data);
これを実行すると path/to/jst.js
というファイルが生成される。extension でそれを読み込む。
使い方は
JST.foo({ name: 'hello' }); //=> <b>hello</b>
みたいな感じ。 path/to/jst.js
の中身は
var JST = {};
JST['foo'] = function(obj){
var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};
with(obj||{}){
__p+='<b>'+
((__t=( name ))==null?'':__t)+
'</b>';
}
return __p;
};
になる。これを応用すれば通常のWebサイトでも Underscore.js のテンプレートエンジンをコンパイル時間の分だけ高速化させることができるが、それは過剰な気がするのでそこまでやる必要はないと思う。