Gabriel / Ramos

⟨ pintor de pixel ⟩


  • Home
  • Blog
  • Minha aplicação com Gastby cresceu

Minha aplicação com Gastby cresceu

Algumas situações que passei, decisões que tomei e plugins que me salvaram a pele

7 min. de leitura

Foto por Jukan Tateisi

Tenho trabalhado com Gatsby em alguns projetos ultimamente (além do blog/site), e um deles tomou uma proporção razoavelmente grande: é um site com algumas 8/9 páginas mas que possui algumas necessidades interessantes e acho que você pode passar por algumas das situações pelas quais passei caso esteja utilizando essa ferramenta também.

Estrutura de páginas e seções

É bem comum que você escreva seus componentes diretamente nas suas páginas e essa, com certeza, é a melhor e mais prática forma de trabalhar.

Entretanto, quando suas páginas começam a crescer e você começa a criar vários componentes, pode ser que seu esse componente que contém a sua página fique um pouco grande. Para lidar com esses casos, Decidi separar o conteúdo de minhas páginas em 2 diretórios: pages (a padrão do gatsby) e sections (onde as seções de cada página estariam).

Dessa forma, os arquivos dentro de pages ficam, atualmente, responsáveis apenas por montar a estrutura básica repetida de cada da página com layout, banner, seo e fazer a consulta em graphql das imagens necessárias e os componentes dentro de sections recebem essas imagens como prop e inserem de fato o conteúdo, a estrutura ficou algo como:

|src
|____pages
|       sobre.js
|____sections
|       sobre.js

Onde, no componente da página, ele possui uma declaração parecida com:

// arquivo pages/sobre.js

import React from 'react';
import { graphql } from 'gatsby';

import Layout from '../components/layout';
import SEO from '../components/seo';
import Banner from '../components/banner';
import Sections from '../sections/sobre';

const SobrePage = ({
  data
}) => {
  const images = {
    // trata imagens e monta melhor estrutura para as seções
  }

  return (
    <Layout>
      <SEO title="sobre" />
      <Banner />
      <Sections images={images} />
    </Layout>
  );
};

export const query = graphql`
  // ... consulta imagens
`;

export default SobrePage;

E o componente da seção ficaria mais ou menos assim:

// arquivo sections/sobre.js

import React from 'react';

const SobreSections = ({ images }) => (
  <>
    <div>conteudo</div>
  </>
);

export default SobreSections;

Talvez possa parecer uma estrutura um pouco repetitiva, mas conforme essas seções vão crescendo, achei que deu uma boa ajuda.

Caso você também precise utilizar subpáginas, você pode criar outras diretórios recursivamente dentro desse diretório sections e utilizar barrel exports para facilitar os imports dessas suas páginas.

Por exemplo, imagine que nossa página sobre, agora possuirá outras 3 subpáginas: /sobre/empresa, /sobre/servico e /sobre/membros.

Nesse cenário você poderia ter uma estrutura parecida com:

|src
|____pages
|   |____sobre
|           empresa.js
|           servico.js
|           membros.js
|____sections
|   |____sobre
|           index.js
|           empresa.js
|           servico.js
|           membros.js

Facilitando o trabalho de import/export, no arquivo index.js, da seguinte maneira:

export { default as EmpresaSections } from './empresa';
export { default as ServicoSections } from './servico';
export { default as MembrosSections } from './membros';

E noas arquivos de cada página, os imports podem ficar algo como:

import { EmpresaSections as Sections } from '../sections/sobre';

Lidando com imports na aplicação

É bem comum criarmos alguns aliases para facilitar a tarefa de lidar com os caminhos de diretórios de nossos arquivos.

Com Gatsby não foi diferente e o plugin que me ajudou nessa tarefa foi o gatsby-plugin-alias-imports.

Não tem muito o que falar sobre ele, basta instalá-lo:

npm i --save gatsby-plugin-alias-imports

E configurar os alias necessários (dentro dos plugins no arquivo gatsby-config.js):

const path = require('path');

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-alias-imports`,
      options: {
        alias: {
          '@components': path.resolve(__dirname, 'src/components'),
          '@sections': path.resolve(__dirname, 'src/sections'),
          '@providers': path.resolve(__dirname, 'src/providers'),
          '@hoc': path.resolve(__dirname, 'src/hoc'),
          '@styles': path.resolve(__dirname, 'src/styles')
        },
        extensions: ['js', 'scss']
      },
    },
  ]
}

Agora o diretório src/components do projeto, pode ser acessada assim, dentro dos componentes:

import Card from '@components/card';

Bem mais fácil do que ficar inserindo o caminho relativo ao arquivo, né?

Vale lembrar que, caso esteja utilizando o VSCode, você precisará configurar o arquivo jsconfig.json para que ele continue te ajudando com aqueles autocompletes dos arquivos das diretórios. Com a estrutura de aliases acima, temos algo como:

{
  "compilerOptions": {
    "target": "es6",
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@sections/*": ["sections/*"],
      "@providers/*": ["providers/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": [
    "node_modules",
    "public",
    "dist",
    "build"
  ]
}

Se você quiser ler um pouco mais sobre essas configurações, você pode acessar a página do VSCode que fala mais detalhadamente.

Estruturas extras (de sua preferência)

Ali no trecho de configuração dos aliases vocês devem ter visto que além da diretório components e sections, que comentamos, existe algumas outras diretórios, e são elas:

  • provider: separei essa diretório para representar às estruturas responsáveis por realizar chamadas HTTP na aplicação com base na Context API do React, com hooks (como o useContextValue);
  • hoc: alguns higher-order components da aplicação;
  • styles: como os estilos desse projeto são feitos utilizando SASS, alguns arquivos base estão ali (como as variáveis e alguns mixins com os breakpoints).

Lidando com traduções (internacionalização)

Começando a pesquisar sobre o tópico você vai encontrar a página do Gatsby que fala sobre o assunto. Além de falarem que você pode escolher uma ferramenta para realizar as traduções, deixam como exemplo o plugin gatsby-plugin-i18n.

O detalhe desse plugin é que, para cada idioma, você precisa de um novo arquivo de cada página: por exemplo, uma página sobre.js, para ser traduzida para inglês e espanhol, você teria sobre.en.js e sobre.es.js, que criaria as respectivas rotas /en/sobre/ e /es/sobre.

Provavelmente você não vai querer duplicar suas páginas completamente apenas para mudar o conteúdo. Duplicar essas páginas completamente apenas para mudar o conteúdo acaba se tornando uma tarefa chata e repetitiva, se suas páginas forem relativamente grandes esse problema se torna ainda pior.

Pesquisando um pouco mais, encontrei um plugin chamado gatsby-plugin-intl que atendeu perfeitamente às minhas necessidades e realiza traduções baseada em arquivos .json de configuração dos idiomas desejado (e com um suporte bacana aos hooks).

Basicamente, basta instalá-lo:

npm i --save gatsby-plugin-intl

E configurar (dentro dos plugins no arquivo gatsby-config.js):

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-intl`,
      options: {
        path: `${__dirname}/src/translations`,
        languages: ['pt', 'en', 'es'],
        defaultLanguage: 'pt',
        redirect: false,
      },
    },
  ]
}

Onde:

  • path: contém o caminho, no seu projeto, para onde os arquivos .json de tradução estão localizados;
  • languages: um array contendo as siglas dos idiomas das traduções (que também devem ser os nomes dos arquivos, respectivamente);
  • defaultLanguage: valor "padrão", que serve como idioma base para tradução (no caso, o site é em português por padrão);
  • redirect: booleano que indica se, ao acessar a raíz do projeto /, o usuário deve ser redirectionado para o caminho da linguagem padrão. Nesse caso, se estivesse como true, os usuários seriam redirecionados para /pt toda vez que acessassem o site e não era um comportamento que queríamos.

Dessa forma, a estrutura das traduções ficou algo como:

|src
|____translations
|       pt.json
|       en.json
|       es.json

Onde, cada arquivo .json possui as chaves que serão utilizadas como tradução:

{
  "header": {
    "title": "name"
  }
}

E dentro dos componentes que precisam de um conteúdo traduzido, basta importar o hook (se quiser dessa maneira) e utilizá-lo, passando como id a chave do conteúdo a ser traduzido:

import { useIntl } from 'gatsby-plugin-intl';

const Header = () => {
  const intl = useItnl();

  return (
    <header>{intl.formatMessage({ id: 'header.title' })}</header>
  );
}

Esse plugin também te permite usar um componente Link, que faz a navegação de forma parecida ao Link do gatsby, mas mantém a linguagem escolhida do usuário.

Conteúdo customizado por rota

É comum em alguns sites você ter algum conteúdo customizado baseado na rota que o usuário está acessando.

Por exemplo: na página /sobre, o o texto sobre no menu do seu site ficar com algum detalhe diferente, fazendo com que o usuário identifique que é a página ativa atualmente.

Para realizar algumas customizações como essa, você pode passar a página atual como prop pro seu componente desejado, mas caso queira deixar essas definições dinâmicas e consultar as rotas da aplicação sem ter que passar esses valores manualmente, o Gatsby disponibiliza também o pacote @react/router para você utilizar.

Dessa forma, você consegue trabalhar um pouco melhor com as rotas que o usuário está acessando, sem precisar instalar outros pacotes extras.


Conclusão

Esses foram alguns desafios que enfrentei nesse projeto que tomou uma proporção interessante.

Sinta-se à vontade para comentar e compartilhar suas decisões e outras abordagens que te ajudaram nos projetos utilizando Gatsby! Espero que esses plugins e dicas de estrutura possam te ajudar também!