vNakamura

Vinicius Nakamura - Compartilho aqui descobertas e experimentos como Full Stack e Game Developer.

Meteor com Polymer

Agora que tanto o Meteor quanto o Polymer estão em versão >1.0, podemos começar a utilizá-los em ambiente de produção.

Depois de quase meio ano desde meu post introdutório ao Meteor, já estou bem mais familiarizado com o framework e sinto que posso me aventurar em desafios mais complexos.

Neste post, considero que você já tenha uma experiência básica com as duas ferramentas. Caso precise de dicas para começar, recomendo meu post anterior de Meteor, atualizei recentemente alguns links de tutoriais. Para Polymer, um bom começo é assistir os vídeos do Polycasts, feitos pelo pessoal do próprio Google.

Apesar da documentação do Polymer ser bem amigável, descobrir como dar os primeiros passos foi uma tarefa um tanto complicada. Levei algum tempo para conseguir resolver alguns conflitos que surgiram entre os dois sistemas. Listo abaixo como consegui.

Instalando o Polymer via Bower

Existem alguns pacotes no Atmosphere para implementar o polymer no Meteor, mas nos testes que fiz eles eram problemáticos e me fizeram perder um bom tempo até decidir importar diretamente com o Bower.

Se esta é uma ferramenta nova para você, o Tableless tem um bom artigo de introdução ao bower.

Um detalhe importante

Para ter acesso no navegador aos componentes e evitar que os arquivos interfiram na estrutura do meteor, vamos configurar o bower para guardar os arquivos dentro da pasta /public.
Crie um arquivo .bowerrc na raiz do projeto com o seguinte:

{
  "directory": "public/bower_components"
}

Adicionando os pacotes

Depois de configurado, podemos começar a incluir os componentes ao nosso projeto.
Para fazer isto, você pode usar o pacote mquandalle:bower e criar um arquivo bower.json contendo:

{
  "name": "meuAplicativo",
  "version": "0.0.0",
  "dependencies": {
    "polymer": "~1.0.5",
    "paper-elements": "PolymerElements/paper-elements#~1.0.1"
  }
}

Além do pacote básico do Polymer, estamos incluindo os elementos de Material Design. Se você precisa de mais algum componente do Catálogo de Elementos do Polymer, é só adicionar à lista.

Se você já utiliza o bower e tem a CLI (Command-line Interface) instalada globalmente, tudo o que você precisa é executar os comandos: bower init e bower install --save polymer PolymerElements/paper-elements.

Vulcanize

O Polymer baseia-se em html imports para carregar seus elementos. Isso pode gerar uma quantidade exagerada de requests ao servidor, deixando o carregamento da página mais lento.
Para contornar este problema existe a vulcanize, uma ferramenta do Polymer que incorpora todos os imports a um documento único.

Normalmente ela é executada via CLI ou com Gulp/Grunt, mas existe o pacote differential:vulcanize para automatizar o uso da vulcanize dentro do Meteor.
Adicione-o ao projeto e crie um arquivo config.vulcanize na raiz. Este arquivo é um json onde você listará todos os componentes que você vai utilizar:

{
  "polyfill": "/bower_components/webcomponentsjs/webcomponents.min.js",
  "useShadowDom": true,
  "imports": [
    "bower_components/font-roboto/roboto.html",
    "bower_components/paper-input/paper-input.html",
    "bower_components/paper-button/paper-button.html",
    "bower_components/paper-checkbox/paper-checkbox.html"
  ]
}

Todos os componentes serão importados automaticamente no HTML principal.
Em ambiente de desenvolvimento, não precisamos que a vulcanize seja executado sempre que o projeto é atualizado. Por isso, como padrão este pacote apenas faz o import individual dos componentes. Para que a vulcanize seja executada e otimize estes imports, você precisa definir a variável VULCANIZE=true antes do comando do Meteor: VULCANIZE=true meteor deploy, VULCANIZE=true meteor build etc. Isto só é necessário quando você for publicar o projeto em ambiente de produção.

Você deve ter notado que além dos imports, o arquivo tem as chaves polyfill e useShadowDom. Elas são importantes para o funcionamento do Polymer em navegadores que não dão suporte nativo a webcomponents.

Resolvendo conflitos

Depois de instalado o Polymer, precisamos fazer algumas pequenas alterações para que integração funcione corretamente. Postarei os scripts necessários e em seguida explico porque são necessários e o que eles fazem.

Os códigos estão em CoffeeScript. Se você não utiliza, instale o pacote coffeescript ou converta para js no site oficial.
Fique a vontade para mudar a nomenclatura dos arquivos ou até uni-los em um único arquivo, precisamos apenas garantir que cada parte execute no lugar correto utilizando Meteor.isClient() e Meteor.isServer().

/client/main.coffee:

polymerReady = new ReactiveVar false

$(window).on "WebComponentsReady", ->
  polymerReady.set true

Meteor.startup ->  
  $("body").append "<div fit layout vertical iron-router></div>"
  Tracker.autorun ->
    if polymerReady.get()
      Router.insert el: "[iron-router]"
      Router.start()

Antes que o aplicativo comece a rodar, precisamos ter certeza que os componentes estão carregados. Para isso utilizamos o pacote reactive-var para iniciar o Iron Router quando estiver tudo OK.
Normalmente, o Router adiciona os template direto no body, mas como o Polymer também o manipula, criamos uma div e instruímos o Router a executar dentro dela, resolvendo os conflitos.

/server/main.coffee:

Meteor.startup ->  
  Inject.rawModHtml 'addUnresolved', (html) ->
    html = html.replace '<body>', '<body unresolved class="fullbleed layout vertical">'

Este script utiliza o pacote meteorhacks:inject-initial para incluir as propriedades ao body que são necessárias ao Polymer. O unresolved faz com que o body fique invisível enquanto os componentes não estão implementados, evitando flicks que podem acontecer quando a página é carregada.
As classes adicionadas só são necessárias se você for usar os componentes de layout do Polymer e estão aqui como exemplo, remova se não for precisar.

Concluindo

Realizando estas etapas, . Foi um pouco complicado mas é recompensador pelas facilidades que as duas ferramentas proporcionam.

Não esqueça de utilizar o VULCANIZE=true quando for publicar o projeto e fique à vontade para me contatar caso tenha dúvidas ou sugestões. Eu não instalei um sistema de comentários porque meu blog ainda não tem tanto público, mas você pode utilizar o formulário ou me mandar um tweet @vNaka