UNPKG

bem-md-renderer

Version:

The builder markdown to html with custom renderer, which generates the html headlines like github

488 lines (373 loc) 16.7 kB
# BEMHTML: a templating engine for BEM **BEMHTML** is a templating engine for thous who are using [BEM metodology](https://bem.info/method) for web development. BEMHTML is: * an HTML layout in terms of blocks, elements and modifiers; * support of BEM-style CSS; * support of BEM-style JS; * declarative and impressive templates; * convenient code support for long-term developing projects. <a name="worldview"></a> ## BEMHTML: картина мира BEM methodology and BMHTML, as it's part, are the product of many-ears experience of web development and maintenance of web interfaces at Yandex. Web development at Yandex were affected by the following factors: * the need of creating a common portal style; * the need for long-term maintainable code; * the need of quick changes in the projects; * joint work on the code of different specialists. BEM was created as a solution for all these problems. At the first place it's a set of web development principles (a world-view), and only at second it's a technology. BEMHTML is one of technologies that helps to carry development according to BEM principles. Hence the problems, that BEMHTML is solving, are imposed by the same principles as for BEM. ## BEMHTML: картина мира After this principle stands a conviction that HTML and CSS are not suitable for a semantic description of web interfaces (as a framework). The reason is in the difference of interpretation of HTML and CSS for different browsers. As the result, one needs to include into HTML and CSS specific elements for providing a cross-browser compatibility. For example, in the recent past, for making a cross-browser rounded corners one needed to wrap an element in six nested `div`. Web interfaces should be described in hight-level terms (as header, button, menu, etc.). That allows us to separate **semantics** and **implementation**. Such contrast helps to divide the labor of those who design the structure of the interface (design, usability, connection with the back-end), and those who are aware of the subtleties of HTML coding (cross-browser compatibility, support for IE, etc.). The conversion (translation) of high-level interface terms in the low-level command language of the browser (HTML + CSS) reminds a compilation *assembler for the web*. ** The task for a templating engine: separate the logic of interface realization and HTML-representation. ** * Templates and the organization of interface (a set of element and layout for the page) should be described separately. BEM structure of interface is described by **BEM tree**. It's a hierarchical structure of blocks, elements and modifiers. * Templates define only the rules of HTML-decoration for the certain parts of the interface. According to BEM methodology, for each part of interface there is a corresponding ***BEM entity* (block or element with modifiers). ## BEMHTML: картина мира This principle is not unique for the web developing, and it's unlikely to cause objections. However technological features of many templating engines are often forcing to code duplication. This problem arises when the same interface element (for example a button) is being used many times. The code for the button has to be repeated on every page for every its usage. If the button changes, the developer will have to update templates of every page where the button appears. Even if the templating engine allows us to put the code for the button into the global function, in every page the button code needs to be replaced by the function call. **A templating engine should provide the ability of creation of flexible libraries of templates** Flexibility for a library means the following, for the project developer it's: * ability to use any template as a bock for the page building; * ability to modify easily any template in the project without making any changes in the library source code; for the library developer: * there should be no need of pre-design of special parts that can be overridden in the future. ### BEM BEMHTML is an expansion of BEM methodology to HTML. BEM gives an opportunity to designer, interface developer, JavaScript-coder to speak one language (in the same terms, these terms are Blocks, Elements, Modifiers). BEMHTML allows HTML coders to join them. ** The task: tools for HTML-development in terms of BEM.** * There should be a template for each BEM entity (block, element or modifier). * CSS integration within BEM style (BEM classes should be generated automatically for all blocks, elements and modifiers). * JS integration within BEM style (JS parameters should be generated automatically for blocks, elements and modifiers). ## Capability of BEMHTML ### Web-page in terms of BEM (Blocks, Elements, Modifiers) - Page structure is described in BEMJSON format, it's a JavaScript representation of the BEM tree; - The templating engine converts the BEM tree into a HTML code; - CSS integration within the BEM style - JS integration within the BEM style #### Examples The templating engine receives the following data: ```js { block: 'widgets', content: [ { elem: 'weather', content: 4 } ] } ``` There is no need in a template (the data is handled by default templates). The resulting HTML: ```xml <div class="widgets"> <div class="widgets__weather">4</div> </div> ``` If the `weather` block has a JavaScript realization with usage of `i-bem.js` one needs to use the following template for passing JavaScript parameters into the block: ```js block weather, js: { id: Math.random() * 1e4 } ``` The resulting HTML: ```xml <div class="widgets i-bem" onclick="return { 'weather': { 'id': 4321 } }"> <div class="widgets__weather">4</div> </div> ``` ### Syntax for data and templates description is based on JavaScript. - Declarative templates: the template consists of condition for usage (predicate) and data structure, that describes the resulting HTML (the template body). - JavaScript syntax is extend with a key-words (`block`, `elem`, `mods`, `elemMods`) for working with BEM entities. - For the templates an arbitrary JavaScript code can be used. There is no technical limitations placed by BEMHTML on operations in predicates or template. An efficiency and consistency of templates work is provided by developers agreements. - All BEMHTML templates are compiled in JavaScript, therefore it can be executed at the server side as well, as at the client side. #### Examples Definition of HTML tags in a declarative style: ```js block widgets { tag: 'ul' elem weather, tag: 'li' } ``` The resulting HTML: ```xml <ul class="widgets"> <li class="widgets__weather">4</li> </ul> ``` Arbitrary calculations performed in the template body: ```js block widgets, elem weather, content: { var oldContent = applyNext() return oldContent > 0 ? '+' : '' + oldContent + ' °C' } ``` The resulting HTML: ```xml <ul class="widgets"> <li class="widgets__weather">+4 °C</li> </ul> ``` ### Flexibility and extendability - BEMHTML allows us to separate a layout into an **independent blocks**, that can be combined among themselves without any restrictions. - ***Definition Levels* allow us to collect templates into libraries, and then can be used in other projects. #### Examples The input-data: ```js { block: page, content: [ { block: header, content: 'Title 1' }, { block: header, mods: { level: 2 }, content: 'Title 2' } ] } ``` Templates defined in the library: ```js block header, tag: 'h1' block header, mod level 2, tag: 'h2' ``` Templates defined in the project: ```js block header, tag: 'h2' block header, mod level 2, tag: 'h3' ``` The result: ```xml <div classs="page"> <h2 class="header"> Title 1 </h2> <h3 class="header header_level_2"> Title 2 </h3> </div> ``` ### Multi-time implementation - During runtime BEMHTML can generate additional elements, that are needed for solving layout problems (different kinds of wrappings). The initial data (BEM tree) can be modified during the templates implementation. Moreover, the same templates can be applied again to modified data. Therefore all layout wrappings can be implemented without messing-up the input data with extra elements. #### Examples The input data is a name of Yandex user: ```js { block: 'ya-user', content: 'Hamster' } ``` The template selects the first letter of the name and wraps it into instantly generated element: ```js block ya-user, content: { var oldContent = applyNext(); return [ { elem: 'first-letter', content: oldContent[0] }, oldContent.substring(1) ] } ``` The resulting HTML: ```xml <div class="ya-user"><div class="ya-user__first-letter">H</div>amster</div> ``` ## BEMHTML and other temlating engines <a name="andothers"></a> There are hundreds of different kinds of template engines. Among all of them several fields of application (generation of HTML and other text formats) and a few different approaches for text generation from data by using a template can be distinguished. By its approaches BEMHTML can be classified as "exotic". Let's take a look at several classification principles of templating engines and the place of BEMHTML among them. ### Classification by semantics (what does the templating engine) #### Strings interpolation The templating engine places a corresponding to needed data string into the text of template. In addition different conditions, variables and loops can be used. It's the largest class of templating engines. ```%username%, don't worry, be happy!``` Templaing engines of this kind: * [Mustache](http://mustache.github.com) * [Handlebars](http://handlebarsjs.com) * [Jade](https://github.com/visionmedia/jade) * [DustJS](http://linkedin.github.com/dustjs/) #### Data bind A templating engine associates data with HTML by using some rules. The rules are described separately form the HTML. ```js var html ="<span class="name"/> "+ "don't worry, be happy!" , data = { username: 'John Smith' } , map = plates.Map(); map.class('name').to('username'); plates.bind(html, data, map); ``` Examples: * [Transparency](https://github.com/leonidas/transparency) * [Flatiron.js](http://flatironjs.org/#templating) * [Angular.js](http://angularjs.org) * [Pure](http://beebole.com/pure/) **Live data bind**: the connection with a changing data can also be declared. An example of such templating engine is [Knockout.js](http://knockoutjs.com). #### Data driven A templating engine connects a data key-word with a fragment of input HTML. In this case at the begging we have the data structure, and later with help of templates it's converted into HTML. In the approaches mentioned above, a page is built form a template, that is filled up with some data. For example the XSLT template below doesn't place any restrictions on the data structure, it can include key-worlds: ```xml <xsl:template match="username"> <span class="name"> <xsl:apply-templates/> </span> </xsl:template> ``` It can also be used with the data: ```xml `<username>John Smith</username>, don't worry, be happy!` ``` Or: ```xml <ul> <li><username>Veni</username>,</li> <li><username>Vidi</username>,</li> <li><username>Vici</username></li> </ul> ``` Examples: * [XSLT](http://www.w3.org/TR/xslt) * BEMHTML ### Classification by semantics #### The final version of the text with special insertions This model is correlated with strings interpolation approach. A template looks very similar to the final HTML: ```xml <span class="name">[% username %]</span> ``` There is no need of learning a special syntax, and very often it's mentioned as an advantage of this approach. Examples: * [Mustache](http://mustache.github.com) * [Handlebars](http://handlebarsjs.com) * [DustJS](http://linkedin.github.com/dustjs/) #### Short HTML notation HTML language has a peculiar syntactic redundancy. Almost all tags have to be in pairs (one opening and one closing tag). For example if we want to declare 'there is a table', we need to mention `table` two times: in the opening tag and in the closing tag. To simplify code writing and make it more readable, some developers suggest to use the short notation for HTML. For example: ``` span.name #{username} ``` Example: #### The object-oriented syntax In this approach the rules for the HTML generation are described in a template, according to the data scope of the templating engine. ```js var html = "<span class="name"/> "+ "don't worry, be happy!" , data = { username: 'John Smith' } , map = plates.Map(); map.class('name').to('username'); plates.bind(html, data, map); ``` Examples: * [XSLT](http://www.w3.org/TR/xslt) * [Flatiron.js](http://flatironjs.org/#templating) * BEMHTML ### Classification by the base language #### One basic language The templating engine accepts only the certain programming language, and all control structures of the templates are written in this language. Examples: * [XSLT — XML](http://www.w3.org/TR/xslt) * [ECO — CoffeeScript](https://github.com/sstephenson/eco) * BEMHTML — JavaScript #### Compiling in a few different languages In the templating engine its own data scope is created. It's simple enough to allow compilation of control structures into a wide range of programming languages. Examples: * [TT2](http://www.template-toolkit.org/) * [Mustache](http://mustache.github.com) ### Why BEMHTML was build this way * **Data driven**. Templates are bounded to the data elements. Therefore it's possible to create templates as a **declarative** and **atomic** (independent and self-sufficient) statements, which connects an element with its representation in HTML. For example the *tag* of the *block "header" - `table`*. BEM-style CSS describes the style with atomic statements: the *color* of the *block "header" - red**. Such templates are similar to modules (in sense of the way they are built). Regardless to its location, the key-word will be handled by the same template. Hence there is no need of code duplication. Also the atomic statements is easy to redefine, therefore allows us to build flexible libraries. * **Subject-oriented syntax**. The main criteria for the syntax selection are: the small size of templates (without a need to repeat tags two times) and the ability to bound templates to BEM entities (but not to the HTML nodes). * **JavaScript is the basic language** JavaScript as a basic language gives many advantages: performance, portability, the active development of technologies, and the last but very important, it's familiar to HTML-coders. ### Why not XSLT? According to the classification mentioned above, BEMHTML fits to the same categories as XSLT. XSLT was being used a lot at Yandex. However BEM developers refused XSLT and developed their own templating engine because of the following reasons: * **Problems of Performance**. Implementation of transformations in XSLT has significant performance limitations. The solutions based on XSLT have significantly lower speed in comparison to the solutions based on other temolating engines. * **XSLT isn't being developed anymore**. In fact XSLT wasn't developing during the last few years. Despite the fact that in 2007 the specification XSLT 2.0 was published. Its implementation is still far from its serious usage in the real-world applications. In the absence of active development of XSLT one cannot expect performance improvements or extension of functionality. * **XSLT is not designed to work in BEM termss** In order to maximize the integration of templating engine in a set of bem-tools, a native support of BEM data scope is needed at the level of the template engine. ## How to try? ### A template of a project To start using BEHTML you need to clone [a project template](https://github.com/bem/project-stub). It has already: a prepared structure for a project, the blocks library [bem-bl](https://github.com/bem/bem-bl), environment customized for the building process and the result viewing, and very simple static page. In fact, the template of this project is a startup for a HTML coder. It can be extended with custom blocks, and any project can be based on it. ### Documentation * [Step-by-step BEMHTML guide](https://bem.info/technology/bemhtml/current/intro/) * [BEMHTML reference](https://bem.info/technology/bemhtml/current/reference/) * [bem-tools reference](https://bem.info/tools/bem/bem-tools/) * [The blocks bem-bl library documentation](https://bem.info/libs/bem-bl/)