Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Você ainda não sabe escrever JavaScript para aplicações Rails

Você ainda não sabe escrever JavaScript para aplicações Rails

Uma palestra com as principais tecnologias e técnicas utilizadas para escrever código JavaScript sano para diferentes tipos de aplicações. Uma viagem às antigas soluções Rails até as atuais e nem sempre suficientes jQuery UJS e Turbolinks. Aprenda sobre componentes auto-discoverable, comunicação através de eventos, modularização e gerência de dependências. Tudo isto sem deixar de fora alguns dos conceitos por trás dos principais frameworks MV* do mercado.

Jean Carlo Emer

August 29, 2014
Tweet

More Decks by Jean Carlo Emer

Other Decks in Programming

Transcript

  1. Você ainda não
    sabe escrever
    JavaScript para
    aplicações Rails!
    @jcemer

    View Slide

  2. JavaScript
    para apps
    Rails
    @jcemer

    View Slide

  3. http://jcemer.com

    View Slide

  4. View Slide

  5. Código JavaScript melhora a
    usabilidade através da
    adição de interatividade
    (ao menos deveria)

    View Slide

  6. 88%
    dos websites utilizam JavaScript
    http://w3techs.com

    View Slide

  7. Túnel do 

    tempo

    View Slide

  8. [...] é necessário ir ao passado para a
    compreensão de todos os
    questionamentos do tempo presente
    - Historiador Tiago Menta

    View Slide

  9. Rails era muito opinativo em
    relação à escrita de
    JavaScript

    View Slide

  10. O framework possuía uma
    série de helpers para gerar
    código para Prototype.js

    View Slide

  11. Envio assíncrono
    de formulários

    View Slide

  12. <%  form_remote_tag  :url  =>  '/'  do  -­‐%>  
           <%=  submit_tag  'Save'  %>  
    <%  end  -­‐%>
    index.erb

    View Slide




  13. index.html

    View Slide

  14. Rio Grande do Sul
    Porto Alegre

    View Slide

  15. <%=  observe_field(:local_estado_id,  
             :update  =>  "local_cidade_id",  
             :url  =>  cidades_options_for_select_path,  
             :with  =>  "estado_id"  %>
    index.erb

    View Slide

  16.                name="local[estado_id]">  
    !
     <br/>//<![CDATA[  <br/>    new  Form.Element.EventObserver('local_estado_id',        <br/>!<br/>!<br/>!<br/>//]]>  <br/>
    !@#$%^@!%
    index.html

    View Slide

  17. Alto acoplamento do HTML com
    Prototype.js
    Tags scripts espalhadas no markup

    View Slide

  18. Existia também o RJS para
    escrever código Prototype.js 

    no back-end

    View Slide

  19. Resposta para 

    chamadas Ajax

    View Slide

  20. update_page  do  |page|  
       page.insert_html  :bottom,  'list',    
           "#{@item.name}"  
       page.visual_effect  :highlight,  
    'list'  
    end
    controller/action.rb

    View Slide

  21. Resposta para 

    chamadas Ajax

    View Slide

  22. new  Element.insert("list",    
           {  bottom:  "Some  item"  });  
    new  Effect.Highlight("list");
    response.js

    View Slide

  23. Alto acoplamento do código
    back-end com Prototype.js

    View Slide

  24. JavaScript não deve estar no
    markup
    Código back-end não deve
    depender de biblioteca front-end.


    View Slide

  25. Evolução
    do Rails

    View Slide

  26. Tudo aquilo que você está perdendo
    se a sua aplicação ainda não foi
    atualizada

    View Slide

  27. Rails 3.0
    Fim das chamadas Ajax através de
    JavaScript inline e dos observers
    https://github.com/rails/prototype_legacy_helper

    View Slide

  28. Rails 3.0
    Nascimento do projeto
    Unobtrusive JavaScript
    https://github.com/rails/prototype-ujs

    View Slide

  29. Confirmar ação

    View Slide

  30. <%=  link_to  "Other  Site",  "url",    
        data:  {  confirm:  "Are  you  sure?"  }  %>
    index.erb

    View Slide

  31.  
      Other  Site
    index.html
    Qualquer biblioteca
    pode endereçar a
    funcionalidade

    View Slide

  32. Envio assíncrono
    de formulários

    View Slide

  33. <%=  form_for  @post,  remote:  true  %>
    index.erb

    View Slide


  34. index.html
    Qualquer biblioteca
    pode endereçar a
    funcionalidade

    View Slide

  35. Considere que o formulário
    também pode ser enviado
    sincronamente pelo usuário
    E se não executar o 

    JavaScript?

    View Slide

  36. Configurar o método 

    de requisição

    View Slide

  37. <%=  link_to  "Destroy",  "url",  

                             method:  :delete  %>
    index.erb

    View Slide

  38.  
       Destroy
    index.html

    View Slide

  39. deletar notícia

    View Slide

  40. O usuário irá apenas ler a notícia,
    considere sempre utilizar
    formulários para este tipo de ação
    E se não executar o 

    JavaScript?

    View Slide

  41. Um pequeno
    parêntese sobre
    atributos data-*
    (

    View Slide

  42. Data attributes são a melhor
    alternativa para armazenar
    informações adicionais de um
    elemento

    View Slide

  43. $('.element').data('remote');
    sample.js (jQuery)

    View Slide

  44. $('[data-­‐element]').data('remote');
    Recomendado, mesmo
    que afete na performance
    http://jsperf.com/class-vs-data-attribute

    -selector-performance
    sample.js (jQuery)

    View Slide

  45. ) Classes do HTML são
    para semântica, o
    JavaScript não deve
    ser baseado nelas

    View Slide

  46. Rails 3.1
    Suporte a Prototype.js e RJS é
    removido dando espaço à jQuery

    View Slide

  47. jQuery é a biblioteca front-end
    mais adequada da atualidade

    (valorize e aprenda de verdade)

    View Slide

  48. As actions ainda podem entregar
    código JavaScript

    View Slide

  49. Requisição Ajax

    View Slide

  50. $('#photo_<%=  params[:id]  %>').remove();
    destroy.js.erb
    photo.html
         data-­‐method="delete"    
         data-­‐remote="true">Destroy  

    View Slide

  51. <%-­‐  if  @contact.errors.any?  %>  
       $('#contact-­‐modal').html('<%=  
    escape_javascript(render(partial:  'form'))  
      )  %>');  
    <%-­‐  else  %>  
       $('#contact-­‐modal').html('<%=  
    !
         
    !
      $('#contact-­‐modal').append('alert-­‐success">Your  message  was  successfully  

    sent  ');  
       setTimeout("$('.close').click();",  2000);  
    <%-­‐  end  %>
    !@#$%^@!%
    create.js.erb

    View Slide

  52. Rails 3.1
    Adoção da linguagem CoffeeScript
    que transpila para JavaScript

    View Slide

  53. Não usamos CoffeeScript 

    por aqui!
    - muitos de vocês

    View Slide

  54. class  Counter  
       constructor:  (@min  =  0,  @max  =  10e9)  -­‐>  
           @current  =  @min  
       next:  -­‐>  
           @current  =  Math.min(@max,  @current  +  1)  
       isFirst:  -­‐>  
           @current  <=  @min  
    !
    class  CounterPlus  extends  Counter  
       goToLast:  -­‐>  
           @current  =  @max
    counter.coffee

    View Slide

  55. function  Counter(min,  max)  {  
           this.min  =  min  !=  null  ?  min  :  0;  
           this.max  =  max  !=  null  ?  max  :  10e9;  
           this.current  =  this.min;  
    }  
    !
    Counter.prototype.next  =  function()  {  
           return  this.current  =  

          Math.min(this.max,  this.current  +  1)  
    }  
    !
    Counter.prototype.isFirst  =  function()  {  
           return  this.current  <=  this.min  
    }  
    !
    function  CounterPlus()  {  
    counter.js

    View Slide

  56. !
    Counter.prototype.isFirst  =  function()  {  
           return  this.current  <=  this.min  
    }  
    !
    function  CounterPlus()  {  
           Counter.apply(this,  arguments)  
    }  
    !
    function  InheritCounter()  {}  
    InheritCounter.prototype  =  Counter.prototype  
    !
    CounterPlus.prototype  =  new  InheritCounter()  
    CounterPlus.prototype.constructor  =  CounterPlus  
    !
    CounterPlus.prototype.goToLast  =  function()  {  
           return  this.current  =  this.max  
    }

    View Slide

  57. Syntax sugar para "classes"
    Arrow functions e fat arrow
    functions para binding com this


    View Slide

  58. Não é por nada que o EcmaScript 6
    usa o CoffeeScript como
    referência

    View Slide

  59. ♥CoffeeScript

    View Slide

  60. Rails 4.0
    Adoção da biblioteca JavaScript
    Turbolinks

    View Slide

  61. O Turbolinks objetiva reduzir
    pela metade o tempo de
    carregamento de uma página

    View Slide

  62. RUBYCONF


    CONHEÇA OS
    PALESTRANTES
    PROMETE TRAZER
    NOVIDADES E
    ASSUNTOS
    PERTINENTES DA
    ÁREA

    View Slide

  63. RUBYCONF


    CONHEÇA OS
    PALESTRANTES
    PROMETE TRAZER
    NOVIDADES E
    ASSUNTOS
    PERTINENTES DA
    ÁREA
    Requisição Ajax pela
    página apontada no link

    View Slide

  64. RUBYCONF


    CONHEÇA OS
    PALESTRANTES
    PROMETE TRAZER
    NOVIDADES E
    ASSUNTOS
    PERTINENTES DA
    ÁREA

    View Slide

  65. RUBYCONF
    PALESTRANTES
    FÁBIO AKITA

    HANNELI TAVANTE

    JEAN CARLO EMER
    Substituição do conteúdo

    do da página com
    a resposta

    View Slide

  66. A barra de endereços é
    atualizada e as páginas
    visitadas são armazenadas
    (voltar à uma página é imediato)

    View Slide

  67. Assets devem ficar no e
    precisam ser marcados para que
    modificações sejam monitoradas
    (e recarregada caso preciso)

    View Slide

  68. Código JavaScript não será
    executado na troca de páginas

    View Slide

  69. Além de, 

    é preciso também esperar por
    $.ready(fn)
    $(document).on('page:load',  fn)
    $(document).on('page:restore',  fn)

    View Slide

  70. Widgets e add-on podem não
    funcionar como esperado

    View Slide

  71. Suporte para widgets do Facebook,
    Twitter, Google+, Google Analytics,
    AdSense e alguns mais
    http://reed.github.io/turbolinks-compatibility

    View Slide

  72. É preciso cuidado dobrado para
    evitar memory leaks

    View Slide

  73. A cada transição os events handlers e
    demais callbacks devem ser
    desativados para não interferir na
    performance

    View Slide

  74. Código JavaScript pode ser
    executado na troca de páginas
    Widgets e add-ons funcionam de
    acordo depois de ajustados
    Memory leaks podem ser evitados



    View Slide

  75. O Turbolinks não permite que
    apenas porções da página sejam
    requisitadas
    (confira o jquery-pajax para isto)

    View Slide

  76. Turbolinks funciona bem 

    em websites simples (como o 

    desta conferência) e forma uma 

    boa dupla com UJS

    View Slide

  77. Evolua você
    também

    View Slide

  78. Rails é framework full-stack para criar
    aplicações, mas você provavelmente
    irá precisar de mais

    View Slide

  79. Organização de código JavaScript
    e modularização
    Componentes front-end
    Bibliotecas e frameworks 

    front-end



    View Slide

  80. Modularização
    de código 

    JavaScript

    View Slide

  81. O JavaScript não possui sistema de
    módulos fazendo com que diferentes
    scripts compartilhem o mesmo escopo

    View Slide

  82. file1.js
    file2.js
    Sem a criação de um
    escopo, as variáveis
    ficam expostas
    var  myVar  =  "bla";
    alert(myVar);

    View Slide

  83. (function  ()  {  
       var  data  =  {};  
       function  parser()  {  
         
       //  Code  
       }  
    })();
    Immediately-Invoked
    Function Expression
    viabilizam a criação
    de escopos
    http://benalman.com/news/
    2010/11/immediately-
    invoked-function-expression

    View Slide

  84. Não polua o escopo global, os
    demais desenvolvedores agradecem

    View Slide

  85. Com a criação de escopos com uma
    única responsabilidade, surge a
    necessidade de acessar dependências

    View Slide

  86. App.modules.mediabox  =  (function  ()  {  
       var  data  =  {};  
    !
       return  {  
         
       data:  data,  
         
       parser:  //  ...  
       }  
    })();
    Namespaces
    mediabox.js (namespace)

    View Slide

  87. Module('modules.mediabox',  

       function  (Mediabox)  {  
           Mediabox.data  =  {};  
         Mediabox.parser  =  //  ...  
       }  
    );
    Biblioteca de módulos
    do Nando Vieira
    http://simplesideias.com.br/
    escrevendo-javascript-modular
    mediabox.js (Module.js)

    View Slide

  88. define(  
       [  
           'jquery',    
           'util/counter'  
       ],  
       function  ($,  Counter)  {  
           //  ...          
           return  {  
               Mediabox:  Mediabox,  
               //  ...  
           };  
       }

    );
    mediabox.js (AMD)
    Módulos AMD que
    permitem indicação
    de dependências
    https://github.com/
    jwhitley/requirejs-rails

    View Slide

  89. Declaração de dependências
    Path do arquivo como identificador
    do módulo
    Assíncrono por natureza e adotado

    por jQuery e outras bibliotecas



    View Slide

  90. [...] it makes code easier to
    understand for others and
    yourself re-visting your own
    code
    - Chris Coyier

    View Slide

  91. ES6 Modules e CommonJS Modules
    não possuem suporte adequado 

    ao Asset Pipeline
    (alguém se habilita?)

    View Slide

  92. Componentes
    front-end

    View Slide

  93. Um componente encapsula
    elementos HTML, CSS e
    comportamento

    View Slide

  94. Template, 

    CSS e JS
    Template, 

    CSS e JS

    View Slide

  95. Web Components é a
    salvação do front-end,
    use agora!!
    - algum desavisado

    View Slide

  96. Web Componentes com Polymer é
    ainda um experimento e não deve
    ser utilizado em produção

    View Slide

  97. Mas temos muito o que aprender
    sobre JavaScript com os Web
    Components

    View Slide

  98. 1. Instanciação de 

    Componentes

    View Slide

  99. main.js
    //  Setup  product  page  
    if  ($('body').is('.page-­‐product'))  {  
       $("[data-­‐draggable]").draggable()  
       $("[data-­‐comments]").comments()  
    }  
    !
    //  Setup  checkout  page  
    if  ($('body').is('.page-­‐checkout'))  {  
       $("[data-­‐draggable]").draggable()  
       $("[data-­‐datepicker]").datepicker()  
    }

    View Slide

  100. Componentes podem ser removidos
    ou adicionados necessitando
    manutenção no JavaScript

    View Slide

  101. main.js
    //  Setup  product  page  
    if  ($('body').is('.page-­‐product'))  {  
       $("[data-­‐draggable]").draggable()  
       $("[data-­‐comments]").comments()  
    }  
    !
    //  Setup  checkout  page  
    if  ($('body').is('.page-­‐checkout'))  {  
       $("[data-­‐draggable]").draggable()  
       $("[data-­‐datepicker]").datepicker()  
    }

    View Slide

  102. Web Components, Angular.js e Dojo
    usam o HTML como referência para
    instanciar componentes

    View Slide

  103. Definindo 

    componentes com
    Piecemaker
    https://github.com/jcemer/

    piecemaker

    View Slide

  104. Definição de um
    componente
     
       Mediabox  content  

    index.html

    View Slide

  105. define(function  ()  {  
       function  Mediabox(container)  {  
           //  ...  
       }  
       return  Mediabox;  
    });
    Chamada do construtor

    com o container
    mediabox.js

    View Slide

  106. 2. Data-binding

    View Slide

  107. Gerenciar dados no front-end não
    é tarefa simples

    View Slide

  108. Trabalhar com models que emitem
    eventos é trabalhoso e passível a erros
    (não entenda mal, Backbone.js)

    View Slide

  109. Valor: R$50,00
    Quantidade: 1
    Model 

    quantidade: 1
    script.js

    View Slide

  110. Valor: R$50,00
    Quantidade: 3
    Model 

    quantidade: 1
    script.js

    View Slide

  111. Valor: R$150,00
    Quantidade: 3
    Model 

    quantidade: 3
    script.js

    View Slide

  112. Valor: R$500,00
    Quantidade: 10
    Model 

    quantidade: 10
    script.js

    View Slide

  113. Data-binding no

    Angular

    View Slide

  114.  
                           ng-­‐init="quantity=1">  
           110  
         
       Valor:  R$  {{price()}}  

    index.html
    function  Basket($scope)  {  
           $scope.price  =  function  ()  {  
                   return  $scope.quantity  *  50;                      
           };  
    }
    main.js

    View Slide

  115. Frameworks como Angular.js,
    React, Ember e Knockout.js
    implementam data-binding

    View Slide

  116. A EcmaScript e a especificação do
    HTML5 estão evoluindo para
    melhor endereçar data-binding

    View Slide

  117. 3. Frameworks

    View Slide

  118. Componentes no Angular
    http://jsfiddle.net/api/post/library/pure/

    View Slide

  119.  
         
             
               Date:  {{  '2012-­‐04-­‐01'  |  date:'fullDate'  }}  
             
             
               Hi!  
             
         

    Tags são mapeadas
    para templates e
    controllers

    View Slide

  120. A partir daqui, o HTML não
    é válido e sem um pouco
    de cuidado...

    View Slide

  121. View Slide

  122. What’s wrong with Angular.js
    https://medium.com/este-js-framework/whats-
    wrong-with-angular-js-97b0a787f903
    What I would recommend instead of
    Angular.js?
    https://medium.com/este-js-framework/what-i-
    would-recommend-instead-of-angular-
    js-62b057d8a9e

    View Slide

  123. Retornar do servidor uma página
    em branco ou inválida é um
    desperdício

    View Slide

  124. Considere utilizar um framework
    JavaScript quando estiver escrevendo
    uma Rich Internet Application

    View Slide

  125. Sempre aprenda a
    fundo antes tudo o que
    for utilizar
    - bom senso

    View Slide

  126. Dicas finais para você que
    quer fazer código ainda
    melhor (e está acordado)
    [

    View Slide

  127. Estude sobre execução de
    código assíncrono com callbacks
    e promises
    https://speakerdeck.com/jcemer/controle-de-
    fluxo-com-execucao-assincrona
    1.

    View Slide

  128. Aceite que o JavaScript do front-end
    da sua aplicação pode dar tanto ou
    mais trabalho que o back-end
    2.

    View Slide

  129. ]Obrigado 

    a todos
    criem produtos incríveis
    @jcemer

    View Slide