no-framework
Neste post faremos um exercício e uma proposta de arquitetura sem frameworks ou libs na stack javascript para montar uma aplicação front-end, chamaremos de no-framework.
O código-fonte utilizado pode ser visualizado e baixado no repositório do Github na url: https://github.com/joaoneto/no-framework
Com a ajuda de algumas ferramentas (tooling), que iremos montar uma página simples no modelo single page application (SPA).
Cuidados
Ao abrirmos mão de algumas implementações, estamos assumindo o
controle e abandonando uma base de código muito bem validada e mantida com constantes evoluções pelas comunidades no github.
Por que?
Quando iniciamos um projeto, escolhemos ferramentas que abstraem a parte mais complicada, para focar no que realmente importa, que é o desenvolvimento das funcionalidades.
É importante também, conhecer um pouco mais como funcionam essas abstrações por baixo dos panos, para conseguir extrair o melhor do que os frameworks e bibliotecas oferecem.
Tendo isso em mente, faremos um exercício de explorar algumas abstrações em um nível mais baixo, trocando a utilização do React e toda a stack de dependências do ecossistema que estamos acostumados por um código manual, sem abrir mão da simplicidade.
Vamos (re)visitar alguns tópicos antes:
1. Ferramentas (tooling)
Tooling são: os empacotadores, linters, code style, validadores de tipagens, transpiladores, etc... que irão auxiliar tanto no ambiente de desenvolvimento, quanto na transformação do código fonte para versão de produção.
2. Single page application (SPA)
SPA é o acrônimo de single page application, que carrega o conteúdo pesado da página apenas uma vez, na primeira requisição e que, quando abrimos links que pertencem a rota dessa aplicação, a página não será totalmente recarregada, possibilitando uma transição de página mais rápida.
Para que o SPA funcione dessa maneira, temos que direcionarmos todo o trafego de todas as rotas do servidor HTTP para um único HTML, por exemplo: /**/* -> /index.html
.
E todo o fluxo de requisição caindo no mesmo HTML, a aplicação SPA fica responsável por lidar com a rota e abrir a página correta e também por erros de página 404 (soft 404).
Outro problema conhecido de utilizar a estratégia SPA, é que o SEO (search engine optimization) se torna mais complicado, pois todas as tags SEO também são incluídas uma única vez no HTML.
3. Server side rendering (SSR)
SSR é o acrônimo de server side rendering, que entrega um HTML dinamicamente "renderizado" para rota em que o servidor é requisitado, fazendo o papel do primeiro render no lado do servidor e entregando tudo "pronto" para exibição no browser, o CSR (client side rendering).
Essa estratégia soluciona o problema do SEO citado anteriormente, pois quando o indexador visita uma rota específica, ele recebe o conteúdo HTML "renderizado".
4. Rehydrate
Quando utilizamos o SSR, podemos usar uma estratégia de reidratação, que irá sincronizar o estado do HTML previamente renderizado no lado do servidor, com a renderização da aplicação no lado do client (CSR).
Ao aplicar a reidratação, o resultado do DOM deve ser o mesmo do que vem pré renderizado, caso contrário, o virtual DOM (VDOM) terá uma diferença detectada invalidando essa pré renderização no SSR, e forçando atualizações desnecessárias no DOM.
5. DOM e VDOM
DOM é o acrônimo de document object model, é a representação da estrutura do HTML que o javascript utiliza em forma de API, para acessar e manipular essa estrutura.
O VDOM é uma representação virtual do DOM utilizado para capturar diferenças e calcular as atualizações que devem ser aplicadas diretamente no DOM.
Webpack
O webpack é um dos empacotadores mais utilizados e usaremos ele em conjunto com babel para transpilar e empacotar.
O plugin webpack-dev-server, fará o papel do servidor SPA, ele está configurado para redirecionar o trafego de todas as rotas para o index.html
, do jeito que precisamos para o desenvolvimento.
Lint e code-style
O eslint em conjunto com o prettier evitará erros de sintaxe, e também foi preparado uma configuração para o vscode, que ao salvar o arquivo, já deixa de acordo com as regras definidas no .eslintrc.json
.
Setup
O setup do projeto é uma configuração bem simples e pode ser visto no repositório git, comentarei aqui apenas alguns pontos relevantes.
Crie uma pasta e inicie o projeto com o yarn:
mkdir no-framework
cd no-framework
yarn init -y
Instale as dependências:
yarn add -D @babel/core @babel/plugin-transform-react-jsx @babel/preset-env @babel/preset-react @babel/preset-typescript @types/webpack-env @typescript-eslint/eslint-plugin @typescript-eslint/parser babel-loader css-loader eslint eslint-config-airbnb-base eslint-config-prettier eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-prettier fork-ts-checker-webpack-plugin html-webpack-plugin prettier style-loader tsconfig-paths-webpack-plugin typescript webpack webpack-cli webpack-dev-server
Adicione 2 scripts no package.json
...
"scripts": {
"dev": "webpack-dev-server --mode development",
"build": "webpack --mode production"
},
...
O .babelrc com os presets typescript e env, com plugin de JSX customizado possibilitará a escrita das tags JSX com as funções globais que serão descritas depois: _createElement
e _Fragment
, na seguinte configuração:
{
"presets": [
"@babel/preset-typescript",
["@babel/preset-env", { "targets": { "node": true } }]
],
"plugins": [
["@babel/plugin-transform-react-jsx", { "pragma": "_createElement", "pragmaFrag": "_Fragment" }]
]
}
O tsconfig.json
deve conter em compilerOptions
:
...
// preserve não altera os arquivos JSX, usaremos um custom
"jsx": "preserve",
// _createElement função global usada no lugar do React
"jsxFactory": "_createElement",
// _Fragment funçãco global usada no lugar do React.Fragment
"jsxFragmentFactory": "_Fragment",
...
Veja a configuração inteira no repositório https://github.com/joaoneto/no-framework/blob/main/tsconfig.json
Na configuração do webpack.config.js, usaremos 3 plugin:
- html-webpack-plugin para gerar o arquivo html com o carregamento dos scripts necessários.
-
tsconfig-paths-webpack-plugin para resolver caminhos com aliases nos imports partindo de
@/arquivo
ficará./src/arquivo
. - fork-ts-checker-webpack-plugin para validação de tipagem de forma assíncrona.
Tendo 2 regras de loaders:
- JS/TS:
babel-loader
- CSS:
style-loader
comcss-loader
Veja o arquivo completo em https://github.com/joaoneto/no-framework/blob/main/webpack.config.js
Para quem utiliza o vscode, existe a configuração que formata o código ao salvar em: .vscode/settings.json
Na pasta src/lib
ficam os arquivos de criação de elementos no DOM, navegação SPA, entre outras libs.
O arquivo que contem as funções responsáveis por criarem os elementos JSX na árvore DOM, ficam no arquivo: src/lib/create-element.ts
e são elas:
Fragment: Cria um elemento do tipo
DocumentFragment
, ele serve de container para agrupar a criação de elementos filhos pode ser usado com o alias<></>
que é o mesmo que importar a funçãoFragment
e usar:<Fragment></Fragment>
.createElement: Cria os elementos escritos com JSX ou importando a função
createElement
e usar:createElement('div')
ou com JSX:<div />
.
O arquivo que contem as funções de criação das rotas é o src\lib\router.ts
e as funções públicas são:
Router: Cria uma div que serve para renderizar os componentes Route.
Route: Cria o objeto de configuração da rota.
Link: Componente específico para navegação SPA.
Na pasta src/pages
ficam os componentes de páginas.
Página home:
import '@/lib/create-element';
export default () => {
return <h1>Home</h1>;
};
Na pasta src/design-system
ficam os estilos do design system e as definições de atributos de estilo passados nos elementos, no arquivo src\design-system\theme.d.ts
. Por exemplo o atributo primary
, que está configurado para setar background da cor primary.
Na pasta src/components
ficam os componentes da aplicação, que nesse exemplo não estão separados dos componentes básicos do design-system.
O src/index.tsx
escuta o evento DOMContentLoaded
e monta a aplicação com o tema do sistema (dark/light).
A tipagem dos componentes JSX não está funcionando propriamente ainda.
Alguns prós
- Um bundle bem compacto
- Inicialização rápida
- Proximidade maior com o javascript e css
Alguns contras
- Maior cuidado com elementos desvinculados do DOM e eventos que o GC (garbage collector) não conseguira liberar
- Exige maior conhecimento
- Gerenciamento de estado pode se tornar uma dor
Top comments (0)