no-framework, front-end moderno sem framework
Tags: javascript, productivity, performance, tooling
Published: 2022-04-04 03:21:07

## 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:

```shell
mkdir no-framework
cd no-framework
yarn init -y
```

Instale as dependências:
```shell
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
```js
...
  "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:
```js
{
  "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`:

```jsx
...
    // 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` com `css-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ção `Fragment` 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:
```js
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