Criando uma arquitetura de front-end do zero

8,611 views
8,474 views

Published on

Published in: Technology, Design
10 Comments
87 Likes
Statistics
Notes
  • adoro seus posts Shiota...sou uma front end 'dente de leite' ainda e leio muito o que posta e acompanho os posts do diego também no tableless. Vocês poderiam pensar num evento aqui em Curitiba, juntos né? ;)
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Estudante web design,Design gráfico e blogueira,acompanhando tudo e aprendendo muito sempre te espiando,fiquei feliz com a conquista do selo da baby pro meu blog pois vejo todo carinho e dedicação de um trabalho Parabéns Eduardo!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @ricardorictorres 'Inline images' são imagens transformadas em string em um esquema que representa um arquivo binário. Ou seja, quanto maior o arquivo, maior a string.

    Quando você converte uma imagem PNG em um arquivo binário, ela fica um pouco maior que o original, e todo esse peso fica 'embutido' no arquivo CSS. A vantagem de fazer isso é que você economiza uma requisição. A desvantagem é que chega uma hora que o peso a mais no CSS não compensa essa requisição economizada (que tem cache e expiração específicas). E uma medida conservadora é sempre fazer isso com imagens menores que 1KB.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Tenho uma dúvida: por que 'inline images' só devem ser usadas quando menores que 1KB?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @diegoeis Vou cobrar royalties =P
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
8,611
On SlideShare
0
From Embeds
0
Number of Embeds
130
Actions
Shares
0
Downloads
191
Comments
10
Likes
87
Embeds 0
No embeds

No notes for slide

Criando uma arquitetura de front-end do zero

  1. 1. Criando uma arquitetura de front-end do zero  @shiota 2013
  2. 2. olá! slideshare.net/eshiota github.com/eshiota @shiota
  3. 3. front-end engineer @
  4. 4. como a Baby (re)nasceu
  5. 5. * reprodução pelo WaybackMachine, não é 100% precisa
  6. 6. * reprodução do dia 27/08/2013
  7. 7. projeto greenfield (a.k.a. o sonho de todo desenvolvedor)
  8. 8. como estruturar o front-end do zero?
  9. 9. filosofia de um front-end de larga escala
  10. 10. Alta performance client-side.
  11. 11. Interface facilmente modificável.
  12. 12. Componentes portáveis entre diferentes aplicações.
  13. 13. Bulletproof web design. * veja http://simplebits.com/publications/bulletproof/
  14. 14. Tipografia e grids flexíveis, responsive-ready.
  15. 15. Baixa barreira de entrada para outros desenvolvedores.
  16. 16. definição de suporte aos navegadores
  17. 17. latest latest 5+ iOS 6+ 8+
  18. 18. latest latest 5+ iOS 6+ 8+ u mad?
  19. 19. O meu website precisa ter o visual exatamente igual em todos os navegadores?
  20. 20. O meu website precisa ter exatamente a mesma experiência em todos os navegadores?
  21. 21. A escolha dos navegadores e o nível de suporte influencia escolhas e tempo de desenvolvimento.
  22. 22. CSS
  23. 23. pre-processors: sass
  24. 24. O uso de partials ajuda a organizar os módulos.
  25. 25. @import "compass/css3"; @import "base/variables"; @import "base/functions"; @import "base/mixins"; @import "base/helpers"; @import "core/reset"; @import "core/basic"; @import "core/forms"; @import "core/tables"; @import "core/typography"; @import "core/icons"; @import "core/buttons"; @import "layout/main"; @import "layout/header"; @import "layout/footer"; @import "ui/loader"; @import "ui/loaderBar"; @import "ui/flashMessage"; @import "ui/breadcrumb";
  26. 26. app/ assets/ stylesheets/ base/ _functions.scss _mixins.scss _variables.scss ui/ _breadcrumb.scss _carousel.scss _dentedBox.scss _flashMessage.scss
  27. 27. Variáveis ajudam a manter os mesmos padrões de interface.
  28. 28. /********************************************************************* * * Variables Module * * All constants that will be used through the styles must be * defined here. * *********************************************************************/ /********************************************************************* * =Dimensions *********************************************************************/ $SITE_WIDTH: 978px; $FOOTER_HEIGHT : 812px; $DEFAULT_FONT_SIZE : 16px; /********************************************************************* * =Colors *********************************************************************/ $TEXT_COLOR: #555; $LINK_COLOR: #447f87; $PURPLE: #905194; $LIGHT: #fefefa; $ORANGE: #fbb100; $YELLOW: #fffd7d;
  29. 29. Mixins padronizam repetições de código.
  30. 30. /********************************************************************* * =Image replacement * * `display` property may be overridden by the element. *********************************************************************/ @mixin image_replacement { text-indent: 101%; overflow: hidden; white-space: nowrap; display: block; }
  31. 31. .my-logo { text-indent: 100%; overflow: hidden; white-space: nowrap; display: block; width: 200px; height: 280px; background: url("mylogo.png"); } .my-other-logo { text-indent: 100%; overflow: hidden; white-space: nowrap; display: block; width: 100px; height: 150px; background: url("myotherlogo.png"); }
  32. 32. .my-logo { @include image_replacement; width: 200px; height: 280px; background: url("mylogo.png"); } .my-other-logo { @include image_replacement; width: 100px; height: 150px; background: url("myotherlogo.png"); }
  33. 33. Mixins padronizam repetições de código.
  34. 34. /* <div class="section-header my-theme1"> ... </div> */ .section-header { width: 100%; height: 15em; color: #fff; background-color: #905194; background-position: center center; background-repeat: no-repeat; background-image: url("themes/default_bg.jpg"); text-align: center; } .my-theme1 { background-color: #fbb100; color: #fff; background-image: url("themes/theme1_bg.jpg"); } .my-theme2 { background-color: #fefefa; color: #333; background-image: url("themes/theme2_bg.jpg"); }
  35. 35. /* <div class="section-header my-theme1"> ... </div> */ @mixin header_theme($background_color: #905194, $text_color: #fff, $image: "default_bg.jpg") { background-color: $background_color; color: $text_color; background-image: url("themes/#{$image}"); }
  36. 36. /* <div class="section-header my-theme1"> ... </div> */ .section-header { @include header_theme; width: 100%; height: 15em; background-position: center center; background-repeat: no-repeat; text-align: center; } .my-theme1 { @include header_theme(#fefefa, #333, "theme2_bg.jpg"); } .my-theme2 { @include header_theme(#fefefa, #333, "theme2_bg.jpg"); }
  37. 37. (use com moderação)
  38. 38. Funções aceleram o processo de desenvolvimento.
  39. 39. // Returns unitless number @function remove-unit($number) { $unit: unit($number); $one: 1; @if $unit == "px" { $one: 1px; } @if $unit == "em" { $one: 1em; } @if $unit == "%" { $one: 1%; } @return $number / $one; } // Returns flexible value using `target ÷ context` formula. // Returns `em` by default, accepts `%` as format. @function flex($target, $context, $unit: "em") { $size: remove-unit($target) / remove-unit($context); @if $unit == "em" { @return #{$size}em; } @if $unit == "%" { @return percentage($size); } } // Alias to `flex` function, using `%` as format. @function perc($target, $context: $DEFAULT_FONT_SIZE) { @return flex($target, $context, "%"); } // Alias to `flex` function, using `em` as format. @function em($target, $context: $DEFAULT_FONT_SIZE) { @return flex($target, $context, "em"); }
  40. 40. .product-title { font-size: 1.5625em; /* 25px / 16px */ }
  41. 41. .product-title { font-size: em(25px, 16px); }
  42. 42. .product-title { font-size: em(25px); }
  43. 43. Sintaxe SCSS: quase não há curva de adaptação para quem já escreve CSS.
  44. 44. Extensões podem auxiliar de jeitos inimagináveis. (mais sobre isso daqui a pouco)
  45. 45. modularização
  46. 46. Front-end deve saber de programação?
  47. 47. CSS possui muitas similaridades com princípios de programação.
  48. 48. estrutura base (reset, base styles) grid padrões módulos módulos contextualizados
  49. 49. Single Responsability Principle Módulos de CSS possuem comportamentos contidos e isolados.
  50. 50. /***************************************************************************** * * UI » Flyout * * Flyouts are those UI components that look like tooltip, and * are activated when the user clicks on a link. The flyout window * opens text to the link, like those present on the iPad. * * **Usage** * * <div class="flyout-container"> * <div class="flyout [vertical-position]-[horizontal-position]-flyout"> * Flyout content * </div> * </div> * *****************************************************************************/ .flyout-container { position: relative; z-index: 100; // may be adjusted as needed through a context } .flyout { @include box-sizing(border-box); background: #f9f9f9; border-radius: 2px; border: 1px solid #d5d5d5; box-shadow: 0 2px 0 rgba(0, 0, 0, .1); display: none; position: absolute; // tip &:after { content: ""; display: block; width: 40px; height: 22px; background: sprite($icon-sprite, tooltip_top_large_gray) no-repeat; position: absolute; } } ...
  51. 51. Open/close Principle Módulos de CSS devem poder ser extendidos sem modificar sua definição core.
  52. 52. /******************************************************************************* * * UI > Loader * * Animated loader for AJAX requests * *******************************************************************************/ @mixin loader_sprite_position($xoffset, $yoffset) { background-position: sprite-position($icon-sprite, loader_sprite, $xoffset, $yoffset); } .loader { width: 25px; height: 25px; display: none; } .loader b { display: block; width: 25px; height: 25px; background-image: sprite-url($icon-sprite); } .loader b, .loader .f1 { @include loader_sprite_position(-10px, -10px); } .loader .f2 { @include loader_sprite_position(-45px, -10px); } .loader .f3 { @include loader_sprite_position(-80px, -10px); } .loader .f4 { @include loader_sprite_position(-115px, -10px); } .loader .f5 { @include loader_sprite_position(-150px, -10px); } .loader .f6 { @include loader_sprite_position(-185px, -10px); } .loader .f7 { @include loader_sprite_position(-220px, -10px); } .loader .f8 { @include loader_sprite_position(-255px, -10px); }
  53. 53. // On ui/_buttons.scss .bt-wrapper .loader { position: absolute; z-index: 4; right: 20px; top: 50%; margin-top: -9px; } // On modules/_checkoutAddressForm.scss .address-form .cep-input .loader { position: absolute; right: -33px; top: em(29px); }
  54. 54. Dependency Inversion Principle Módulos macro não devem ter seus layouts alterados por módulos micro.
  55. 55. .flyout
  56. 56. guias de estilo
  57. 57. #cheat #wip
  58. 58. JavaScript
  59. 59. qual framework usar?
  60. 60. Analise qual (ou se) vale a pena.
  61. 61. Você precisa de rotas client-side?
  62. 62. Você precisa de sincronização e persistência de modelos client-side?
  63. 63. Você precisa de uma solução pronta pra fazer bind entre view e dados?
  64. 64. Você precisa de uma estrutura pronta e fechada para manter a consistência do código?
  65. 65. Às vezes você não precisa de um framework terceiro. =)
  66. 66. Talvez tudo o que você precise seja um código consistente e organizado.
  67. 67. decisões de arquitetura
  68. 68. "Mas Shiota, todo mundo falou pra eu abandonar o jQuery!"
  69. 69. O jQuery diminui bastante a barreira de entrada e dá agilidade.
  70. 70. Analise a necessidade. Pese os benefícios. Pesquise outras soluções.
  71. 71. single entry points
  72. 72. (function(){ window.app = jQuery.extend({ init: function(){ tab = $('.tabs li > a.tab-toggle'); tabs = $('.tabs').find('> div'); if (tabs.length > 1){ tab.each(function (i){$(this).attr('href', '#content-' + ++i)}); tabs.each(function(i){$(this).attr('id', 'content-' + ++i)}); tabs.addClass('tab-inactive'); $('.tabs li:first-child a').addClass('state-active'); } $('#initial-cash, #financing_value_vehicles, #tax, #bid-initial-cash, #bid-product-value').maskMoney({ thousands: '.', decimal: ',', allowZero: true, allowNegative: false, defaultZero: true }); /** FINANCING CALCULATOR **/ $("#financing_value_vehicles").on("blur", function(){ var price = (accounting.unformat($(this).val(), ",")) || 0; var suggestedInitialPayment = price * 0.2; var formattedResult = accounting.formatMoney(suggestedInitialPayment, "", "2", ".", ","); $("#initial-cash").val(formattedResult); }); $("#calculate-financing").click(function(event){ var price = (accounting.unformat($("#financing_value_vehicles").val(), ",")) || 0; var rate = (accounting.unformat($("#tax").val(), ",") / 100) || 0; var initialCash = (accounting.unformat($("#initial-cash").val(), ",")) || 0; var value = (accounting.unformat($("#amount-finance").val(), ",")) || 0; var finance = price - initialCash; var months = (accounting.unformat($("#prize_parcela").val(), ",")) || 0; var tax = parseFloat(rate);
  73. 73. Page load jQuery load jQuery plugins application.js
  74. 74. Pontos únicos de entrada controlam o flow da aplicação.
  75. 75. Page load Vendor code Application modules application.js dispatcher.js beforeCommand controllerCommand actionCommand afterCommand
  76. 76. Page load Vendor code Application modules application.js dispatcher.js beforeCommand controllerCommand actionCommand afterCommand
  77. 77. <body data-dispatcher="<%= dispatcher_label %>">
  78. 78. <body data-dispatcher="products#show">
  79. 79. dispatcher.js beforeCommand() productsControllerCommand() productsShowCommand() afterCommand() products#show
  80. 80. Os commands não contêm lógica, apenas inicializam outros módulos.
  81. 81. namespaces
  82. 82. "JavaScript é zoado! Não tem nem namespaces!"
  83. 83. window.MYAPP = { commands : { productsShowCommand : function () { console.log("Execute code from products#show page"); } } }; MYAPP.commands.productsShowCommand();
  84. 84. "Mas ficar declarando objetos é um saco, e você pode acabar sobrescrevendo..."
  85. 85. ;(function (root) { root.ns = function (name, obj, scope) { var parts = name.split(".") , curScope = scope || root , curPart , curObj ; obj = obj || {}; while (typeof (curPart = parts.shift()) !== "undefined") { curObj = (parts.length > 0) ? ((typeof curScope[curPart] !== "undefined") ? curScope[curPart] : {}) : obj; curScope[curPart] = curObj; curScope = curScope[curPart]; } return curScope; }; })(this);
  86. 86. ns("MYAPP.commands.productsShowCommand", function () { console.log("Execute code from products#show page"); }); // Same as: window.MYAPP = { commands : { productsShowCommand : function () { console.log("Execute code from products#show page"); } } };
  87. 87. module.js
  88. 88. Define namespaces e coloca açúcar sintático na definição de funções construtoras.
  89. 89. window.EDEN = window.EDEN || {}; EDEN.forms = EDEN.forms || {}; EDEN.forms.AddressForm = function (el) { this.element = $(el); this.init(); } $.extend(EDEN.forms.AddressForm.prototype, { // Public methods // -------------- // Inits the instance init : function () { // Do something } }); var shippingAddressForm = new EDEN.forms.AddressForm($("#shipping-address"));
  90. 90. Module("EDEN.forms.AddressForm", function (AddressForm) { AddressForm.fn.initialize = function (el) { this.element = $(el); // Do form stuff } }); var shippingAddressForm = Module.run("EDEN.forms.AddressForm", $("#shipping-address")); // or var shippingAddressForm = new EDEN.forms.AddressForm($("#shipping-address"));
  91. 91. Padroniza a criação de novos módulos.
  92. 92. desacoplamento via eventos
  93. 93. MEDIATOR
  94. 94. MEDIATOR Mediator, me avisa quando sair o novo do Game of Thrones? Blz
  95. 95. MEDIATOR Mediator, me avisa quando sair o novo do Mythbusters? É nóish.
  96. 96. MEDIATOR Mediator, saiu um eppy novo de Game of Thrones. Subscribers, saiu um eppy novo de Game of Thrones! Ae, vou baixar, acho que vai ser feliz e tal =D
  97. 97. MEDIATOR Mediator, saiu um eppy novo de Mythbusters. Subscribers, saiu um eppy novo de Mythbusters! Ae, vou baixar!
  98. 98. Os módulos só conhecem o mediator.
  99. 99. testes
  100. 100. describe("EDEN.ui.Loader", function () { var Loader = EDEN.ui.Loader; beforeEach(function () { loadFixtures("loader.html"); }); afterEach(function () { $("body").find(".loader").remove(); }); it("accepts instance creation without new operator", function () { var newLoader = Loader(); expect(newLoader).toBeInstanceOf(Loader); }); it("appends the loader to body as a default", function () { var loader = new Loader(); expect($("body").find(".loader").length).toEqual(1); }); it("appends the loader through an argument function", function () { var loader = new Loader(function ($loader) { $("#loader-placeholder").append($loader); }); expect($("#loader-placeholder").find(".loader").length).toEqual(1); }); });
  101. 101. "Mas se eu escrever teste de JavaScript, eu não entrego o projeto!"
  102. 102. (e os testes de JavaScript quebram o build do CI.)
  103. 103. "Mas pra que teste de JavaScript?"
  104. 104. — "Precisamos atualizar o jQuery de 1.4 para 1.10"
  105. 105. Testes dão a segurança para atualizações, modificações e substituições.
  106. 106. HTML
  107. 107. sintaxe: erb
  108. 108. <% product.foreach_variant(current_cart) do |variant, size, i| %> <label class="variant"> <input value="<%= size.value %>" name="product_size" type="radio" data-price="<%= variant.price.to_f %>" data-variant-sku="<%= variant.sku %>" class="<%= "disabled" unless variant.has_stock? %>" /> <span class="variant-name"><%= size.value %></span> </label> <% end %>
  109. 109. Próximo do HTML puro.
  110. 110. Todos sabem (ou deveriam saber) escrever HTML puro.
  111. 111. Menos uma dependência no projeto.
  112. 112. classes semânticas
  113. 113. Dica 1: Sigam tudo o que o Diego Eis falou. =)
  114. 114. Usem classes que descrevem o conteúdo e não o estilo.
  115. 115. <div class="column-left"> <!-- Dropdown Categoria --> <!-- Dropdown Marca --> </div> <div class="column-right"> <!-- Product Navigation --> <!-- Products List --> </div>
  116. 116. column-left? column-right?
  117. 117. Classes semânticas desacoplam o documento do estilo.
  118. 118. <div class="products-search-filters"> <!-- Dropdown Categoria --> <!-- Dropdown Marca --> </div> <div class="products-search-filtered-results"> <!-- Product Navigation --> <!-- Products List --> </div>
  119. 119. products-search-filters products-search-filtered-results
  120. 120. Maior portabilidade do markup entre diferentes projetos.
  121. 121. data-attributes
  122. 122. contentDropdown.js
  123. 123. Componentes com mesmo comportamento podem ter estilos diferentes.
  124. 124. <div class="size-selector"> <div class="size-selector-header" data-dropdown-header> <!-- some title, could be anything --> </div> <div class="size-selector-content" data-dropdown-content> <!-- content here --> </div> </div> <div class="filter-selector"> <div class="filter-selector-header" data-dropdown-header> <!-- some title, could be anything --> </div> <div class="filter-selector-content" data-dropdown-content> <!-- content here --> </div> </div>
  125. 125. Classes diferentes, estilos diferentes.
  126. 126. data-attributes iguais, comportamento igual.
  127. 127. // Inits the `ContentDropdown` instance // // * `el`: jQuery selector init : function (el) { this.element = $(el); this.content = this.element.byData("dropdown-content"); this.selection = this.element.byData("dropdown-selection"); }
  128. 128. $.fn.byData = function (dataAttr) { return $(this).find("[data-" + dataAttr + "]"); };
  129. 129. Comportamento é adicionado através dos data-attributes.
  130. 130. dicas adicionais
  131. 131. performance client-side
  132. 132. Faça sprites. De preferência, de maneira automágica.
  133. 133. $icon-sprite: sprite-map("icon/*.png", $spacing: 16px, $repeat: no-repeat, $layout: vertical);
  134. 134. $icon-sprite: sprite-map("icon/*.png", $spacing: 16px, $repeat: no-repeat, $layout: vertical);
  135. 135. /* Compass sprite function receives the map variable and image as arguments */ background: sprite($icon-sprite, arrow_dropdown) no-repeat; /* Compiled CSS */ background: url(/assets/icon-s5dab8c2901.png) -40px -158px no-repeat;
  136. 136. Use inline images para imagens < 1KB que estarão apenas em um lugar do CSS.
  137. 137. /* Compiled CSS */ background: #f5f3fb url('data:image/ png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAMAAAAcVM5PAAAAGXRFWHRTb2Z0d2FyZQBBZG9 iZSBJbWFnZVJlYWR5ccllPAAAAAlQTFRF5+TW////////4qZUpQAAAAN0Uk5T// 8A18oNQQAAACBJREFUeNpiYGBgAgMGBkYog4mJXAbILAiDkVxzAAIMAEMOAPMId2OWAAAAAElFTkSuQmCC ') repeat; /* Generates a base64 image */ background: #f5f3eb inline-image("bg_dots.png") repeat;
  138. 138. Use lazy-load onde fizer sentido.
  139. 139. code standards
  140. 140. "O código deve parecer que foi escrito pela mesma pessoa, independente de quem o escreveu."
  141. 141. Código consistente: maior legibilidade, manutenção mais fácil, evita bikeshedding.
  142. 142. build para o deploy
  143. 143. Ruby on Rails » Asset Pipeline » ♥
  144. 144. TL;DR
  145. 145. Alta performance client-side Interface facilmente modificável Componentes portáveis entre diferentes aplicações Bulletproof web design Tipografia e grids flexíveis, responsive-ready Baixa barreira de entrada para outros desenvolvedores
  146. 146. Não saia adicionando códigos de terceiros sem pensar.
  147. 147. Front-end deixou de ser coisa de agência e sobrinho.
  148. 148. obrigado! slideshare.net/eshiota github.com/eshiota @shiota

×