Giter VIP home page Giter VIP logo

enb-bemxjst's Introduction

enb-bemxjst

NPM version Build Status Build status Coverage Status Dependency Status

Пакет предоставляет набор ENB-технологий для сборки BEMTREE- и BEMHTML-шаблонов в проектах, построенных по методологии БЭМ.

Технологии пакета enb-bemxjst:

Принципы работы технологий и их API описаны в документе API технологий.

Совместимость: технологии пакета enb-bemxjst используют компилятор BEM-XJST. Мажорная версия enb-bemxjst всегда совпадает с мажорной версией bem-xjst.

Установка

Установите пакет enb-bemxjst:

$ npm install --save-dev enb-bemxjst

Требования: зависимость от пакета enb версии 0.16.0 и выше.

Обзор документа

Быстрый старт

Подключите необходимые технологии: bemtree, bemhtml.

var BemtreeTech = require('enb-bemxjst/techs/bemtree'),
    BemhtmlTech = require('enb-bemxjst/techs/bemhtml'),
    FileProvideTech = require('enb/techs/file-provider'),
    bemTechs = require('enb-bem-techs');

 module.exports = function(config) {
     config.node('bundle', function(node) {
         // Получаем FileList
         node.addTechs([
             [FileProvideTech, { target: '?.bemdecl.js' }],
             [bemTechs.levels, { levels: ['blocks'] }],
             bemTechs.deps,
             bemTechs.files
         ]);

         // Создаем BEMTREE-файл
         node.addTech(BemtreeTech);
         node.addTarget('?.bemtree.js');

         // Создаем BEMHTML-файл
         node.addTech(BemhtmlTech);
         node.addTarget('?.bemhtml.js');
     });
 };

Для сборки HTML используйте технологию bemjson-to-html.

var BemjsonToHtmlTech = require('enb-bemxjst/techs/bemjson-to-html'),
    BemhtmlTech = require('enb-bemxjst/techs/bemhtml'),
    FileProvideTech = require('enb/techs/file-provider'),
    bemTechs = require('enb-bem-techs');

module.exports = function(config) {
    config.node('bundle', function(node) {
        // Получаем BEMJSON-файл
        node.addTech([FileProvideTech, { target: '?.bemjson.js' }]);

        // Получаем FileList
        node.addTechs([
            [bemTechs.levels, { levels: ['blocks'] }],
            [bemTechs.bemjsonToBemdecl],
            [bemTechs.deps],
            [bemTechs.files]
        ]);

        // Собираем BEMHTML-файл
        node.addTech(BemhtmlTech);
        node.addTarget('?.bemhtml.js');

        // Создаем HTML-файл
        node.addTech(BemjsonToHtmlTech);
        node.addTarget('?.html');
    });
};

Работа с технологиями

По БЭМ-методологии шаблоны к каждому блоку хранятся в отдельных файлах с расширением .bemtree.js и .bemhtml.js в директориях блоков. Чтобы использовать шаблоны, необходимо собрать их исходные файлы.

Отдельные файлы с шаблонами (.bemtree.js или .bemhtml.js) собираются в один общий файл (?.bemtree.js или ?.bemhtml.js) с помощью технологий:

Результат — скомпилированный файл ?.bemhtml.js или ?.bemtree.js — может применяться по-разному в зависимости от наличия модульной системы и ее типа в следующих случаях:

Исполнение шаблонов в Node.js

Скомпилированный файл подключается как модуль в формате CommonJS.

var BEMTREE = require('bundle.bemtree.js').BEMTREE, // Путь до скомпилированного BEMTREE-файла
    BEMHTML = require('bundle.bemhtml.js').BEMHTML; // Путь до скомпилированного BEMHTML-файла

var bemjson = BEMTREE.apply({ block: 'page', data: { /* ... */ } }),
    html = BEMHTML.apply(bemjson); // <html>...</html>

Исполнение шаблонов в браузере

Скомпилированный файл подключается на страницу как JavaScript-файл.

<script src="bundle.bemtree.js"></script>
<script src="bundle.bemhtml.js"></script>

В браузере способы исполнения шаблонов зависят от наличия модульной системы:

  • Без модульной системы

    Шаблоны доступны из глобальной переменной BEMTREE или BEMHTML.

    var bemjson = BEMTREE.apply({ block: 'page', data: { /* ... */ } }),
        html = BEMHTML.apply(bemjson); // <html>...</html>
  • С модульной системой YModules

    Шаблоны доступны из модульной системы (YModules):

    modules.require(['BEMTREE', 'BEMHTML'], function(BEMTREE, BEMHTML) {
        var bemjson = BEMTREE.apply({ block: 'page', data: { /* ... */ } }),
            html = BEMHTML.apply(bemjson); // <html>...</html>
    });

Использование шаблонов для сборки HTML

HTML – результат применения скомпилированного шаблона к указанному BEMJSON-файлу.

Сборка HTML (файл ?.html) с помощью технологий enb-bemxjst проходит в два этапа:

  1. Файл ?.bemhtml.js собирается с помощью технологии bemhtml.
  2. BEMJSON и скомпилированный ?.bemhtml.js-файл обрабатываются с помощью технологии bemjson-to-html, которая возвращает HTML-файл (?.html).

Особенности работы пакета

Подключение сторонних библиотек

Технологии bemtree и bemhtml поддерживают возможность подключения сторонних библиотек как глобально, так и для разных модульных систем с помощью опции requires.

Для подключения укажите название библиотеки и в зависимости от используемой модульной системы:

  • имя глобальной переменной;
  • имя модуля из YModules;
  • путь к модулю для CommonJS.
{
    requires: {
        'lib-name': {
            globals: 'libName',           // Название переменной в глобальной видимости
            ym: 'lib-name',               // Имя модуля из YModules
            commonJS: 'path/to/lib-name'  // Путь к модулю CommonJS относительно собираемого файла
        }
    }
}

В шаблонах модули будут доступны с помощью метода this.require, например:

block('button').content()(function () {
    var lib = this.require('lib-name');

    return lib.hello();
});

Не обязательно указывать все модульные системы для подключения библиотеки.

Например, можно указать зависимости глобально. В этом случае модуль всегда будет передаваться из глобальной переменной, даже если в среде исполнения будет модульная система.

{
    requires: {
        'lib-name': {
            globals: 'dependName' // Название переменной в глобальной видимости
        }
    }
}

Пример подключения библиотеки moment

Указывается путь к модулю:

{
    requires: {
        moment: {
            commonJS: 'moment',  // Путь к модулю CommonJS относительно собираемого файла
        }
    }
}

В шаблонах модуль будет доступен с помощью метода this.require('moment'). Код шаблона пишется один раз, одинаково для исполнения в браузере и в Node.js:

block('post').elem('data').content()(function () {
    var moment = this.require('moment'),  // Библиотека `moment`

    // Время в миллисекундах, полученное с сервера
    return moment(ctx.param.date).format('YYYY-MM-DD HH:mm:ss');
});

Синтаксис

Существует два синтаксиса для BEMHTML-шаблонов:

С момента выпуска библиотеки bem-core сокращенный синтаксис шаблонов считается устаревшим и больше не поддерживается.

О правилах перехода на JS-синтаксис читайте в руководстве по миграции.

Интернационализация

Базовая реализация BEM-XJST-технологий не содержит шаблонов для интернационализации (i18n).

Чтобы использовать i18n в шаблонах, следует подключить модуль BEM.I18N по аналогии с другими сторонними библиотеками.

BEM.I18N — библиотека для интернационализации блоков. Ядро находится в keyset-файлах в одной из базовых библиотек блоков:

После подключения BEM.I18N библиотека будет доступна в шаблонах с помощью метода this.require:

block('button').elem('tooltip').content()(function () {
    var i18n = this.require('i18n'),  // Библиотека `BEM.I18N`

    // Локализованное значение для ключа `tooltip`
    return i18n('button', 'tooltip');
});

Использование карт кода

Для того, чтобы включить на вашем проекте вывод ошибок в BEMHTML- и BEMTREE- шаблонах с использованием карт кода (ошибка будет указывать не на собранный файл, а на исходный файл с шаблоном) вам необходимо использовать enb-bemxjst версии 8.9.0 и выше.

В конфигурационном файле .enb/make на вашем проекте у технологий bemhtml/bemtree должна быть включена опция sourcemaps: true. Настоятельно рекомендуем включать эту опцию только в окружении разработки, но не в продакшене.

'use strict';

const techs = {
    bemhtml: require('enb-bemxjst/techs/bemhtml'),
    ...
};

module.exports = function(config) {
    config.nodes('pages/all', function(nodeConfig) {
        nodeConfig.addTechs([
            // bemhtml
            [techs.bemhtml, {
                target: '?.bemhtml.js',
                sourcemap: env === 'development',
                engineOptions: {
                    production: env === 'production',
                    omitOptionalEndTags: true,
                    unquotedAttrs: true,
                    elemJsInstances: true
                }
            }]
        ]);

        nodeConfig.addTargets(['?.bemhtml.js']);
    });
});

Дополнительная документация

Лицензия

© 2013 YANDEX LLC. Код лицензирован Mozilla Public License 2.0.

enb-bemxjst's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

enb-bemxjst's Issues

Ошибка при сборке проекта под Windows

Внезапно потребовалось собрать проект под windows, но сборка спотыкается на обработке bemhtml-old.

$ enb make desktop.bundles/blank
14:44:31.033 - build started
14:44:34.982 - build failed
TypeError: Cannot read property '1' of null
    at Object.module.exports.declare (e:\Work\projects\7days-redesign\node_modules\enb-bemxjst\node_modules\sibling\inde
x.js:12:33)
    at Object.<anonymous> (e:\Work\projects\7days-redesign\node_modules\enb-bemxjst\techs\bem-xjst.js:61:43)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (e:\Work\projects\7days-redesign\node_modules\enb-bemxjst\techs\bemhtml.js:25:18)
    at Module._compile (module.js:456:26)

При отсутствии enb-bemxjst, на более простых конфигах, enb отрабатывает как надо. Не знаете, в чем может быть причина такой неинформативной ошибки?

Обновление до версии 1.3.*

Привет!
У меня возникли непонятные проблемы с обновлением с 1.2.0 до 1.3.1.

Сначала было куча ошибок, связанных с синтаксисом bemhtml, который раньше допускал конструкции вида

attrs()(this.ctx.attrs)

После исправления всех ошибок, сборка работает отлично, но непонятным образом ломается работа tag()(). Причины отловить пока что не смог.

При этом с флагом devMode: true тэги обрабатываются корректно.

Это баг, фича, или просто я что-то делаю не так? Если нет готового рецепта, я попробую локализовать проблему и сделать небольшой пример.

Add error handler on template error

When you have a mistakes in BEMHTML-templates, you'll got error in production mode while tmpl-specs is running:

17:48:26.807 - [rebuild] [desktop.tmpl-specs/header/header.bemhtml-dev.js] bemhtml
17:48:26.809 - [rebuild] [desktop.tmpl-specs/header/header.bemhtml-dev.lang.js] mock-lang-js.js
17:48:26.833 - [failed] [desktop.tmpl-specs/header/header.bemhtml-prod.js] bemhtml
17:48:26.833 - [failed] [desktop.tmpl-specs/header/header.bemhtml-prod.lang.js] mock-lang-js.js
17:48:26.834 - [failed] [desktop.tmpl-specs/header/header.tmpl-spec.js] tmpl-spec
17:48:26.835 - build failed

Get rid of `xjst` suffix

Now source templates are taken from files with bemhtml and bemhtml.xjst suffixes.

Interesting fact: files with bemhtml.xjst suffixes will not be processed by using bemhtml-compat.

This feature nobody uses.

Move to mock-enb

  • Remove iojs-v2 from list of node environments for testing
  • Move to mock-enb

Requires Option

Now we can use modulesDeps option to require dependencies from YModules:

{ 
    modulesDeps: {
        vow: 'Vow'
    } 
}

After compilation dependencies are provided in base templates as "global" variables.

modules.define('BEMHTML', ['vow'], function (provide, Vow) {
    // Base templates of BEMTREE expect `vow` module from `Vow` variable.
});

Shortcomings

  • It is impossible get the module from global scope.
  • It is impossible get the module using CommonJS.
  • Interface expects variables from global scope.

Problem Solution

{ 
    requires: {
        'lib-name': {
            globals: 'dependName',      // var name from global scope
            ym: 'depend-name',          // module name from YModules
            commonJS: 'path/to/module', // relative path to CommonJS module from target
        }
    } 
}

For templates dependencies will be available in this.requre('lib-name'):

block('block').content(function () {
    var lib = this.require('lib-name');

    return lib.method();
});

In bundle file will be as follows:

// For global scope
oninit(function(exports, context) {
    context.BEMContext.prototype.requre = function(name) {
        return dependName; 
    };
});

// For YModules
modules.define('BEMHTML', ['depend-name'], function (provide, libName) {
    /* core + templates */
    oninit(function(exports, context) {
        context.BEMContext.prototype.requre = function(name) {
            return libName; 
        };
    });
});

// For CommonJS
oninit(function(exports, context) {
    var deps = context.BEMContext.prototype.libs = {};

    context.BEMContext.prototype.requre = function(name) {
        return require('path/to/module'); 
    };
});

If you want to get the dependency from the global scope for all modular systems:

{ 
    requires: {
        libName: {
            globals: 'dependName' // var name from global scope
        }
    } 
}

In bundle file will be as follows:

// For global scope
oninit(function(exports, context) {
    context.BEMContext.prototype.requre = function(name) {
        return dependName; 
    };
});

// For YModules
modules.define('BEMHTML', function (provide) {
    /* core + templates */
    oninit(function(exports, context) {
        context.BEMContext.prototype.requre = function(name) {
            return dependName; 
        };
    });
});

// For CommonJS
oninit(function(exports, context) {
    context.BEMContext.prototype.requre = function(name) {
        return dependName; 
    };
});

Support BEMContext from exports

See bem/bem-core#1099

Now we extend the definition of the basic templates with oninit. The BEMContext is available from context argument.

oninit(function(exports, context) {
    if(!context.BEMContext) {
        throw Error("Seems like you have no base templates from i-bem.' + this.getName() + '");
    }
    context.BEMContext.prototype.require = function(lib) {',
        return __bem_xjst_libs__[lib];
    };
});

In bem-core@v3 BEMContext wiil be available from exports argument only.

Support `*.js` suffix

The libraries may be two sets of templates:

old syntax

  • i-bem.bemhtml — base templates in xjst
  • block.bemhtml — source template in old syntax

JS syntax

  • i-bem.bemhtml.js — base templates in bem-xjst
  • block.bemhtml.js — source template in JS syntax

Import: templates with bemhtml suffix should be used only if templates with bemhtml.js suffix are missing for its BEM-entity (block, elem or mod).

Add an index for all inner techs

something like:

{
  bemhtml : require('./techs/bemhtml'),
  bemtree : require('./techs/bemtree'),
  htmlFromBemjson : require('./techs/htmlFromBemjson'),
  bemjsonToHtml : require('./techs/htmlFromBemjson'),
  // etc...
}

Build mock if not templates

If no template need build bundle without bem-xjst core. Instead of it need provide mocks.

This can be useful to build BEMHTML for run in browsers with depsByTech.

For BEMHTML apply method should always returns empty string:

BEMHTML.apply = function () { return ''; };

For BEMTREE apply method should always returns empty object:

BEMTREE.apply = function () { return Vow.resolve({}); };

Get rid of bemhtml-old

Now the only difference between bemhtml and bemhtml-old techs is the use of bemhtml-compat.

I suggest to run bemhtml-compat in bemhtml tech as optional step switched on by default so there won't be any reason to have 2 different techs any more.

// @arikon

Remove aliases

Option aliases are for backward compatibility deprecated options.

Inline CommonJS requires

requires: {
    lib: {
        commonJS: 'path/to/module'
    }
}

Now the code will contain a line with require('path/to/module'). Such file can not be used in a browser.

borschik:include относительно блока. Правильное раскрытие путей

Во всех наших проектах мы вставляем SVG в шаблоны. SVG бывает очень развесистым и переводить его в «строку» руками не очень удобно и быстро.

Мы попробовали вставлять SVG через /*borschik:include:…..*/, но в той схеме сборки, что реализована сейчас, нужно путь к файлу указывать относительно банда, а не блока.

Хочется как то так:

block('link').mod('theme', 'instagram').content()('borschik:include:link_theme_instagram.svg');

Думаю это интересное решение для вставки чего-то в шаблон. У нас есть возможность использовать один SVG файл для блока в шаблоне, в css и в js через такую конструкцию, кажется совершенно неправильным думать о пути к файлу из вне блока.

html-from-bemjson works only from enb-xjst

require('enb-bemxjst/techs/html-from-bemjson'),

does not work. To make my project buildable I had to use both enb-xjst and enb-bemxjst like this:

require('enb-bemxjst/techs/bemhtml-old'),                                                                          
require('enb-xjst/techs/html-from-bemjson'),

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.