Porque estudar Web Components?

Este artigo será útil para o entendimento sobre os Web Components, uma tecnologia nova da HTML5 que vem ganhando cada vez mais notoriedade e que visa auxiliar o desenvolvedor front-end na criação de componentes customizados.

Além do entendimento sobre a tecnologia, o artigo também visa esclarecer alguns receios comuns da comunidade de desenvolvedores em torno dos Web Components que poderiam impactar negativamente nossos projetos ao utilizá-la.

Os principais receios explorados no artigo são: acessibilidade, semântica, indexação e performance.


Guia do artigo:

A HTML5 nos trouxe inúmeros recursos novos como os Web Components. Os Web Components podem ser divididos em cinco categorias: Custom Elements, Templates, HTML Imports, Shadow DOM e Decorators.

Essas tecnologias visam ajudar o desenvolvedor front-end na criação de novos componentes com o auxílio nativo do browser. Apesar dos componentes web ganharem cada vez mais notoriedade, muitas dúvidas e receios ainda costumam surgir entre os desenvolvedores, envolvendo assuntos como acessibilidade, semântica, SEO e performance no client-side.

Explorando os assuntos do ponto de vista dos Web Components percebemos que podemos facilmente contornar tais receios utilizando algumas técnicas e tecnologias já consolidadas no desenvolvimento front-end.

É possível utilizarmos microdados, WAI-ARIA, e as tags semânticas da HTML5 para aumentarmos a acessibilidade e semântica dos componentes.

Buscadores como o Google aperfeiçoam constantemente o algoritmo do sistema de busca e recentemente engenheiros da empresa declararam no blog oficial já ser possível indexar o conteúdo gerado com JavaScript.

Essa notícia diminui a preocupação de utilizarmos recursos como templates, uma vez que para tal é necessário a utilização de manipulação do conteúdo via JavaScript.

O único dificultador na utilização da tecnologia de fato é o suporte dos navegadores. Felizmente, os principais navegadores já iniciaram o processo de implementação dos Web Components.

Enquanto aguardamos o suporte deles, é possível explorar os polyfills (código que pode ser baixado para prover facilidades que não estão implementadas nos browsers nativamente) que existem no mercado como o Polymer mantido pelo Google, o X-Tags pela Mozilla e o Bosonic.

Diante do grande furor gerado pelo lançamento dessas tecnologias, os mais entusiasmados consideram que os Web Components são o futuro da web.

E de fato são, principalmente ao se considerar que a sua adesão ainda não aconteceu plenamente pela comunidade de desenvolvedores e sobretudo pelos principais navegadores do mercado.

Além do apoio que esses projetos fornecem à utilização dos Web Components, profissionais mais experientes e bastante conhecidos na comunidade de desenvolvimento web têm escrito artigos, realizado workshops e palestrado em eventos incentivando o estudo a fim de que os desenvolvedores conheçam e apoiem a nova tecnologia.

É bem verdade que muitas iniciativas de separar aplicações em parte menores, muitas vezes chamadas de componentes, deram origem a muitos projetos que foram adotados por muitos desenvolvedores web.

Projetos como Twitter Bootstrap, Zurb Foundation, Pure.css, Semantic UI e tantos outros ganharam reconhecimento e continuam sendo utilizados em larga escala.

A maioria possui uma vasta variedade de componentes, auxiliam no desenvolvimento responsivo, foram demasiadamente testados e são suportados pelos principais navegadores.

Diante de projetos bem consolidados, muitos podem se perguntar qual o grande diferencial dos Web Components. Resumidamente, os Web Components são a promessa de padronizar e tornar nativo nos navegadores os recursos que até hoje têm sido uma solução criativa e alternativa por parte dos desenvolvedores que criaram substitutos a altura.

O que são os Web Components?

De acordo com a especificação da W3C, os Web Components consistem em “um conjunto de cinco tecnologias: Templates, Shadow DOM, Custom Elements, HTML Imports e Decorators”. Sendo que essa última, diferente das demais, ainda não possui uma especificação e tem sido bastante omitida pela comunidade, por esses motivos os exemplos disponíveis nesse artigo não farão menção aos decoradores.

Para facilitar o entendimento do conjunto de tecnologias podemos defini-las da seguinte forma:

  • Templates: Templates representam uma sub árvore no DOM que permanece inerte e é enxertada na árvore principal. O trecho de código contido no template serve para a criação de componentes dinâmicos, possibilitando que o desenvolvedor instancie e manipule tal código sob demanda.

    Devido a inércia dos templates o navegador não realiza a requisição das imagens e não executa os scripts contidos nos mesmos até que sejam enviados para a página via JavaScript.

  • Shadow Dom: O Shadow DOM realiza o isolamento de elementos do DOM em trechos independentes evitando que estilos CSS e comportamentos JavaScript dos elementos alterem as características uns dos outros.
  • Custom Elements: O Custom Element permite que o desenvolvedor crie tags diferentes das convencionais. O intuito é encapsular as demais tags numa personalizada, reutilizável, manutenível e manuseável. Essa tecnologia auxilia bastante na diminuição dos enormes aninhamentos de divs, conhecidos como div hell. Custom Elements também possibilitam que os elementos personalizados herdem características e propriedades de tags nativas específicas como a tag <button>, por exemplo.
  • HTML Import: Com o HTML Import podemos importar documentos HTML inteiros para dentro de nossas páginas. De uma maneira semelhante à importação de um arquivo JavaScript ou CSS;, o HTML Import cria uma nova requisição ao servidor para realizar o download do arquivo. Essa tecnologia auxilia no encapsulamento dos componentes em arquivos externos possibilitando importá-los posteriormente.

    Antes do HTML Imports, as poucas alternativas de importarmos documentos HTML eram através de elementos iframes e requisições AJAX, não muito bem vistas do ponto de vista do código limpo.

  • Decorators: Os decoradores aplicam os templates com base em seletores CSS e JavaScript para criar mudanças visuais e comportamentais. O elemento "content" inserido dentro do template será substituído com o conteúdo do elemento de decoração.

    E através do atributo "select" é possível especificar a posição exata do elemento particular na marcação que será produzida. Com o CSS em conjunto com as Media Queries seria possível criar uma poderosa ferramenta de Responsive Web Design utilizando decoradores.

Veja nas Listagens 1 e 2 um exemplo simples e de cunho didático onde podemos visualizar os quatro componentes web: Templates, Shadow DOM, Custom Elements e HTML Imports funcionando em conjunto.

Nota: É importante ressaltar que os únicos navegadores até o momento que implementam as quatro tecnologias são o Google Chrome e o Opera.

Listagem 1. Arquivo componente-loading.html portador do componente de carregamento (Loading...)

  01 <html>
  02     <head>
  03         <script>
  04             var NovoComponente = document.registerElement('loading-componente', {
  05                 prototype: Object.create(HTMLElement.prototype, {
  06                     createdCallback: {
  07                         value: function(){
  08                           var 
  09                           link     = document.querySelector('link[rel=import]'),
  10                           t        = link.import.querySelector('#tpl-loading'),
  11                           clone    = document.importNode(t.content, true);
  12                           element  = this,
  13                           text     = this.getAttribute('text'),
  14                           animates = clone.querySelectorAll('.load-anime div');
  15                             clone.querySelector('.load-anime').classList.add("circle");
  16                           clone.querySelector('.loading-text').innerHTML = text;
  17                           element.createShadowRoot().appendChild(clone);
  18                         }
  19                     }
  20                 })
  21             });
  22         </script>
  23     </head>
  24     <body>
  25         <template id="tpl-loading">
  26             <style>
  27                 .loading {
  28                     height: auto;
  29                     margin: 10px auto;
  30                     text-align: center;
  31                     width: auto;
  32                 }
  33                 .loading p {
  34                     font-family: 'Arial';
  35                     font-weight: bold;
  36                 }
  37                 .load-anime div{
  38                   background: #FF5700;
  39                   display: inline-block;
  40                 }
  41                 .circle{
  42                   height: 10px;
  43                 }
  44                 .circle div {
  45                   border-radius: 100%;
  46                   display: inline-block;
  47                   height: 10px;
  48                   width: 10px;
  49                   -webkit-animation: scale 1.2s infinite ease-in-out;
  50                   animation: scale 1.2s infinite ease-in-out;
  51                 }
  52                 .load-anime .load-anime2 {
  53                   -webkit-animation-delay: -1.1s;
  54                   animation-delay: -1.1s;
  55                 }
  56                 .load-anime .load-anime3 {
  57                   -webkit-animation-delay: -1.0s;
  58                   animation-delay: -1.0s;
  59                 }
  60                 .load-anime .load-anime4 {
  61                   -webkit-animation-delay: -0.9s;
  62                   animation-delay: -0.9s;
  63                 }
  64                 .load-anime .load-anime5 {
  65                   -webkit-animation-delay: -0.8s;
  66                   animation-delay: -0.8s;
  67                 }
  68                 @-webkit-keyframes scale {
  69                   0%, 40%, 100% { -webkit-transform: scale(0.4) }  
  70                   20% { -webkit-transform: scale(1.0) }
  71                 }
  72                 @keyframes scale {
  73                   0%, 40%, 100% { 
  74                     transform: scale(0.4);
  75                     -webkit-transform: scale(0.4);
  76                   }  20% { 
  77                     transform: scale(1.0);
  78                     -webkit-transform: scale(1.0);
  79                   }
  80                 }
  81             </style>
  82             <div class="loading">
  83               <div class="load-anime"> 
  84                 <div class="load-anime1"></div>
  85                 <div class="load-anime2"></div>
  86                 <div class="load-anime3"></div>
  87                 <div class="load-anime4"></div>
  88                 <div class="load-anime5"></div>
  89               </div>
  90               <p class="loading-text"></p>
  91             </div>
  92         </template>
  93     </body>
  94 </html>

Listagem 2. Arquivo index.html importa e faz uso do componente de carregamento

  01 <!DOCTYPE html>
  02 <html lang="pt-br">
  03 <head>
  04     <meta charset="utf-8">
  05     <title>Web Components</title>
  06     <meta name="description" content="Web Components">
  07     <link rel="import" href="componente-loading.html">
  08 </head>
  09 <body>
  10     <loading-componente text="Loading"></loading-componente>
  11 </body>
  12 </html>

No primeiro exemplo do nosso artigo criamos um novo elemento de carregamento animado, muito conhecido como “Loading...”. Antes das animações em CSS era muito comum a utilização de imagens GIF, arquivos em Flash e até mesmo JavaScript para a criação de elementos como esse.

Agora com o uso da versão três do CSS para animar o elemento e com os componentes web podemos facilmente encapsulá-lo e torná-lo customizável de acordo com cada necessidade do desenvolvedor.

No arquivo componente-loading.html criamos o nosso componente propriamente dito. Entre as linhas 4 e 20 manipulamos o DOM para criarmos o componente baseado no template que fora definido entre as linhas 25 e 92.

O template é bem simples, ele possui regras de estilo e algumas “divs” que realizam a animação do elemento, além do parágrafo que receberá o texto do atributo “text” definido no elemento. Perceba também que para criá-lo fazemos uso direto da tag template do próprio framework.

O arquivo index.html realiza a importação do componente através da linha 7 e declara o componente de carregamento na linha 10. O componente criado possui um atributo chamado “text” que possui o texto que será exibido junto ao elemento renderizado, nesse caso a palavra “Loading”.

O resultado da execução deste exemplo pode ser visualizado na Figura 1, assim como o código HTML gerado na Listagem 3.

Componentes de carregamento gerados com Web Components através do Google Chrome
Figura 1.Componentes de carregamento gerados com Web Components através do Google Chrome.

Listagem 3. Código-fonte inspecionado através do Chrome DevTools.

<!DOCTYPE html>
  <html lang=”pt-br”>
   <head>
    <meta charset=”utf-8”>
    <title>Web Components</title>
    <meta name=”description” content=”Web Components”>
    <link rel=”import” href=”loading-componente.html”>
     #document
    </link>
   </head>
   <body cz-shortcut-listen=”true”>
    <loading-componente text=”Loading”>
     #shadow-root
     <style>...</style>
     <div class=”loading”>
      <div class=”load-anime circle”>
       <div class=”load-anime1”></div>
       <div class=”load-anime2”></div>
       <div class=”load-anime3”></div>
       <div class=”load-anime4”></div>
       <div class=”load-anime5”></div>
      </div>
      <p class=”loading-text”>Loading</p>
     </div>
    </loading-componente>
   </body>
  </html>

Exemplos bem mais complexos e elaborados podem ser visualizados através do endereço customelements.io na seção Links do artigo, que funciona como um repositório de elementos criado com Web Components e compartilhado pela comunidade de desenvolvedores.

A quantidade de elementos tem crescido a cada dia, mostrando que muitos desenvolvedores têm aderido à tecnologia. Também é importante destacar que muitos elementos foram criados baseados nos projetos que já existem, e possuem boilerplates (código clichê) que facilitam na implementação dos novos elementos.

Além dos boilerplates para os projetos citados também podemos usar um boilerplate que utiliza o VanillaJS (seção Links) para customizar nossos elementos.

Mesmo com tantos benefícios, os Web Components ainda têm preocupado os desenvolvedores mais cautelosos, os que gostam de analisar e ver as coisas acontecerem antes de se alvoroçarem.

Os principais receios giram em torno do usuário final e de aspectos como: acessibilidade, semântica, indexação do conteúdo por meio dos mecanismos de busca e performance no client-side.

As novas tecnologias que compõem o conjunto dos componentes da web possuem características bem peculiares, e que tem relação direta e indireta com tais aspectos.

As novas tecnologias possibilitam importar arquivos HTML inteiros aumentando o número de requisições ao servidor, algo que implicaria na performance da nossa aplicação; encapsular parte do DOM em sub níveis mais profundos podendo dificultar o acesso ao conteúdo por parte de sintetizadores de voz ou robôs de busca, algo que afetaria a acessibilidade ou a indexação de conteúdo prejudicando o SEO; e a criação de novos elementos HTML de forma arbitrária podendo prejudicar a semântica do conteúdo.

Com a finalidade de nos aprofundarmos em tais receios e analisarmos se realmente oferecem algum impeditivo para o futuro dos componentes web, vamos averiguar as principais áreas que podem afetar o usuário final.

De uma forma macro e dentro das limitações atuais impostas pelos navegadores e pela tecnologia, realizamos uma série de pesquisas e testes que forneceram o embasamento para o artigo.

Acessibilidade

A acessibilidade é um fator importantíssimo do ponto de vista do usuário. Permitir que o mesmo acesse o conteúdo da melhor forma possível é um esforço geral que pode envolver inúmeros profissionais como arquitetos de informação, desenhistas, desenvolvedores e outros. A tecnologia, por sua vez, é o meio pelo qual tais profissionais disponibilizarão a informação para o usuário final.

A W3C considera quatro princípios como a base da web acessível: percepção, operabilidade, compreensão e robustez comumente conhecidos como POUR (perceivable, operable, understandable, and robust).

Esses são os pilares que regem a web para todos. O objetivo desses princípios é permitir que todos tenham a chance de navegar na internet sem que sejam impedidos por suas limitações visuais, auditivas, cognitivas, motoras ou qualquer outra.

Em palestras sobre Web Components são bastante comuns indagações a respeito da acessibilidade. A preocupação faz sentido quando pensamos na forma de isolamento e customização que os Web Components nos oferece.

As principais dúvidas são se o Shadow DOM, com seu forte encapsulamento, ou a criação de novos elementos poderiam afetar de alguma forma a navegação do usuário ou o acesso ao conteúdo.

Tomando como base a biblioteca Polymer, um dos mais famosos projetos relacionados ao assunto e que tem por finalidade tornar a criação de aplicações web mais fáceis e rápidas utilizando Web Components, foram feitas algumas asserções para averiguar se há algum impacto na acessibilidade quando utilizamos essas tecnologias.

Uma bateria de testes simples que englobaram leitores de telas, navegação por teclado, inversão no esquema de cores, alteração na resolução da tela, uso de dispositivos móveis (smartphones e tablets), sistemas operacionais e navegadores diferentes foi realizada usando alguns dos principais componentes (menu dropdown, menu accordeon, slider, botões, checboxes, tooltip e outros) do Polymer.

Utilizando leitores de tela como VoiceOver para OSX, NVDA no Windows e o plugin ChromeVox do Google Chrome foi possível perceber que não há muita diferença entre um componente construído de forma convencional com recursos nativos da HTML e JavaScript comparados com os Web Components.

O único contratempo encontrado durante o teste de navegação assistida ocorreu ao utilizarmos o plugin ChromeVox, uma vez que o mesmo não foi capaz de acessar e ler o conteúdo encapsulado pelo Shadow DOM.

A navegação por teclado não funciona tão bem quanto esperado, não por culpa da tecnologia dos Web Components, mas por falta de aprimoramento nos componentes testados.

Alguns elementos não respondem bem à navegação utilizando a tecla “tab”, algo que poderia ser facilmente resolvido com o atributo “tabindex” da própria linguagem HTML. Outro fator importante na navegação via teclado é saber a posição que nos encontramos na tela.

Alguns dos elementos testados removeram a propriedade CSS outline dificultando a orientação do usuário na página. Além da navegação, é importante que ações dos componentes respondam as interações dos usuários provocadas via teclados, algo que não ocorre muito bem e pode ser melhorado via JavaScript.

Ao alterar a resolução da tela e esquema de cores nenhum problema fora do esperado ocorreu que impactasse na utilização da tecnologia. Os testes nos dispositivos, plataformas e navegadores foram bem razoáveis apesar de o suporte ainda ser bem precário.

Entretanto, é muito importante ressaltar que esse tipo de teste só foi possível devido a utilização do Polymer, sem o mesmo não seria possível a realização destes.

Apesar do cenário de teste ter sido baseado em um polyfill e não utilizando a tecnologia final, ficou claro que para tornar um website ou aplicação web acessível dependemos muito mais das pessoas envolvidas na execução do projeto do que da tecnologia em si.

Ao contrário do que possa parecer, os componentes web se utilizados de uma maneira inteligente podem ser grandes aliados para enriquecer a acessibilidade de nossas páginas.

Semântica

A versão cinco da HTML ampliou a sua coleção de tags da linguagem. Dentre as finalidades está a de enriquecer a semântica do conteúdo disponibilizado na internet. Muitos desenvolvedores têm usufruído de tags como: <article>, <section>, <nav>, <aside>, <header>, <footer> e tantas outras que nos auxiliam a estruturar e dar mais sentido às nossas páginas.

Além das novas tags semânticas, a HTML5 provê outros recursos para ampliar o significado. Os microdados, por exemplo, destinam-se a dar mais sentido ao conteúdo web para que possam ser lidos por máquinas, como mecanismo de busca, web crawlers, navegadores, leitores de tela, e outros, com a finalidade de enriquecer a experiência do usuário. A WAI-ARIA (Web Assessibility Initiative - Accessible Rich Internet Applications) é outro excelente recurso que possibilita dar sentido às interações que ocorrem na página transmitindo ao usuário o significado de suas ações.

Sabe-se que, com o advento dos Web Components, o desenvolvedor ganha a liberdade de criar suas próprias tags, podendo uni-las com a coleção de tags nativas da linguagem HTML.

A única regra que o desenvolvedor deve atentar é que para criar as novas tags ele precisará respeitar o padrão dash case, ou seja, a criação das tags customizadas deverá contemplar o caractere "-" separando as palavras do novo elemento.

Nesse caso <meu-elemento> é um nome válido enquanto <meuElemento> ou <meuelemento>, não. Além do hífen, o desenvolvedor deverá atentar para algumas combinações de palavras reservas como: annotation-xml, color-profile, font-face, font-face-format, font-face-name, font-face-src, font-face-uri e missing-glyph. Essas palavras podem ser encontradas nas especificações SVG e MathML, cujos links estão disponíveis na página oficial do W3C.

Outra forma bem simples de verificar se o nome para o novo componente encontra-se disponível é utilizar a ferramenta online mothereff.in, disponibilizada pelo Mathias Bynens e que utiliza o módulo do Node.js validate-element-name criado por Sindre Sorhus.

A liberdade concedida pelos Web Components na criação dos nossos próprios elementos não deveria ser algo preocupante do ponto de vista semântico, pois, apesar de toda essa liberdade, é possível que o desenvolvedor mantenha a semântica do seu conteúdo utilizando os recursos citados: Microdados e WAI-ARIA.

Listagem 4. Componente de painel com abas que utiliza WAI-ARIA

  01 <!-- Menu em Abas -->
  02 <tabs-menu role="tabsmenu">
  03   <tab-item href="tab-1" role="tab" aria-selected="true">Custom Elements</tab-item>
  04   <tab-item href="tab-2" role="tab">Templates</tab-item>
  05   <tab-item href="tab-3" role="tab">Shadow DOM</tab-item>
  06   <tab-item href="tab-3" role="tab">HTML Import</tab-item>
  07 </tabs-menu>
  08 
  09 <tab-panel id="tab-1" role="tabpanel" aria-labelledby="customelements">
  10   Conteúdo sobre Custom Elements...
  11 </tab-panel> 
  12 <tab-panel id="tab-2" role="tabpanel" aria-labelledby="template">
  13   Conteúdo sobre templates...
  14 </tab-panel> 
  15 <tab-panel id="tab-3" role="tabpanel" aria-labelledby="shadowdom">
  16   Conteúdo sobre Shadow DOM
  17 </tab-panel> 
  18 <tab-panel id="tab-4" role="tabpanel" aria-labelledby="htmlimport">
  19   Conteúdo sobre HTML Import
  20 </tab-panel>

O exemplo da Listagem 4 demonstra a utilização de um componente de navegação por abas que foi enriquecido pelo uso de WAI-ARIA. Perceba que agora fazemos uso de tags antes nunca reconhecidas pela HTML, em quaisquer browsers que executassem.

A estrutura dos itens de tabs aliada aos elementos roles (que lembram muito os do Bootstrap) complementam a implementação deixando o entendimento fácil até para quem nunca usou Web Components.

Essa estrutura também é muito similar à de frameworks como o jQuery UI, que provê funções JavaScript para produzir o mesmo efeito que temos na listagem, porém exigindo a necessidade de importação de duas bibliotecas externas à aplicação.

Alguns desenvolvedores ainda não sabem, mas ao utilizarmos Custom Elements para a criação de novos elementos podemos estender elementos nativos herdando suas propriedades e semântica.

Nesse caso para criarmos um botão baseado na sua versão nativa da HTML, por exemplo, basta definirmos seu protótipo como sendo uma instância do objeto HTMLButtonElement, tal como demonstrado na Listagem 5.

Isso é possível graças ao uso da função registerElement presente no próprio objeto DOM JavaScript, além disso, esse modelo pode ser usado para definir quaisquer outros elementos que o leitor desejar.

Listagem 5. Estendendo o elemento nativo button.

  01 var meuBotao = document.registerElement(meu-botao, {
  02   prototype: Object.create(HTMLButtonElement.prototype),
  03   extends: 'button'
  04 });

Outro detalhe importante do ponto de vista semântico, é que além de fornecer sentido ao conteúdo de suas páginas, um bom desenvolvedor front-end deve se preocupar com a semântica do seu código a fim de que outros profissionais possam facilmente entender e dar continuidade ao projeto.

Portanto, deve-se tomar cuidado ao escolher o nome do novo marcador evitando encurtar demais o nome dos elementos de forma que perca o significado. Evite simplificar demais o componente como no exemplo da Listagem 6, por exemplo.

O conceito é o mesmo que já usamos para declaração de variáveis em qualquer linguagem de programação.

Listagem 6. Componente com nome demasiadamente simples.

  01 <dd-m>
  02   <dd-i>Criar</dd-i>
  03   <dd-i>Editar</dd-i>
  04   <dd-i>Excluir</dd-i>
  05 </dd-m>

Procure utilizar palavras que auxiliem na identificação do componente e seus elementos. No exemplo da Listagem 7, uma vez entendido o que são “dropdowns”, fica fácil perceber como os seus elementos internos se alinham e dependem uns dos outros.

Listagem 7. Componente com nome mais verboso, contudo mais significativo.

  01 <dropdown-menu>
  02   <dropdown-item>Criar</dropdown-item>
  03   <dropdown-item>Editar</dropdown-item>
  04   <dropdown-item>Excluir</dropdown-item>
  05 </dropdown-menu>

Indexação

Um especialista front-end é um conhecedor assíduo dos principais fatores on-page para otimização de sites para os mecanismos de busca.

Ele sabe que, acima de tudo, o conteúdo é o principal responsável por atrair as visitas e consequentemente pelo posicionamento de um site nas primeiras posições das SERPs (Search Engine Result Pages). O conteúdo precisa ser original, bem escrito, relevante e principalmente estar facilmente acessível aos usuários e buscadores.

Diante disso, muitos desenvolvedores têm se perguntado como os Web Components se comportarão mediante a indexação do conteúdo de suas páginas através dos mecanismos de busca.

Para criar novos componentes, manipular templates e encapsular seus elementos o desenvolvedor precisa utilizar JavaScript para manipular o DOM. E dúvidas como "O que aconteceria se um crawler como o Googlebot acessasse uma página recheada de Custom Elements e fortemente isolados com Shadow DOM?", surgem entre muitos desenvolvedores curiosos.

Como se sabe, a maioria dos web crawlers navega de uma forma bem limitada, sem renderização de estilos CSS e execução de scripts, baseando-se apenas na estrutura HTML para realizar uma navegação totalmente textual.

O Google está constantemente aprimorando o seu algoritmo para que seus robôs ganhem mais inteligência no processo de indexação de conteúdo web. Recentemente, no blog da empresa, os engenheiros de software Erik Hendriks e Michael Xu e o Webmaster Analista de Tendências Kazushi Nagayama publicaram um artigo reconhecendo que o cenário atual da web mudou bastante desde o início da empresa.

Os sites atuais são mais ricos, dinâmicos e utilizam bastante JavaScript. Diante disso, eles anunciaram que a ferramenta de busca já tem sido capaz de executar JavaScript com a finalidade de enxergarem as páginas como os navegadores modernos o fazem.

A informação é bem animadora, porém o artigo é um tanto vago a respeito de como o Googlebot realiza a execução do JavaScript. Os profissionais da empresa também deixam claro que em casos particulares a renderização da página pode não funcionar como o esperado podendo causar um impacto negativo no resultado da pesquisa.

Diante disso, os autores e especialistas compartilham através do artigo dicas para evitar armadilhas que possam afetar o seu site.

Dentre as dicas a que se destacou foi a ideia de construir páginas que degradem graciosamente, dessa forma o conteúdo estaria acessível à minúscula parcela de usuários que desabilitam o JavaScript de seus navegadores e para rastreadores que ainda não interpretam JavaScript.

Ainda é bem difícil determinar até que ponto a indexação de conteúdo poderá afetar o futuro dos Web Components. Na página de FAQ do projeto Polymer, a questão "Crawlers understand custom elements? How does SEO work? (Crawlers entendem Custom Elements? Como o SEO funciona?)" é respondida com bastante otimismo dizendo que "daqui para frente, é uma suposição razoável que, como o uso de espécies nativas do Shadow DOM aumentam, os fornecedores de motores de busca tentarão se adaptar e entendê-los, assim como eles se adaptaram a outras novas tecnologias web no passado."

Obviamente, o cenário atual não está propício para a utilização dos Web Components na criação de sites tradicionais que precisam ter o seu conteúdo facilmente indexável e disponibilizado para os resultados de pesquisa.

Projetos como o Polymer destacam que muitos desenvolvedores têm obtido sucesso ao utilizarem a biblioteca em suas aplicações que encontram-se em produção, mas que ainda é muito importante ter cautela. Devido a imaturidade da tecnologia, a mesma poderá sofrer muitas mudanças e a realização de um test drive é amplamente aconselhada.

No contexto atual da internet é muito difícil imaginarmos quais soluções estaríamos utilizando caso o JavaScript não existisse. A linguagem mudou completamente o panorama da internet e continua evoluindo muito nesses últimos dias. Graças ao JavaScript, as aplicações web se tornaram mais dinâmicas e com uma interface muito mais rica.

O percentual de usuários que navegam com ele desabilitado é muito baixo. É bem provável que tão logo a indexação de conteúdo gerado por JavaScript esteja sanada, mitigando os riscos de usarmos Web Components.

Performance

Performance é um fator importantíssimo para qualquer site ou aplicação web. Disponibilizar o conteúdo para o usuário final em tempo hábil é sempre um desafio. Inúmeras pesquisas e estudos de caso comprovam que cada segundo é precioso, podendo impactar em conversões, engajamentos, resultados de busca, e tantos outros pontos.

Diante disso, muitas tecnologias, técnicas e dicas foram compartilhadas entre a comunidade de desenvolvedores. Essas técnicas foram aperfeiçoadas ao decorrer do tempo, e outras novas têm surgido para melhorar a experiência do usuário.

O desenvolvedor front-end se mostrou bastante criativo e um verdadeiro solucionador de problemas, aprendendo a tratar melhor as imagens, diminuir o tamanho dos seus arquivos, configurar o cacheamento dos arquivos estáticos, diminuir os refluxos de renderização das páginas, diminuir a quantidade de requisições para o servidor e muito mais.

No que tange à performance dos recursos dos Web Components de importação de HTML e Shadow DOM, o que temos na verdade são verdadeiras incógnitas.

O que sabemos atualmente é que quando importamos documentos HTML geramos novas requisições ao servidor. Além das próprias requisições do documento importado, o mesmo pode conter outras importações e requisições de imagens, folhas de estilo ou arquivos de scripts caindo em um verdadeiro request hell.

No exemplo ilustrado na Listagem 8 é possível ver isso, onde Web Components são importados de várias fontes diferentes, gerando várias consequentes requisições.

Listagem 8. Importações de múltiplos arquivos HTML.

  01 <!DOCTYPE>
  02 <html lang="pt-br">
  03 <head>
  04   <link rel="import" href="componente-1.html">
  05   <link rel="import" href="componente-2.html">
  06   <link rel="import" href="componente-3.html">
  07   <link rel="import" href="componente-N.html">
  08 </head>
  09 <body>
  10 </body>
  11 </html>

Isso difere das soluções server side utilizadas para incorporar trechos de códigos HTML ao documento principal. Essas soluções inserem os partials/includes no arquivo que será entregue ao usuário final sem a necessidade de requisições extras.

Com a finalidade de diminuir o impacto na performance, o time responsável pelo Polymer desenvolveu uma ferramenta em NodeJS chamada Vulcanize. O Vulcanize concatena as referências dos arquivos a serem importados em um único arquivo evitando a necessidade de novas requisições.

Para instalá-lo basta executar o comando sudo npm install -g vulcanize no npm do Node.js e concatenar os arquivos usando vulcanize index.html.

O HTTP 2.0 é outra tecnologia que tem sido aguardada com muita expectativa pela comunidade web. A nova versão do protocolo HTTP recebeu inúmeras melhorias visando justamente o desempenho, especificamente para o usuário final, percebido pela latência da rede e uso de recursos do servidor.

Uma dessas melhorias é poder paralelizar as requisições com multiplexação, isso significa poder realizar várias requisições ao mesmo tempo e receber suas respectivas respostas conforme ficam prontas, de forma paralela e assíncrona.

Utilizando esse recurso, apenas uma conexão basta evitando a necessidade de criarmos outros hostnames para superar a limitação do número de conexões por hostname dos navegadores.

Mas apesar de ainda não estar disponível, o HTTP 2.0 teve uma influência forte de outra tecnologia já disponível no mercado, o protocolo SPYD (pronuncia-se “SPeeDY”, ou “mais rápido”), implementado pelo Google e já suportado pelos navegadores mais modernos. Além do problema das requisições causadas pelas importações que podem ser contornadas concatenando os arquivos HTML com o Vulcanize, e que provavelmente será solucionada em breve com a utilização do HTTP 2.0, temos um outro dificultador: o isolamento do Shadow DOM.

O isolamento do Shadow DOM é realmente ótimo para evitar que estilos indesejados alterem as características de seus componentes, mas pode se tornar um verdadeiro incômodo quando queremos reaproveitar estilos comuns para nossos componentes nos levando à utilização de estilos incorporados.

A utilização de regras CSS incorporadas diretamente na página é algo considerado ruim tanto para performance quanto para modularização, e vem sendo evitada a bastante tempo por desenvolvedores que têm apreço por desempenho e reutilização de código. Estilos declarados fora do escopo do Shadow DOM não conseguem acessar os elementos devido ao seu isolamento.

A solução é declarar regras de estilo direto no escopo do elemento isolado, ou seja, tag <style> </style> direto no elemento. Veja um exemplo dessa injeção direta de JavaScript no exemplo da Listagem 9.

Listagem 9. Exemplo de utilização de estilos incorporados na declaração do Shadow DOM.

  01 <div class=”elemento”></div>
  02 <script>
  03    var root = document.querySelector('.elemento').createShadowRoot();
  04    root.innerHTML = '<style>h3{ color: red; }</style>' + '<h3>Shadow DOM</h3>';
  05 </script>

Novos seletores têm aparecido e nos permitirão estilizar o conteúdo isolado no Shadow DOM sem que tenhamos que declarar estilos incorporados toda vez que precisarmos estilizar nossos elementos. Os pseudo-elementos ::shadow (Listagem 10) e o /deep/combinator nos permitem penetrar a barreira do Shadow DOM para que possamos acessar os elementos dentro da Shadow Tree.

Listagem 10. Exemplo de utilização do seletor ::shadow.

  01 <!DOCTYPE html>
  02 <html lang="en">
  03 <head>
  04   <meta charset="UTF-8">
  05   <title>Shadow DOM</title>
  06   <style>
  07     #host::shadow p {
  08       color: red;
  09       font-weight: bold;
  10     }
  11   </style>
  12 </head>
  13 <body>
  14    <div id="host">
  15       <p>Conteúdo no DOM</p>
  16    </div>
  17 
  18    <script>
  19     var host = document.querySelector('#host');
  20     var root = host.createShadowRoot();
  21     root.innerHTML = "<content></content>" + "<p>Conteúdo no Shadow DOM</p>";
  22    </script>
  23 </body>
  24 </html>

No exemplo, é possível ver que incutimos CSS específico (linhas 7 à 10) somente para o elemento de parágrafo criado dentro da função JavaScript da linha 21. Para recuperar a raiz da Shadow DOM basta usarmos a função createShadowRoot() da própria API HTML5.

Os seletores ::shadow e /deep/ são semelhantes, sendo que o segundo é bem mais poderoso. Ele ignora completamente as barreiras do Shadow DOM e permite acessar determinado elemento em qualquer nível da árvore que o mesmo se encontre.

Podemos utilizar o /deep/ para customizarmos o player da tag nativa <video>, por exemplo, como mostrado na Listagem 11. Veja como a forma de declarar esse tipo de estilo difere um pouco do que estamos acostumados a usar em CSS, parecendo mais com uma espécie de comentário.

Listagem 11. Utilização do seletor /deep/ para aplicar estilos na tag nativa video.

  01 <style>
  02     video /deep/ input[type="range"] {
  03       background: #ff0;
  04     }
  05     video /deep/ div {
  06       color: #00ff00;
  07     }
  08 </style>
  09 <video src="http://techslides.com/demos/sample-videos/small.ogv" controls>
  10     Texto de fallback...
  11 </video>

Criando seus próprios Web Components

Vamos mudar um pouco as coisas dentro do elemento <template> e ver o que acontece. Vejamos o exemplo definido na Listagem 12.

Listagem 12. Exemplo de criação de biblioteca própria.

  01 <!-- Carrega a biblioteca do Google Polymer -->
  02 <link rel="import" href="../packages/sample/polymer/polymer.html">
  03 
  04 <!-- Define um novo web component. -->
  05 <polymer-element name="meu-componente" noscript>
  06   <template>
  07     Web components
  08     <em><content></content>!</em>
  09   </template>
  10 </polymer-element>
  11 
  12 <!-- Usa o novo web component. -->
  13 <meu-componente>rocha</meu-componente>
  14 <meu-componente>são fáceis de usar</meu-componente>
  15 <meu-componente>me dê superpoderes web</meu-componente>

Enquanto o uso de componentes web apenas requer conhecimentos básicos de HTML, criação de componentes complexos requer o conhecimento de JavaScript, e está fora do escopo deste artigo.

Se você é um programador JavaScript, dê uma olhada na documentação do projeto do Google Polymer para obter mais informações sobre como criar seus próprios componentes via JavaScript.

Se você não escreve muito JavaScript mesmo, há ainda uma gama de possibilidades interessantes para a criação de componentes básicos da web. A biblioteca Polymer permite que você crie componentes web simples somente com HTML. A demonstração que fizemos na última listagem usa o Polymer para criar um novo componente sem JavaScript:

  • O exemplo define um novo componente chamado <meu-componente>.
  • O componente inclui um elemento <template>. Qualquer coisa dentro do template vai se repetido cada vez que alguém usa o seu componente.
  • O template inclui o texto de ações "Web components".
  • O modelo também inclui um elemento <content>. Este é mais um novo elemento HTML que funciona como um espaço reservado no template de um componente web. Quando alguém usa o seu componente, se colocar um texto ou outra coisa entre as tag <meu-componente> de abertura e a tag </ meu-componente> de fechamento, esse texto irá aparecer onde o espaço reservado para <content> aparece.

Este tipo de componente web é efetivamente uma “macro” HTML: um pedaço de HTML que você pode usar várias vezes sem constantemente ter que copiar e colar coisas. Há muito mais o que você pode fazer com um componente desse tipo, mas o ponto principal é que você pode criar componentes web simples, mesmo se você não sabe o JavaScript.

Apesar das preocupações que os Web Components podem gerar acerca do desempenho, vimos que inúmeras soluções têm surgido e que muito em breve evitarão os impactos negativos na performance de nossas aplicações web.

Em um mundo extremamente dinâmico como o da web é difícil falarmos sobre o futuro de uma determinada tecnologia. Muitas tecnologias desapareceram antes mesmo de se tornarem conhecidas, outras levaram bastante tempo para serem adotadas.

Os Web Components ainda são uma tecnologia muito nova, mesmo assim são apontados como sucesso certo em um futuro próximo. Os receios citados em torno da tecnologia estão todos voltados para o momento da web que estamos vivenciando e certamente serão solucionados a partir do instante em que a adesão dos Web Components finalmente ocorrer.

Já em relação ao impeditivo do suporte dos navegadores, talvez deva ser considerado o principal e único receio quando pensamos em adotar os Web Components em nossos projetos. Felizmente, os principais browsers têm dado início à implementação dos Web Components.

Os browsers baseados no motor de renderização Blink, Google Chrome e Opera, têm liderado essa corrida. Eles são os únicos até o momento que implementaram o conjunto de recursos: Templates, Shadow DOM, Custom Elements e HTML Imports de forma estável.

O Firefox, mesmo sendo mais vagaroso, tem feito grandes progressos e implementado várias partes do conjunto de recursos. A Mozilla mantém uma lista de bugs em seu repositório oficial, nos quais tem trabalhado para corrigir.

Através da lista podemos acompanhar o progresso e votar nos bugs que consideramos mais importantes para correção. É uma ótima forma de contribuir com a evolução da Mozilla.

A Microsoft também tem feito planos para implementação dos componentes web no Internet Explorer. Através do endereço disponível na seção Links é possível acompanhar o status das funcionalidades cogitadas para fazerem parte do navegador.

Os quatro principais recursos ainda estão sob consideração. A versão atual do navegador não possui nenhuma das APIs para Web Components e é muito provável que tais implementações sejam disponibilizadas apenas na próxima versão do navegador que também contará com uma série de melhorias.

O Safari ainda permanece uma grande incógnita. Embora a recente versão do navegador já suporte o recurso de template, a funcionalidade de Shadow DOM foi recentemente removida do Webkit levantando dúvidas sobre o que de fato será implementado no navegador e quando.

Ao contrário do que possa parecer, o futuro dos Web Components depende antes de tudo da comunidade de desenvolvedores. Somos nós os principais responsáveis por utilizar e consequentemente manter viva qualquer tecnologia. É bem verdade que os Web Components e as tecnologias adjacentes ainda hão de amadurecer bastante, mas isso não impede que deixemos nossos receios de lado e possamos confiar mais uma vez na HTML5.

Agora cabe a você se inteirar melhor do assunto, fazendo mais testes e acrescentando funcionalidades aos exemplos desenvolvidos neste artigo. Tente baixar um dos polyfills da seção Links, e criar seus próprios Web Components de forma a entender como eles funcionam na prática e como serão abordados quando começarem a ser usados.

Leia as documentações, as notas de atualização, e os blogs dos mesmos sites. Ademais, as principais dúvidas dos desenvolvedores podem sempre ser solucionadas/acompanhadas pelos fóruns oficiais de cada projeto e isso te ajudará quando estiver emperrado com alguma implementação específica. Bons estudos!

Saiu na DevMedia!

  • Onde colocar minhas regras de negócio?:
    Você já imaginou como seria dar manutenção em uma aplicação MVC onde a camada de controle também fosse responsável pelas validações? E se a camada de visão também tivesse regras de negócio? Assista esse DevCast e fique por dentro.
  • O que é MVC?:
    Neste curso vamos entender o que é o padrão MVC (Model-VIew-Controller), qual sua proposta e aplicabilidade no desenvolvimento de aplicações.
  • Como implementar o MVC em PHP:
    O padrão MVC é amplamente utilizado no desenvolvimento de aplicações web, e saber implementá-lo é importante para trabalhar de forma eficiente com frameworks como CodeIgniter e Laravel, bem como para desenvolver projetos sem depender dessas soluções de terceiros.

Saiba mais sobre Front-end ;)

  • Guias para Front-end e JavaScript:
    Encontre aqui todos os Guias de estudo que você precisa para dominar as principais tecnologias Front-end. Falaremos sobre JavaScript, CSS e HTML. Escolha!
  • Progressive Web Apps:
    Os Progressive Web Apps são um conjunto de técnicas para desenvolver aplicações web, adicionando "progressivamente" funcionalidades que antes só eram possíveis em apps nativos.

Referências: