O artigo focará na montagem de projetos BEM usando o empacotador Webpack. Vou mostrar um exemplo de configuração sem carregar leitores com entidades desnecessárias.
O material é adequado para quem está começando a se familiarizar com o BEM. Primeiro, abordaremos os aspectos teóricos da metodologia e, na seção "Prática", mostrarei como eles podem ser aplicados.
Pouco de teoria
Se é a primeira vez que você ouve sobre o BEM e deseja conhecê-lo, guarde a documentação .
O BEM é uma metodologia usada para organizar projetos de qualquer escala. A Yandex a desenvolveu e a princípio a utilizou apenas no trabalho de seus serviços, mas depois foi publicada em domínio público.
BEM significa "Bloco, Elemento, Modificador".
Block é uma entidade com uma arquitetura autônoma que pode ser reutilizada. Um bloco pode conter seus próprios elementos.
Um elemento é parte integrante de um bloco. Um item só pode ser usado dentro do bloco pai.
Um modificador é uma entidade que altera a exibição, estado ou comportamento de um bloco.
Esses componentes estão subjacentes à metodologia. Eles oferecem beleza e separação de código conveniente. Mais detalhes sobre o dispositivo estão escritos na documentação .
A documentação do BEM é extensivamente escrita. No entanto, existe um "mas": um limite alto para a entrada do material. Se o básico do layout puder ser descoberto lendo uma página da documentação, a questão da montagem do projeto é mais complicada.
Por que foi a montagem do projeto? Ao trabalhar em um projeto de larga escala, todos enfrentam o problema de organizar o código. É inconveniente armazenar todo o código de um projeto grande em um arquivo. Dividir o código em vários arquivos e compilá-lo manualmente também não é uma boa saída. Para resolver esse problema, são usados coletores ou empacotadores que automatizam a conversão do código-fonte do projeto em código que está pronto para ser enviado à produção.
Deixe-me lembrá-lo: supõe-se ainda que os leitores tenham habilidades básicas no Webpack. Se você não trabalhou com ele antes, recomendo que você se familiarize com essa ferramenta.
A documentação do BEM fornece recomendações para a montagem de projetos. Apenas duas opções são oferecidas como exemplos: montagem usando ENB e Gulp.
ENB é um utilitário projetado especificamente para a construção de projetos BEM. Ela é capaz de trabalhar com entidades do BEM imediatamente. Mas dê uma olhada no código. À primeira vista, ele pode desmotivar um desenvolvedor despreparado:
make.jsconst techs = {
Código do repositório público project-stub .
O código de configuração da ENB obviamente será complicado para quem está começando a usar o BEM.
A documentação contém configurações prontas para o coletor e podem ser usadas sem se aprofundar nos detalhes da montagem. Mas e se você, como eu, gostaria de ter uma imagem completa do que está acontecendo com o projeto durante a construção?
A documentação do BEM explica bem o processo de montagem na teoria; no entanto, existem poucos exemplos práticos e nem sempre são adequados para uma compreensão clara do processo. Para resolver esse problema, tentarei criar um projeto BEM elementar usando o Webpack.
Prática
Antes disso, mencionei que a separação de código e a organização da montagem simplificaram o trabalho com o projeto. No exemplo abaixo, forneceremos a separação de código usando o BEM e seu assembly usando o Webpack.
Queremos obter a configuração mais simples, a lógica de montagem deve ser linear e intuitiva. Vamos montar uma página com um bloco BEM, que terá duas tecnologias: CSS e JS.
Você pode escrever código HTML com um DIV com a classe "block" e conectar manualmente todas as suas tecnologias. Usando a nomeação de classe BEM e a estrutura de arquivo correspondente, não violamos os princípios da metodologia.
Eu recebi a seguinte árvore de projeto:
├── desktop
A primeira linha refere-se ao nível de substituição de "área de trabalho". Na terminologia BEM, os níveis de redefinição são diretórios que contêm suas próprias implementações de bloco. Ao montar um projeto, implementações de todos os níveis de redefinição em uma determinada ordem caem no pacote final.
Por exemplo, temos um nível de redefinição de "área de trabalho" no qual as implementações de bloco para dispositivos de área de trabalho são armazenadas. Se precisarmos complementar o projeto com o layout para dispositivos móveis, será suficiente criar um novo nível de redefinição de "móvel" e preenchê-lo com novas implementações dos mesmos blocos. A conveniência dessa abordagem é que, em um novo nível de redefinição, não precisaremos duplicar o código que já existe no "desktop", pois ele se conectará automaticamente.
Aqui está a configuração do Webpack:
Aqui, especificamos o arquivo /pages/index.js
como um ponto de entrada, adicionamos carregadores para estilos CSS e /pages/index.html
para /dist/index.html
.
index.html <html> <body> <div class="block">Hello, World!</div> <script src="index.js"></script> </body> </html>
block.css .block { color: red; font-size: 24px; text-align: center; }
block.js document.getElementsByClassName('block')[0].innerHTML += " [This text is added by block.js!]"
O exemplo usa um nível de substituição e um bloco. A tarefa é montar a página para que as tecnologias (css, js) do nosso bloco estejam conectadas a ela.
Para conectar tecnologias, usamos o require()
:
Inicie o Webpack e veja o que acontece. Abra index.html
na pasta ./dist
:
Captura de tela da página Os estilos de bloco foram carregados, o javascript funcionou com sucesso. Agora podemos adicionar, com razão, as preciosas letras "BEM" ao nosso projeto.
Primeiro, o BEM foi criado para trabalhar com grandes projetos. Vamos imaginar que nosso designer tentou e na página agora não é um bloco, mas cem. Seguindo o cenário anterior, conectaremos manualmente as tecnologias de cada bloco usando require()
. Ou seja, pelo menos cem linhas de código adicionais aparecerão no index.js.
Linhas extras de código que poderiam ter sido evitadas são ruins. Código não utilizado é ainda pior. E se, em nossa página, houver apenas 10 dos blocos disponíveis, ou 20 ou 53? O desenvolvedor terá mais trabalho: ele terá que se concentrar exatamente em quais blocos são usados na página, além de conectá-los e desconectá-los manualmente para evitar código desnecessário no pacote final.
Felizmente, este trabalho pode ser confiado ao Webpack.
O algoritmo ideal de ações para automatizar esse processo:
- Selecione as classes correspondentes à nomeação do BEM a partir do código HTML existente;
- Com base nas classes, obtenha a lista de entidades do BEM usadas na página;
- Verifique se existem diretórios de blocos, elementos e modificadores usados nos níveis de redefinição;
- Conecte a tecnologia dessas entidades ao projeto adicionando as expressões
require()
apropriadas.
Para começar, decidi verificar se há algum carregador de inicialização pronto para esta tarefa. Não encontrei um módulo que fornecesse toda a funcionalidade necessária em um frasco. Mas me deparei com bemdecl-to-fs-loader , que converte declarações BEM em expressões require()
. Ele se baseia nos níveis de redefinição e nas tecnologias disponíveis na estrutura do arquivo do projeto.
Declaração BEM - uma lista de entidades BEM usadas na página. Leia mais sobre eles na documentação .
Um link está ausente - a conversão de HTML para uma matriz de entidades BEM. Esta tarefa é resolvida pelo módulo html2bemjson .
bemjson - dados que refletem a estrutura da página futura. Geralmente eles são usados pelo mecanismo de modelo bem-xjst para formar páginas. A sintaxe do bemjson é semelhante à sintaxe das declarações, mas a declaração contém apenas uma lista de entidades usadas, enquanto o bemjson também reflete sua ordem.
o bemjson não é uma declaração; portanto, primeiro a convertemos para o formato decl para transmissão no bemdecl-to-fs-loader. Para esta tarefa, use o módulo do SDK: bemjson-to-decl . Como esses são módulos regulares do NodeJS, não carregadores Webpack, é necessário criar um carregador de wrapper. Depois disso, podemos usá-los para converter em Webpack.
Nós obtemos o seguinte código do carregador de inicialização:
let html2bemjson = require("html2bemjson"); let bemjson2decl = require("bemjson-to-decl"); module.exports = function( content ){ if (content == null && content == "") callback("html2bemdecl requires a valid HTML."); let callback = this.async(); let bemjson = html2bemjson.convert( content ); let decl = bemjson2decl.convert( bemjson ); console.log(decl);
Para simplificar a instalação do gerenciador de inicialização e economizar tempo no futuro, baixei o módulo no NPM .
Vamos instalar o carregador de inicialização em nosso projeto e fazer alterações na configuração do Webpack:
const webpack = require('webpack'); const path = require('path'); const opy = require('copy-webpack-plugin'); module.exports = { entry: path.resolve(__dirname, "pages", "index.js"), output: { filename: 'index.js', path: path.join(__dirname, 'dist') }, module: { rules: [ { test: /\.html$/, use: [ {
O parâmetro de levels
bemdecl-to-fs-loader
inicialização do bemdecl-to-fs-loader
especifica quais níveis de substituição usar e em que ordem. As extensions
fornecem as extensões de tecnologia de arquivo usadas em nosso projeto.
Como resultado, em vez de conectar tecnologias manualmente, incluímos apenas um arquivo HTML. Todas as conversões necessárias serão realizadas automaticamente.
Vamos substituir o conteúdo de index.js pela linha:
require('./index.html');
Agora execute o Webpack. Ao montar, a linha é exibida:
[ BemEntityName { block: 'block' } ]
Isto significa que a formação da declaração foi bem sucedida. Observamos diretamente a saída do Webpack:
Entrypoint main = index.js [0] ./pages/index.js 24 bytes {0} [built] [1] ./pages/index.html 74 bytes {0} [built] [2] ./desktop/block/block.css 1.07 KiB {0} [built] [3] ./node_modules/css-loader/dist/cjs.js!./desktop/block/block.css 217 bytes {0} [built] [7] ./desktop/block/block.js 93 bytes {0} [built] + 3 hidden modules
Captura de tela da página Obtivemos um resultado idêntico ao anterior, com a diferença de que todas as tecnologias de bloco foram conectadas automaticamente. Por enquanto, basta adicionar uma classe nomeada BEM ao HTML, conectar esse HTML com require()
e criar o diretório apropriado com as tecnologias para conexão.
Portanto, temos uma estrutura de arquivos que corresponde à metodologia BEM, bem como um mecanismo para conectar automaticamente tecnologias de bloco.
Abstraindo dos mecanismos e entidades da metodologia, criamos uma configuração Webpack extremamente simples, porém eficaz. Espero que este exemplo ajude todos que começarem a conhecer o BEM a entender melhor os princípios básicos da criação de projetos.
Links úteis