Использование 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/.

Другие вопросы по тегам