четверг, 12 ноября 2015 г.

Node.js static SSI - Script to inline HTML Static Includes

index.html

<!DOCTYPE html>
<!-- #include "inc_header.html" title="Example" header="Sample Title" -->
<html>
    <head>
        <meta charset="utf-8">
        <title>Example</title>
        <link rel="stylesheet" href="css/main.css">
    </head>
    <body>
        <h1>Sample Title</h1>
<!-- endinclude -->

        <div role="main">
            content goes here
        </div>

<!-- #include "inc_footer.html" msg="yeah" -->
        <footer>yeah</footer>
<!-- endinclude -->
    </body>
</html>

inc_header.html

<html>
    <head>
        <meta charset="utf-8">
        <title>{{title}}</title>
        <link rel="stylesheet" href="css/main.css">
    </head>
    <body>
        <h1>{{header}}</h1>

Если ваш проект состоит из более чем 5 статичных страниц, использующих одинаковые header и footer, то в этом случае вы можете использовать данный простой script для вставки кода из внешних файлов, основанный на использовании комментариев в качестве разметки. Таким образом вы сможете обновлять все файлы сразу, внося изменение только в одном месте. В дальнейшем данный script может быть расширен для поддержки variables/arguments, но сейчас в этом нет необходимости.

inc_footer.html

        <footer>{{msg}}</footer>

templater.js

// Для правильной работы необходимо установить библиотеку "glob": npm install glob
//
// Данный сценарий будет искать все HTML-файлы в корневой папке, в которой он находится, или в папке, которую вы зададите,
// и обрабатывать статичные инклюды обернутые в HTML-комментарии следующим образом:
// <!-- #include "example/foo.html" -->
// Вы также можете добавить переменные, подлежащие замене, используя синтакиси mustache
// (пока поддерживается только самый простой способ замены):
// <!-- #include "inc/header.html" title="Example Title" foo="bar" -->
// значения внутри {{title}} и {{foo}} будут заменены на соотвестующий значения, прописанные в комментарии.
// После обработки шаблонов будут сформированы итоговые файлы, которые будут помещены в указанную вами папку.
//
// Пример кода шаблона
//
// Файл /index.html
// <!DOCTYPE html>
//     <!-- #include "tpl/header.html" title="Example" header="Sample Title" -->
//         <div role="main">
//             content goes here
//         </div>
//     <!-- #include "tpl/footer.html" msg="yeah" -->
//     </body>
// </html>
//
// Файл /tpl/header.html
// <html>
//     <head>
//         <meta charset="utf-8">
//         <title>{{  title  }}</title>
//         <link rel="stylesheet" href="css/main.css">
//     </head>
//     <body>
//         <h1>{{header}}</h1>
//
// Файл /tpl/footer.html
//         <footer>{{msg}}</footer>
//
// Итоговый файл /result/index.html
// <!DOCTYPE html>
// <html>
//     <head>
//         <meta charset="utf-8">
//         <title>Example</title>
//         <link rel="stylesheet" href="css/main.css">
//     </head>
//     <body>
//         <h1>Sample Title</h1>
//         <div role="main">
//             content goes here
//         </div>
//         <footer>yeah</footer>
//     </body>
// </html>

// Конфигурационные настройки
var config = {
      inputDirectoryPath: './'
    , outputDirectoryPath: './result/'
    , fileEncoding: 'utf-8'
};

// Загрузка модулей
var glob = require('glob')
    , fs = require('fs');

// Регулярное выражения для поиска комментария инклюда
// ($1) = file name - путь к файлу и его имя "folder/file.html"
// ($2) = variables - переменные title="Example Title" foo="bar"
//                               |       <!--      #include   "file.html" variable="value" -->   |
var regExpForInclude = /^\s*<!--\s*\#include\s*["']([^"']+)["']\s*(.+)?\s*-->\s*$/gm;

// Регулярное выражения для поиска объявленных переменных
// ($1) = variable name - имя переменной
// ($2) = variable value - значение переменной
//                   | some-variable_name    =      "value" |
var regExpForVariables = /([-_\w]+)\s*=\s*["']([^"']+)["']/g;

// Регулярное выражения для поиска мест, куда должно быть вставлено значение переменной
//                                  | {{       some-variable_name       }} |
var regExpForMustache = /\{\{\s*([-_\w]+)\s*\}\}/g;

// Обработать все файлы в исходной директории и поместить результаты обработки в виде файлов в заданную папку
glob(config.inputDirectoryPath + '*.html', function (error, files) {
    if (error) {throw error;}
    files.forEach(function (filePath) {
        fs.readFile(filePath, config.fileEncoding, function (error, fileData) {
            if (error) {throw error;}
            fileData = fileData.replace(regExpForInclude, function (match, fileName, variablesString) {
                var content = fs.readFileSync(fileName, config.fileEncoding);
                content = interpolate(content, parseVariables(variablesString));
                return content;
            });
            fs.writeFile(config.outputDirectoryPath + filePath, fileData, config.fileEncoding, function (error) {
                if (error) {throw error;}
                console.log('complete: '+ filePath);
            });
        });
    });
});

// Функция преобразования строки с набором переменных в объект, состоящий из комбинаций "имя переменной: значение переменной"
function parseVariables (variablesString) {
    var obj = {}
        , match;
    while (match = regExpForVariables.exec(variablesString)) {
        obj[match[1]] = match[2]; // obj[some-variable_name] = variable_value;
    }
    return obj;
}

// Функция для замены имен переменных внутри шаблона на значения этих переменных
function interpolate (template, variablesObject, regexp) {
    function replaceFunction (match, variableName) {
        return (variableName in variablesObject) ? variablesObject[variableName] : '';
    }
    return template.replace(regexp || regExpForMustache, replaceFunction);
}

Комментариев нет:

Отправить комментарий