Использование Jurassic для предварительной компиляции шаблона JsRender на стороне сервера
Я пытаюсь предварительно скомпилировать шаблоны JsRender из библиотеки классов, написанной на C#, используя механизм сценариев юрского периода для выполнения JsRender.
Вот мой код:
var engine = new Jurassic.ScriptEngine();
engine.Execute(JsRenderContents);
var precompiledTemplate = engine.CallGlobalFunction<string>(String.Concat("$.templates(\"", template, "\");"));
Я взял вызов функции JavaScript, $.templates()
с этой страницы, которая утверждает, что
$.templates(markupOrSelector) возвращает: скомпилированный шаблон объекта
И мой образец HTML-шаблона просто
<li>{{:Name}}</li>
Однако мой код выдает исключение:
'$.templates("<li>{{:Name}}</li>");' is not a function.
Теперь я не уверен на 100%, могу ли я использовать оператор $ без присутствия jQuery. Автор включает jQuery в несколько своих примеров, но также утверждает, что jQuery не требуется.
Так что же не так? Не устарела ли документация для версии JsRender, взятой из GitHub в тот же день, когда я разместил этот вопрос? (Я знаю, что JsRender все еще находится в бета-версии.) Или, может быть, я неправильно использую юрский период?
РЕДАКТИРОВАТЬ:
Я считаю, что на самом деле это скорее вопрос юрского периода, чем вопрос JsRender. В частности, я думаю, что это относится к глобальному объекту Jurassic, так как JsRender обернут в функцию немедленного вызова, которая передает this
и я не уверен, что юрский this
,
Похоже, я не первый, кто сталкивается с этим вопросом. Я воспользовался советом из последнего поста на этой странице и изменил свой код следующим образом:
var engine = new Jurassic.ScriptEngine();
engine.Execute(JsRenderContents);
engine.Global["window"] = engine.Global;
var precompiledTemplate = engine.CallGlobalFunction<string>(String.Concat("window.jsviews.templates(\"", template, "\");"));
который не работал - вероятно, потому что IIF JsRender все еще проходит this
вместо window
и я не хочу изменять скрипт.
Кто-нибудь может помочь продвинуть это вперед? Как я могу вызвать любую функцию JsRender из юрского периода, учитывая, что юрский период... я не знаю... возможно, существует некоторая условная разница в том, как юрский период реализует глобальный объект.
2 ответа
Я использую jsRender + Jurassic для предварительной компиляции моих шаблонов и создания js-файлов в T4. Я потратил много времени на решение этой проблемы и не нашел ответа, но прочитал несколько статей, которые помогли.
Смотри мой код. Это работает в моем случае. Я уверен, что смогу помочь вам решить проблему, если это не поможет:
var engine = new Jurassic.ScriptEngine();
var jsRenderPath = "/pathToDir/jsrender.js";
var jsUnevalPath = "/pathToDir/jsRenderUtils.js";
engine.ExecuteFile(jsRenderPath);
engine.ExecuteFile(jsUnevalPath);
engine.Evaluate("function renderTemplate(name, markup) { var tmpl = this.jsviews.templates(name, markup); return uneval(tmpl); }");
var compiledTemplateString = engine.CallGlobalFunction<string>("renderTemplate", templateName, templateString);
var result = "$.templates['" + templateName + "'] = " + compiledTemplateString + ";";
Содержимое jsRenderUtils.js (неравная функция)
function uneval(obj, known) {
var root = (known === undefined), result;
known = known || [];
// some values fail eval() if not wrapped in a ( ) parenthesises
var wrapRoot = function (result) {
return root ? ("(" + result + ")") : result;
};
// special objects
if (obj === null)
return "null";
if (obj === undefined)
return "undefined";
if (obj !== obj) // isNaN does type coercion, so can't use that.
return "NaN";
if (obj === Infinity)
return "Infinity";
if (obj === -Infinity)
return "-Infinity";
// atoms
switch (typeof obj) {
case 'function':
return wrapRoot(obj.toString());
case 'number':
case 'boolean':
return obj.toString();
case 'string':
return "\"" + obj.toString() + "\"";
}
// circular reference check for non-atoms
if (known.indexOf(obj) !== -1)
return "null";//throw new Error("Circular references detected while unevaling.");
known.push(obj);
// specialized types
if (obj instanceof Array)
return "[" + obj.map(function (o) { return uneval(o, known); }).join(",") + "]";
if (obj instanceof Date)
return wrapRoot("new Date('" + obj.toString() + "')");
// hashes
var key, pairs = [];
for (key in obj) {
var val;
switch (key) {
case "render":
val = "$.fn.render";
break;
case "markup":
val = "null";
break;
default:
val = uneval(obj[key], known);
}
pairs.push("\r\n" + key + " : " + val);
}
return wrapRoot("{" + pairs.join(",") + "}");
};
ОБНОВЛЕНО: Если вы будете рендерить шаблоны без jquery, вы должны добавить это:
$ = window.jsviews;
$.fn = {
render: function (data, view, j, u) {
return this.fn(data, view, j, u);
}
};
JsRender можно использовать без jQuery.
Это работает так, что для звонков, таких как var compiledTemplate = $.templates(...);
, если jQuery не загружен, вы должны установить $ = window.jsviews
(или эквивалент, такой как this.jsviews, когда на сервере).
Так что на самом деле вы звоните:
compiledTemplate = this.jsviews.templates(...);
Вот пример: http://borismoore.github.io/jsrender/demos/step-by-step/20_without-jquery.html (код здесь https://github.com/BorisMoore/jsrender/blob/master/demos/step-by-step/20_without-jquery.html).
Здесь также есть много модульных тестов: http://borismoore.github.io/jsrender/test/unit-tests-jsrender-no-jquery.html (код: https://github.com/BorisMoore/jsrender/blob/master/test/unit-tests-jsrender-no-jquery.html).
Дополнительная документация / примеры для этого сценария будут добавлены позже на http://www.jsviews.com/.