Как объединить JSON и Handlebars из партиалов в HTML с Gulp?

Я строю статический сайт, используя Handlebars и Gulp. Вот моя структура папок:

app/
    content/
        intro.json
        header.json
        faq.json
        features.json
        footer.json
    templates/
        home.hbs
        partials/
            home-section.hbs
            header.hbs
            footer.hbs
    index.html
Gulpfile.js

Содержание home.hbs таково:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Test</title>
</head>
<body>
    {{> header}}
    {{> home-section}}
    {{> home-section}}
    {{> home-section}}
    {{> footer}}
</body>
</html>

Я хочу пройти в intro.json, faq.json, а также features.json каждому из home-section частичные и header.json в header а также footer.json в нижний колонтитул.

Вот что у меня есть в моем Gulpfile:

var gulp = require('gulp');
var handlebars = require('gulp-compile-handlebars');
var rename = require('gulp-rename');

gulp.task('html', function() {
  return gulp.src('./app/templates/*.hbs')
    .pipe(handlebars({}, {
            ignorePartials: true,
            batch: ['./app/templates/partials']
          }))
    .pipe(rename({
            extname: '.html'
          }))
    .pipe(gulp.dest('build'));
});

Я не смог выяснить, как передавать более одного файла JSON одновременно, особенно в home-sections. Заранее спасибо!

2 ответа

Решение

Первый параметр для handlebars это ваш глобальный контекст, доступный для всех ваших шаблонов. Вы можете загрузить свои отдельные файлы JSON в объект контекста и использовать его в качестве первого параметра.

(Определенно есть лучшие способы сделать это, но эй, это быстро и просто!)

var infoData = require('./app/content/info.json');
var faqData = require('./app/content/faq.json');
var featuresData = require('./app/content/features.json');

Затем вы можете передать эти объекты через глобальный контекст в вашу функцию handlebars

.pipe(handlebars({ info: infoData, faq: faqData, features: featuresData }))

Как только данные попадают в ваш контекст, вы можете получить к ним доступ следующим образом:

{{> home-section content=info }}
{{> home-section content=faq }}
{{> home-section content=features }}

Внутри вашего home-section частично, у вас будет content объект, который будет содержать данные файла, который вы передали в него. Итак, если ваш info.json файл выглядел так:

{ "header": "Info", "details": "This is some information" }

Ваш home-content.hbs часть может затем получить доступ к данным следующим образом:

<h2>{{ content.header }}</h2>
<p>{{ content.details }}</p>

К несчастью, gulp-compile-handlerbars Функция принимает только два аргумента, первый из которых - все данные, передаваемые в ваши шаблоны. Это означает, что вы должны загрузить все ваши файлы json вместе и передать их как один объект.

Вы можете сделать это с помощью небольшого помощника:

function requireJsons(fileNames) {
  return fileNames.reduce(function(jsons, fileName) {
    jsons[fileName] = require('app/content/' + fileNames[i] + '.json');
    return jsons;
  }, {});
}

Который вы можете использовать для создания объекта данных для всех ваших шаблонов:

var data = requireJsons(['intro', 'header', 'faq', 'features', 'footer']);

gulp.task('html', function() {
  return gulp.src('./app/templates/*.hbs')
    .pipe(handlebars(data, {
      // ...

Если вам всегда нужно загрузить все файлы json из app/content каталог, вы можете использовать readdirSync для получения всех имен файлов.json, а затем передать их requireJsons:

var path = require('path');
var fileNames = fs.readdirSync('app/content')
  .filter(function(fileName) {
    return path.extname(fileName) === '.json';
  });
var data = requireJsons(fileNames);

Конечно, если скорость важна, вы можете объединить два метода в один, который загружает jsons и создает data объект в один проход.


Другой вариант - возможно скомпилировать каждый шаблон отдельно и передать соответствующие данные в каждую компиляцию. Такой инструмент, как gulp-foreach, будет полезен.

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