// Для правильной работы необходимо установить библиотеку "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 = replaceVariables(content, parseVariables(variablesString));
content = renderTemplate(content, parseVariables(variablesString) /* или {value: 1}*/).replace(/(\s+<)/g, '\n$1'); // ДОБАВЛЕНО МНОЙ
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 replaceVariables (template, variablesObject, regexp) {
function replaceFunction (match, variableName) {
return (variableName in variablesObject) ? variablesObject[variableName] : '';
}
return template.replace(regexp || regExpForMustache, replaceFunction);
}
// Функция для выполнения кода внутри шаблона
function renderTemplate (templateString, dataObject) {
// <% for (var i = 0; i < 3; i++) { %><p><%= i %> <%= someArray[i] %></p><% } %>
var functionArgument ="dataObject"
, functionBody = "var code = [];"
+ "with (dataObject) {"
+ "code.push('" + templateString
.replace(/[\r\t\n]/g, "")
.split("<%").join("\t")
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("code.push('")
.split("\r").join("\\'")
+ "');"
+ "}"
+ "return code.join('');";
return new Function(functionArgument, functionBody).call(null, dataObject);
}
// Взять шаблон, подставить в него значения переменных, вернуть новый обработанный шаблон в виде строки
Файл index.html
<!DOCTYPE html>
<!-- #include "tpl/header.html" title="Example" header="Sample Title" superman="['one', 'two', 'three']" -->
<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>
<h2><%= header %></h2>
<% for (var i = 0; i < 3; i++) { %><p><%= i %> <%= superman[i] %></p><% } %>
Файл 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>
<h2>Sample Title</h2>
<p>0Example</p><p>1Example</p><p>2Example</p><p>3Example</p><p>4Example</p><p>5Example</p><p>6Example</p><p>7Example</p><p>8Example</p><p>9Example</p>
<div role="main">
content goes here
</div>
<footer>yeah</footer>
</body>
</html>
Комментариев нет:
Отправить комментарий