Executando verificação de segurança...
2

[PITCH] el.js - sua nova biblioteca de elementos

O problema...

Até alguns dias atrás, eu escrevia HTML literals para adicionar elementos no meu HTML a partir de dados que vinha da API. Eu nunca fui de usar react, no máximo um lit-html, para criar componentes. Sempre fui mais do vanilla javascript. Todas as soluções que usava tinham que compatíveis com o mínimo de tranqueira possível.

Era o caso de sempre ter que fazer:

const text = "Paris é a capital da França.";
const foo = /*html*/`
<div class="card">
    <div class="card-header">Paris</div>
    <div class="card-body">
        ${escapeHTML(text)}
    </div>
</div>`;

document.body.append(foo);

E caia sempre no mesmo problema: era uma gambiarra horrível. Essa prática me deixava sujeito à:

  • legibilidade: tornava o código ruim, ilegível, dependia de extensões para fazer highlight do que tava naquele template literal.
  • performance: a estrutura daquele código era uma string. Quando fazia o Node.append(string), aquilo era convertido/interpretado para HTML e então criava um HTMLElement para adicionar naquele Node. Se eu fosse fazer isso em um loop, o consumo de processamento era bem alto.
  • interpolação e segurança: se eu precisasse criar um conteúdo, precisaria ter certeza que aquele conteúdo não ia quebrar todo o HTML naquele template literal. Para isso, tinha que recorrer à criar métodos que "sanitizavam" a entrada para não enfiar um ataque XCSS ali naquele template literal.

Todas essas camadas de complexidade e vulnerabilidade eram expostas ao usar template literals. Se eu quisesse fazer "do jeito certo", teria que usar document.createElement, e o código acima seria o equivalente à:

const card = document.createElement('div');
card.className = 'card';

const cardHeader = document.createElement('div');
cardHeader.className = 'card-header';
cardHeader.textContent = 'Paris'; 

const cardBody = document.createElement('div');
cardBody.className = 'card-body';
cardBody.innerText = text;

card.appendChild(cardHeader);
card.appendChild(cardBody);

return card;

E sinceramente, não gosto muito de OOP. Achei essa solução horrível para quando tinha que criar um componente com mais uns 10 componentes aninhados. Todos com classes, atributos, event-handlers...

E foi aí que fiz a

A solução!

Eu criei uma função, chamada el(). O que ela faz? Sabe todo o código do problema acima? Eu consigo reescrever com:

const foo = 
    el(".card",
        el(".card-header", "Paris"),
        el(".card-body", text));
    
document.body.appendChild(foo); // foo é um HTMLElement!

E está aí a mágica dessa super biblioteca. É um wrapper funcional para o document.createElement.

Ela automaticamente entende que cada argumento da função el após o primeiro é um "encaixe" para o elemento que está sendo criado. Posso usar apenas com o emmet embutido:

const countries = ['Brazil', 'Russia', 'India'];

el("select#country",
    ...countries.map(c => el("option", c)));
    
/*
<select id="country">
    <option>Brazil</option>
    <option>Russia</option>
    <option>India</option>
</select>
*/

Ou criar componentes:

el.defineComponent('card', attr => 
    el("div.card",
        el("div.card-header", attr.title),
        el("div.card-body", ...attr.slot)));

E usar como:

el("card", { title: "Paris" }, "Paris é a capital da França!");

/*
<div class="card" title="Paris">
    <div class="card-header">Paris</div>
    <div class="card-body">Paris é a capital da França!</div>
</div>
*/

E então?

Então, eu pude usar o el() para resolver os três problemas mencionados anteriormente, com apenas 4.1 KB!. A legibilidade não fica ruim, e na documentação até deixei um exemplo de como fazer elementos stateful/reactive.

Seu uso foi feito para ser usado em qualquer lugar que tenha um document.createElement.

Estou mostrando para vocês essa engenhoca. Fiquem a vontade para comentarem o que pensam disso.

Carregando publicação patrocinada...
1

Legal pra caramba man, biblioteca levinha que pra quem trabalha com JavaScript vanilla, é muito mão na roda, desonera bastante tempo de desenvolvimento escrever assim. Parabéns!