Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Владимир Гриненко
Search
FrontFest
November 21, 2017
Programming
740
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Владимир Гриненко
FrontFest
November 21, 2017
More Decks by FrontFest
See All by FrontFest
Тим Чаптыков
frontfest
0
1.2k
Егор Банщиков
frontfest
0
900
Jose M. Perez
frontfest
0
760
Алексей Иванов
frontfest
0
1.4k
Екатерина Пригара
frontfest
0
710
Léonie Watson
frontfest
0
780
Кирилл Чернышев
frontfest
0
770
Виктор Грищенко
frontfest
0
660
Игорь Алексеенко
frontfest
0
510
Other Decks in Programming
See All in Programming
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
240
Foundation Models frameworkで画像分析
ryodeveloper
1
620
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
330
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
570
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
810
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
340
複数の Claude Code が"放置"されてしまう問題をCLI ダッシュボードを自作して解決した話
sumihiro3
1
700
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
420
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
310
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
530
引き算の組織 ― アウトカムとAIに全振りするために辞めたこと ― / Organization by Subtraction
hirokiyamamoto14
PRO
0
250
改善しないと、タスクが回らない。 “てんこ盛りポジション” を引き継いだ情シスの、入社3ヶ月の業務改善録
krm963
0
270
Featured
See All Featured
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Building Adaptive Systems
keathley
44
3.2k
Why Our Code Smells
bkeepers
PRO
340
58k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
780
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
280
Joys of Absence: A Defence of Solitary Play
codingconduct
1
440
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.3k
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
490
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Designing Experiences People Love
moore
143
24k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
Transcript
Декларативная шаблонизация Владимир Гриненко руководитель службы
Декларативность
Декларативное программирование — это парадигма программирования, в которой задается спецификация
решения задачи, то есть описывается, что представляет собой проблема и
4
Императивно
document Императивно 6
document .querySelectorAll('.link') Императивно 7
document .querySelectorAll('.link') .forEach(link => link.style.color = 'red'); Императивно 8
document .querySelectorAll('.link') .forEach(link => link.style.color = 'red'); document.body.innerHTML += '<a
class="link" href="http://2017.frontfest.ru">FrontFest</a>'; Императивно 9
document .querySelectorAll('.link') .forEach(link => link.style.color = 'red'); document.body.innerHTML += '<a
class="link" href="http://2017.frontfest.ru">FrontFest</a>'; Императивно 10 document.querySelector('.link').classList.remove('link');
Декларативно
.link { color: red } Декларативно 12
library/components/link.css .link { color: red } Декларативно 13 project/components/link.css .link
{ text-decoration: none }
$('.btn').click(function() { $(this) .toggleClass('btn_disabled') .text( $(this).text() === 'Enable' ? 'Disable'
: 'Enable' ); }); Императивно 14
<Btn onToggleDisabled={this.handleToggleDisabled} disabled={this.state.disabled}> {this.state.buttonText} </Btn> Декларативно 15
Шаблонизация
<div class="user"> Elizabeth </div> Шаблонизация 17
<div class="user"> <?php echo $username; ?> </div> Шаблонизация 18
const html = `<div class="user">${username}</div>`; Шаблонизация 19
20
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> Dropdown button </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> <a class="dropdown-item" href="#">Something else here</a> </div> </div> Шаблонизация 21
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Шаблонизация 22
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Шаблонизация 23
Проблемы 24 〉Много писать 〉Много исправлять 〉Невозможно обновиться автоматически
const html = `<div class="user">${username}</div>`; Шаблонизация 25
render() { return ( <div className="user"> {this.props.username} </div> ); }
Компонентный подход 26
<User username="Elizabeth"/> Компонентный подход 27
Проблемы решены 28 〉Много писать 〉Много исправлять 〉Невозможно обновиться автоматически
render() { return ( <div className="user"> {this.props.username} </div> ); }
Еще проблемы 29
render() { return ( <div className="user"> {this.props.hasIcon && <Icon/>} {this.props.username}
</div> ); } Еще проблемы 30
library/components/link.css .link { color: red } Декларативно 31 project/components/link.css .link
{ text-decoration: none }
32
Больше декларативности!
XML + XSLT
<User username="Elizabeth"/> <User username="Elizabeth II" hasIcon="true"/> XML + XSLT 35
<xsl:template match="User"> <div class="user"> <xsl:apply-templates/> <xsl:apply-templates select="@username"/> </div> </xsl:template> XML
+ XSLT 36
<xsl:template match="User[hasIcon=true]"> <xsl:apply-templates select="Icon"/> </xsl:template> XML + XSLT 37
BEMJSON + BEMHTML
{ block: 'user', username: 'Elizabeth' } Полная декларативность 39
{ block: 'user', username: 'Elizabeth' } Полная декларативность 40 <div
class="user"></div>
block('user').content()(node => node.ctx.username); Полная декларативность 41
block('user').content()(node => node.ctx.username); block('user') .match()(node => node.ctx.hasIcon) .content()(node => [
{ block: 'icon' }, applyNext() ]); Полная декларативность 42
block('user').content()(node => node.ctx.username); block('user') .match()(node => node.ctx.hasIcon) .content()(node => [
{ block: 'icon' }, applyNext() ]); Полная декларативность 43
block('user').content()(node => node.ctx.username); block('user') .match()(node => node.ctx.hasIcon) .content()(node => [
{ block: 'icon' }, applyNext() ]); Полная декларативность 44
block('data')( tag()('ul'), elem('item').tag()('li') ); Полная декларативность: теги 45
block('data')( tag()('table'), content()(() => ({ tag: 'tr', content: applyNext() })),
elem('item').tag()('td') ); Полная декларативность: теги 46
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> Dropdown button </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> <a class="dropdown-item" href="#">Something else here</a> </div> </div> Полная декларативность: реальный пример 47
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Полная декларативность: реальный пример 48
<div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-
haspopup="true" aria-expanded="false"> <?php echo $buttonText; ?> </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <?php for ($i = 1; $i <= count($items); $i++) { ?> <a class="dropdown-item" href="<?php echo $items[$i] ["href"]; ?>"><?php echo $items[$i]["text"]; ?></a> <?php } ?> </div> </div> Полная декларативность: реальный пример 49
block('dropdown')( content()(node => [ { block: 'btn', mods: { secondary:
true }, mix: 'dropdown-toggle', attrs: { type: 'button', id: 'dropdownMenuButton', 'data-toggle': 'dropdown', 'aria-haspopup': true, 'aria-expanded': false } }, { elem: 'menu', attrs: { 'aria-labelledby': 'dropdownMenuButton' }, content: applyNext().map(item => ({ elem: 'item', url: item.url, content: item.text })) } ]), Полная декларативность: реальный пример 50 elem('item').replace()(node => ({ block: 'link', mix: node.ctx, url: node.ctx.url, content: node.ctx.content })) )
{ block: 'dropdown', content: [ { elem: 'item', url: 'http://site1.com',
text: 'Site1' }, { elem: 'item', url: 'http://site2.com', text: 'Site2' }, { elem: 'item', url: 'http://site3.com', text: 'Site3' } ] } Полная декларативность: реальный пример 51
const css = require('./css.json'), visited = {}; block('*') .match()(node =>
!visited[node.block]) .replace()(node => { visited[node.block] = true; return [ css[node.block], this.ctx ]; }); Полная декларативность: любой узел 52
53 bem.github.io/bem-xjst
54 github.com/bem/bh-php
$bh->match('button', function ($ctx) { $ctx->tag('button'); }); bh.php 55
Синтаксис может быть любым
React
bem-react-core
Что это 59 〉Обертка над стандартными React-компонентами 〉Полностью совместимая со
стандартными компонентами 〉Не требует знания БЭМ 〉Не требует использования модификаторов 〉Не требует использования уровней переопределения
Что это 60 〉Автоматизирует генерацию классов 〉Позволяет использовать элементы, модификаторы
и миксы 〉Позволяет использовать уровни переопределения 〉Оперирует компонентами, а не путями
None
<div class="user"> Elizabeth </div> Пример 62
export default class User extends Component { render() { return
( <div className="user">{this.props.username}</div> ); } } Было 63
import {decl} from 'bem-react-core'; export default decl({ block: 'user', content({username})
{ return username; } }); Стало 64
export default decl({ block: 'User', willMount() {}, didMount() {}, willReceiveProps()
{}, shouldUpdate() {}, willUpdate() {}, didUpdate() {}, willUnmount() {} }); Livecycle-методы 65
import User from 'b:user'; ReactDOM.render( <User />, //... ); Импорт
66
var User = [ require('path/to/user/user.js') ][0].applyDecls(); ReactDOM.render(<User />); Импорт 67
Траншпилеры 68 〉webpack-bem-loader 〉babel-plugin-bem-import
Какие проблемы решает bem-react-core
Какие проблемы 70 〉Модификации бывают опциональными › отдельные файлы ›
можно выразить через class ButtonWithIcon extends Button
Какие проблемы 71 〉Модификации бывают опциональными 〉Композитные модификации › пересечение
всех вариантов не выражается через наследование › Button, Button_compound, Button_with-icon
import { BaseComponent, warn } from '../../Utilities'; import { ButtonType,
IButtonProps } from './Button.Props'; import { DefaultButton } from './DefaultButton/DefaultButton'; import { CommandButton } from './CommandButton/CommandButton'; import { CompoundButton } from './CompoundButton/CompoundButton'; import { IconButton } from './IconButton/IconButton'; import { PrimaryButton } from './PrimaryButton/PrimaryButton'; Например, кнопка 72 github.com/OfficeDev/office-ui-fabric-react
public render() { const props = this.props; switch (props.buttonType) {
case ButtonType.command: return <CommandButton { ...props } />; case ButtonType.compound: return <CompoundButton { ...props } />; case ButtonType.icon: return <IconButton { ...props } />; case ButtonType.primary: return <PrimaryButton { ...props } />; default: return <DefaultButton { ...props } />; } } Например, кнопка 73
<Button compound primary icon="check"></Button> А теперь с bem-react-core 74 Декларативно!
// Button_type_compound.js import {declMod} from 'bem-react-core'; import React from 'react';
export default declMod(({ type }) => type === 'button', { block: 'Button', mods({ type }) { return { ...this.__base.apply(this, arguments), type }; }, content() { return <Button … /> } }); Модификатор 75
import Button from 'b:Button m:type=compound'; <Button type="compound">my button</Button> Модификатор 76
None
Шаблонизация в bem-react-core 78 〉tag 〉attrs 〉mods 〉cls 〉mix 〉content
Уровни переопределения
Для чего 80 〉Общая библиотека и проекты
Для чего 81 〉Общая библиотека и проекты lego serp images
video news
Для чего 82 〉Общая библиотека и проекты 〉Платформы
Для чего 83 〉Общая библиотека и проекты 〉Платформы common desktop
touch
Для чего 84 〉Общая библиотека и проекты 〉Платформы common desktop
touch pad phone
Для чего 85 〉Общая библиотека и проекты 〉Платформы 〉Дизайн
Для чего 86 〉Общая библиотека и проекты 〉Платформы 〉Дизайн 〉Эксперименты
experiments exp1 exp2 exp3
None
library/components/link.css .link { color: red } Как это работает 88
project/components/link.css .link { text-decoration: none }
[ 'path/to/level1', 'path/to/level2' ] Уровни переопределения 89
/* styles.css */ @import path/to/level1/block1/block1.css; @import path/to/level2/block1/block1.css; Уровни переопределения 90
// blocks/Link/Link.js import decl from 'bem-react-core'; export default decl({ block:
'Link', tag: 'a', attrs(({url}) => ({href: url})) }); <Link url="…">… <a class="Link" href="…">… Уровни переопределения 91
// blocks/Link/Link.js // a11y/blocks/Link/Link.js import decl from 'bem-react-core'; export default
decl({ block: 'Link', attrs() { return { ...this.__base.apply(this, arguments), role: 'link' }; } } <Link url="…">… <a class="Link" href="…" role="link">… Уровни переопределения 92
None
94 github.com/bem/bem-react-core
95 Пишите декларативно!
None
Вопросы?
None
Владимир Гриненко
[email protected]
tadatuta tadatuta tadatuta