1bragimov
@1bragimov
Web стэк

Как по уму указать статичный ресурс внутри шаблонизатора?

Собираю с помощью Gulp статичный сайт.
Сайт пока что статический и в будущем планируется переходить на динамику. Как внутри шаблонизатора ссылаться на рисунки, аудио и т.д. из одного файла, чтобы при изменении не влезть в код шаблона, а поправить там же.

Смотрю в сторону JSON, чтобы указать все
вот таким образом
JSON файлик:
"static" : {
    "images" : {
        "wallpaper": {
             src : "https://example.com/images/img.png",
             alt : "Image PNG"
              },
        "graphicClip" : {
             src : "https://example.com/images/png.png"
             }
          },
      },
   "Text" : {
       English :  "English string",
       Russian : "Russian string"
       }
  }


HTML (или NUNJUCKS)
<img src={{static.images.wallpaper.src}} alt={{static.images.wallpaper.alt}}
<p>{{static.text.English}}</p>
<p>{{static.text.Russian}}</p>
Оффтоп
Посоветуйте, пожалуйста, рускоязычное сообщество (группы, чаты, форумы) NUNJUCKS, где можно задавать вопросы и поделиться опытом. Если знаете таковых.
  • Вопрос задан
  • 81 просмотр
Решения вопроса 1
@ned4ded
Верстка, Фронтенд
Добрый день! В своих проектах как раз использую такой "кустарный" подход, разделяя его на два этапа:
1) подгрузка глобальных констант в движок nunjucks до компиляции страниц (хранятся в json);
2) добавление фильтра на выдачу локалей (тоже хранятся в json, но в отдельной папке).

Грубо говоря, это два способа реализации,
первый - выгрузка глобальной константы в nunjucks в контекст (gulp-nunjucks-render, render api );
второй - это использование отдельной от nunjucks сущности (в моем случае экземпляр i18next без бекенда), в которой происходит синхронный процесс выдачи данных по запросу через кастомный фильтр nunjucks.

Сейчас, проведя с такой сборкой уже около 8-9 месяцев, могу сказать, что там много условностей, багов и проблем с производительностью при сборке. И в целом она не умещается в рамки хоть какой-нибудь глобальной концепции по организации кода (что просто усложнит поддержку в будущем). Наверное, более правильное решение - это настроить какой-то готовый генератор статических сайтов, чем писать свою собственную сборку. Но если вам интересно, с чего начать, то структура и код:

├── datasets
│   └── meta.json
├── locales
│   ├── en
│   │   └── translation.json
│   └── ru
├── tasks
...
└── gulpfile.js

# Это упрощенная структура, 
# но если вам будет что-то непонятно, я напишу подробнее.


код html таска на сборку страниц
import gulp from 'gulp';
import fs from 'fs';
import path from 'path';
import i18next from 'i18next';
import config from '../gulpfile.config';
import engine from 'gulp-nunjucks-render';
import minify from 'gulp-htmlmin';
import Backend from 'i18next-sync-fs-backend';
import rename from 'gulp-rename';

i18next.use(Backend).init({
  debug: true,
  fallbackLng: ['en'],
  initImmediate: false,
  backend: {
    loadPath: config.paths.locales + '/{{lng}}/{{ns}}.json' // локали собираются по названиям из папки locales
  },
  ns: ['translation'],
  defaultNS: 'translation'
});

export function html(done) {
  const envHooks = [
    env => env.addFilter('__', function(key, ns) { // фильтр на поиск и выдачу информации по ключу в i18next
      if(!i18next.exists(key)) return 0;

      return i18next.t(key);
    }),
  ]

  const data = fs.readdirSync( config.paths.datasets ).reduce( (acc, filename) => {
    return { ...acc, [ path.basename( filename, '.json') ] : require('../' + config.paths.datasets + '/' + filename) };
  }, {});

  data.get = function(name) { 
    return this[name];
  }

  const [ def ] = i18next.options.fallbackLng;

  const rec = (arr) => {

    const [lng, ...rest] = arr;

    return i18next.changeLanguage(lng, (err) => {
      if(err) throw new Error(err);

      return gulp.src(config.paths.pages)
        .pipe(engine({
          data: {
            datasets: data,
          },
          path: ['src/pages/templates'],
          manageEnv: function(env) {
            return envHooks.forEach(fn => fn(env));
          },
        }))
        .pipe(minify({ collapseWhitespace: true }))
        .pipe(rename(function(path) {

          path.basename = lng === def ? path.basename : lng + '.' + path.basename;
        }))
        .pipe(gulp.dest(config.server.dest))
        .on('end', () => {
          return rest.length ? rec(rest) : done();
        });
    });
  }

  rec(['ru', 'en']); // если язык дефолтный, то страницы компилируются обычным образом, если нет - у них будет префикс с названием языка

  return;
};


В коде демонстрируется сразу 2 подхода. В темплейтах вызывается по-разному:
1)
<!--
datasets/features.json
[
  {
    "name" : "independent",
    "_descr" : "features.indep.descr"
  },
  {
    "name" : "secure",
    "_descr" : "features.secure.descr",
  },
]
-->

{% set features = datasets.get('features') %}

<ul class="page-home__features">
  {% for f in features %}
   <li>
    {{ feature.make(f) }}
   </li>
  {% endfor %}
</ul>


2)
<!--
 locales/en/translation.json

  "pages" : {
    "home" : {
      "headings" : {
        "qualities": "a perfect solution for projects"
        }
      }
    }
-->

<code lang="html">
<h2 class="text-center font-weight-bold mb-4 mb-lg-6">
  {{ 'pages.home.headings.qualities' | __ }}
  <!-- фильтр зарегистрирован под названием __ -->
</h2>
</code>
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы