Подтвердить что ты не робот

Node.js с Handlebars.js на сервере и клиенте

У меня есть приложение в Node.js с использованием Expressjs и Handlebars в качестве механизма шаблонов.

Expressjs использует макеты, а затем отображает представления. Макет (layout.hbs) выглядит так:

<!doctype html>
<html lang="en">
    <head>
    </head>
  <body>
    {{{body}}}
  </body>
</html>

{{{body}}} заменяется на стороне сервера в пределах Node.js при доступе к маршруту. Например:

app.get('/', function(req, res){
   res.render('index'})
})

Будет заменен тег {{{body}}} содержимым index.hbs.

Теперь на стороне клиента я использую Backbone.js и хочу использовать Handlebars для представлений, управляемых через Backbone. Проблема в том, что, поскольку эти страницы уже обрабатываются с помощью Handlebars, когда я пытаюсь использовать Handlebars внутри него (или Handlebars in Handlebars), это не сработает. Ошибок нет, просто просто не заменяет теги данными.

Кто-нибудь сталкивался с этим раньше или имел какое-то представление о работе?

Спасибо!

4b9b3361

Ответ 1

Yup, это липкая проблема - вроде как проблемы с цитированием в сценариях оболочки, которые становятся гнездом крыс в цитируемых цитатах.

Мое решение - использовать jade (a la haml) в expressjs (на стороне сервера) для вывода шаблонов на основе дескрипторов для клиента. Таким образом, сервер использует один синтаксис (нефрит), а клиент использует другое (рули). Я нахожусь на том же перекрестке, что и вы, поэтому у меня есть тот же вызов.

Конечно, нефрит не является существенным (хотя он готов для выражения). Вы можете выбрать любой механизм шаблонов (не для рулей) для сервера и/или вы могли бы использовать рули на сервере с шаблонами шаблонов без рулей на клиенте --- пока два синтаксиса выбранных вами шаблонных двигателей не сталкиваются. Поскольку я использую emberjs на клиенте, и он использует синтаксис handlebars (по умолчанию), я предпочитаю использовать emberjs + handlebars синтаксис на клиенте. Так что expressjs + jade стал естественным для сервера.

Ответ 2

Вы должны использовать предварительно скомпилированные шаблоны клиентов. Они быстрее выполняются и позволяют использовать один и тот же язык шаблонов на сервере и клиенте.

  • Установить ручки глобально npm install handlebars -g
  • Предварительно скопируйте свои шаблоны handlebars client-template1.handlebars -f templates.js
  • Включить templates.js <script src="templates.js"></script>
  • Выполнить шаблон var html = Handlebars.templates["client-template1"](context);

fooobar.com/questions/180422/...

Ответ 3

Легкий способ сделать это - просто добавить \ до {{ в файле Handlebars. Например:

<script type="text/x-template" id="todo-item-template">
<div class="todo-view">
    <input type="checkbox" class="todo-checkbox" \{{checked}}>
    <span class="todo-content" tabindex="0">\{{text}}</span>
</div>

<div class="todo-edit">
    <input type="text" class="todo-input" value="\{{text}}">
</div>

<a href="#" class="todo-remove" title="Remove this task">
    <span class="todo-remove-icon"></span>
</a>

Вышеуказанный код будет отображаться на клиенте с сохраненными тегами {{..}}.

Ответ 4

Бесстыдная самореклама!

Я хотел сделать то же самое, что и клиент/сервер, поэтому я написал небольшой пакет npm, чтобы помочь:

node-handlebars-precompiler

Я взбивал его через пару часов на основе компилятора командной строки в репозитории ручек wycats. Это не самый лучший код в мире, но он очень хорошо работает для меня.

EDIT: я больше не поддерживаю этот пакет. Если вы хотите взять на себя ответственность, свяжитесь со мной через Github. В основном я использую шаблоны Jade, поэтому для меня не имеет смысла продолжать работу в качестве сопровождающего.

Ответ 5

Я работал над этим, передавая клиентские шаблоны через серверные шаблоны.

Таким образом, на стороне сервера прочитайте все ваши клиентские шаблоны в массиве и передайте их функции рендеринга на стороне сервера

В вашем обработчике маршрута сделайте что-то вроде:

readTemplates(function(err, clientTemplates) {
  res.render("page", {
    clientTemplates: clientTemplates;   
  });
});

И затем в layout.hbs:

{{#each clientTemplates}}
<script type="text/handlebars id="{{this.filename}}" >
{{{this.template}}}
</script>
{{/each}}

Здесь я использую имена файлов без расширений в качестве идентификатора шаблона, чтобы на них можно ссылаться из представлений Backbone. О, и не забудьте реализовать кэширование для режима производства.

Да, это отстой.

Я думаю, что для этого нужно написать хелпер Handlebars/Express/Connect.

Ответ 6

У вас есть 2 варианта. Второй вариант - лучший способ:

1) Побег усов

<script type="text/x-handlebars" data-hbs="example">
  <p>\{{name}}</p>
</script>

2) Прекомпиляция

Это скомпилирует шаблон на сервере, прежде чем он перейдет к клиенту. Это сделает шаблон готовым к использованию и уменьшит нагрузку на браузер.

Ответ 7

Мне не понравилось решение для предварительной компиляции (потому что я хочу определить шаблоны в том же файле, где я их буду использовать), и наивное решение для удаления \{{ (потому что ему нужен полный компилятор Handlebars и более javascript-код), поэтому Я придумал гибридное решение, в котором используются помощники Handlebars:

1) Зарегистрируйте новый помощник под названием "шаблон" в конфигурации сервера

var hbs = require('hbs');
hbs.registerHelper("template", function(key, options){
    var source = options.fn().replace("\\{{", "{{");
    var ret =
    '<script>\n' + 
        key + ' = function(opt){\n' +
            'return Handlebars.template(' + hbs.handlebars.precompile(source) + ')(opt);\n' +
        '}\n' + 
    '</script>';
    return ret;
});


2) Используйте его в любом месте вашей клиентской веб-страницы (с \{{ escape для параметров на стороне клиента)

{{#template "myTemplate"}}
    <div>
        <p>Hello \{{this.name}}!</p>
    </div>
{{/template}}

(сервер будет прекомпилировать его примерно так)

<script>
    myTemplate = function(opt){
        return Handlebars.template(/* HBS PRECOMPILATED FUNCTION */)(opt);
    }
</script>


3) Просто вызовите функцию там, где она вам нужна, на javascript на стороне клиента

var generatedHtml = myTemplate("world");   // = <div><p>Hello world!</p></div>
$("#myDiv").html(generatedHtml);           // or whatever