Este é mais um artigo sobre Web Components, focando primeiramente no impacto do desempenho do imports do HTML.
Escopo
O primeiro artigo, Anúncios Assíncronos com imports do HTML, propõe a utilização dessa nova tecnologia como uma forma de evitar o comportamento de bloqueio de anúncios síncronos. É melhor do que usar iframe, porque a tag LINK do import no HTML pode ser colocada no HEAD de modo que os anúncios apareçam de forma mais rápida, resultando em maior receita publicitária.
Uma desvantagem é que muitos anúncios usam document.write, e isso apaga toda a página quando dentro de um import HTML. Isso é surpreendente para pessoas que sabem que document.write funciona bem dentro de um iframe. Por que ele não deve funcionar tão bem dentro de um import do HTML? Afinal de contas, os imports HTML são documentos separados da mesma forma que iframes. A primeira linha da especificação confirma isso:
HTML Imports, or just imports from here on, are HTML documents…
E a interface mostra claramente que um documento é criado para conter o conteúdo:
interface Import { readonly attribute DOMString? href; readonly attribute Node ownerNode; readonly attribute Document content; };
Esse problema ocorre porque quando o JavaScript no import do HTML faz referência à variável “document“, ele não se refere ao document do import do HTML. Em vez disso, ele se refere ao document da página principal. Em outras palavras, JavaScript do import do HTML é executado no âmbito do documento da página principal, não no escopo do seu próprio documento.
Jonas Sicking (Mozilla) começou uma thread com o tema what scope to run in em que discute essa questão. A solução sugerida é recomendar que os imports do HTML usem a tag MODULE em vez da tag SCRIPT. Há mais discussão sobre carregadores de módulos e a colisão de namespaces de módulos. Para mim, o maior problema é que, apesar dessa recomendação, os imports do HTML ainda terão a tag SCRIPT, e que o JavaScript será executado em um contexto que é provavelmente contraintuitivo para os desenvolvedores.
Seria melhor se o JavaScript dentro de um import do HTML fosse executado no contexto do documento do import do HTML. O JavaScript do import do HTML ainda pode chegar ao namespace da janela pai, por exemplo, window.parent.document. Apesar disso, seria bom se o dono do site pudesse controlar esse acesso, o que nos levaria a uma maior segurança.
Segurança
Acredito que Web Components vão se tornar populares como uma forma de reutilizar os widgets de terceiros, mas isso introduz um risco de segurança em que terceiros podem ler a informação que é confidencial para o site e seus usuários, tais como cookies.
Notei que a especificação diz que imports do HTML devem ser CORS-enabled. No começo, achei que isso era para resolver a questão de os imports do HTML de terceiros acessarem informações privilegiadas na página principal. Mas, aprofundando a leitura, percebi que é o contrário: o objetivo é fornecer uma forma para que os imports do HTML permitam que a página principal acesse o conteúdo dentro do documento importado.
Eu criei algumas páginas de teste para confirmar esse comportamento. O import do HTML no exemplo de elemento personalizado é CORS-enabled ao adicionar este cabeçalho de resposta ao import do HTML:
Access-Control-Allow-Origin: *
O elemento personalizado na página de teste CORS tem o cabeçalho removido e, portanto, o import do HTML falha. Apesar de isso proteger corretamente o conteúdo de terceiros de ser exposto para o site principal, é importante para a adoção dos imports do HTML que eles forneçam um meio de segurança na outra direção. Iframes resolvem essa questão com o atributo sandbox do HTML5. Eu gostaria de ver algo semelhante adicionado aos imports do HTML.
Sugestões
Encontrei recentemente questões sobre o JavaScript que eu encontrei em relação ao Web Components. Eu gostaria de resumir, fornecendo uma lista das minhas sugestões para o Web Components:
- Adicione um atributo “lazyload” ao <link rel=”import” …>. Isso permite a renderização mais rápida da página. Isso talvez seja tratado pela especificação Resource Priorities, mas o comportamento desejado deve ser aplicado sempre que os imports do HTML não bloquearem a renderização quando uma tag SCRIPT é encontrada.
- Adicione um atributo “elements” ao <link rel=”import” …>. Isso fornece uma maneira de evitar FOUC para elementos personalizados, enquanto permite que elementos DOM anteriores sejam renderizados. Daniel Buchner e eu propusemos isso na lista de discussão public-webapps do W3C.
- Torne <link rel=”import” …> válido dentro do BODY. Agora eles são válidos apenas dentro do HEAD. É melhor que a tag LINK do import do HTML seja colocada no BODY no lugar onde o conteúdo será importado porque: elimina a possibilidade de a tag SCRIPT bloquear a renderização da página inteira ao mesmo tempo em que proporciona uma maneira de fazer com que certos tipos de importações HTML sejam síncronas (bloquear a renderização até que a importação esteja pronta) evitando assim FOUC; torna mais fácil para novos desenvolvedores entenderem a semântica da construção da página, com todas as partes do Web Component localizadas próximas umas das outras.
- Faça com que o JavaScript dentro de um import do HTML execute no contexto do documento importado. Isso é provavelmente mais intuitivo para os desenvolvedores e propicia uma portabilidade maior para JavaScript existente migrado para um import do HTML.
- Acrescentar um atributo “sandbox” para <link rel=”import” …>. Isso permite que proprietários de sites incluam o conteúdo de terceiros e evita que fontes desconhecidas acessem informações confidenciais na página (tal como cookies).
Conteúdo de terceiros é um problema de desempenho que fica pior a cada ano. Estou animado com o potencial dos Web Components na medida em que a especificação e as implementações crescem para atender às necessidades dos desenvolvedores web e proprietários de sites.
***
Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://www.stevesouders.com/blog/2013/12/02/html-imports-scope-security-and-suggestions/