Rails com inertiajs

Desenvolver e manter uma aplicação monolítica pode ser uma tarefa desafiadora. À medida que a aplicação cresce, surgem dificuldades como a escalabilidade, a manutenção do código, a integração de novas funcionalidades e a complexidade desde manipulação de DOM a deploys. Grandes bases de código monolíticas podem se tornar difíceis de…

Desenvolver e manter uma aplicação monolítica pode ser uma tarefa desafiadora. À medida que a aplicação cresce, surgem dificuldades como a escalabilidade, a manutenção do código, a integração de novas funcionalidades e a complexidade desde manipulação de DOM a deploys. Grandes bases de código monolíticas podem se tornar difíceis de gerenciar, especialmente quando várias equipes estão trabalhando nelas simultaneamente. No entanto, o uso de ferramentas adequadas pode aliviar alguns desses desafios.

Uma ferramenta bastante promissora com a qual me deparei há alguns dias, para mitigar as dores do desenvolvimento de uma aplicação monolítica, foi inertiajs

O que é Inertia.js?

Inertia.js é uma biblioteca que permite construir SPAs utilizando frameworks do lado do servidor, como Laravel, Rails, ou Django proporcionando uma experiência de desenvolvimento mais simples e coesa ao combinar o melhor dos dois mundos: a velocidade e a interatividade das SPAs com a simplicidade do desenvolvimento de aplicações server-rendered. Em vez de lidar com uma API separada para o front-end e back-end, Inertia.js funciona como uma ponte entre os dois, permitindo que você continue usando rotas e controladores do lado do servidor enquanto utiliza bibliotecas modernas de front-end como Vue.js, React ou Svelte.

O Inertia não é um framework, nem é um substituto para seus frameworks existentes do lado do servidor ou do lado do cliente.

Como Funciona?

Inertia.js age como um intermediário entre o front-end e o back-end. Ele captura as requisições do navegador e as envia para o back-end, que responde com dados JSON. Esses dados são então utilizados para renderizar componentes do front-end. Em vez de carregar páginas completas, apenas os dados necessários são trocados, proporcionando uma navegação mais rápida e responsiva.

Benefícios do Inertia.js

  1. Desenvolvimento Simplificado: Não há necessidade de gerenciar uma API REST ou GraphQL separada. Toda a lógica de controle pode ser mantida no back-end, enquanto a lógica de exibição reside no front-end.
  2. Sem API Adicional: Você não precisa criar uma API adicional para o front-end se comunicar com o back-end, o que economiza tempo e esforço.
  3. Transições Suaves: Inertia.js gerencia automaticamente as transições entre as páginas, proporcionando uma experiência de usuário suave e responsiva.
  4. SEO Amigável: Como as rotas ainda são gerenciadas no servidor, as páginas podem ser renderizadas no servidor para fins de SEO, garantindo que os mecanismos de busca possam indexar seu conteúdo.

Integração com Rails

Para fugir do famigerado ToDo, vamos criar uma aplicação com a seguinte estrutura

  • CRUD de Receitas/Despesas
  • CRUD de categorias para entradas
  • Um “dashboard” com um resumo das entradas

Vamos iniciar nossa aplicação

rails new cyber_inertia --skip-turbolinks

Vamos instalar a gem inertia_rails

bundle add inertia_rails

Vamos instalar a gem vite_rails para processar nossos assets

bundle add vite_rails
bundle exec vite install

Para o front, vamos instalar as seguintes libs

yarn add vite @vitejs/plugin-vue yarn add @inertiajs/inertia @inertiajs/inertia-vue3 @inertiajs/progress vue@next

Agora vamos configurar nossa aplicação para funcionar com inertiajs, vitejs, e vuejs

No nosso application.html.erb, vamos inserir os helpers do vite e inertia

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <%= csp_meta_tag %> 
    <%= inertia_headers %> 
    <%= vite_client_tag %> 
    <%= vite_javascript_tag 'application', defer: true %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

Instruções de configuração do Vite

import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'
import VuePlugin from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [
    RubyPlugin(),
    VuePlugin()
  ],
})
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { InertiaProgress } from '@inertiajs/progress';
InertiaProgress.init();

const pages = import.meta.glob('../Pages/**/*.vue', { eager: true });

createInertiaApp({
  resolve: (name) => {

    let page = pages[`../Pages/${name}.vue`];
    if (!page)
      throw new Error(
        `Unknown page ${name}. Is it located under Pages with a .vue extension?`,
      );
    page.default.layout = page.default.layout || Layout
    return page;
  },

  title: (title) => (title ? `${title} - CyberFin` : 'CyberFin'),

  setup({ el, App, props, plugin }) {
    const vueApp = createApp({
      render: () => h(App, props),
    });
    vueApp.use(plugin).mount(el);
  },
});

Pronto! Isso é tudo que precisa ser configurado para nosso front

Agora precisamos fazer a instrução dos nossos controllers para renderizarem com o inertia

Para que a postagem não fique muito extensa, vou mostrar apenas o exemplo de categorias

O código completo está no github!

class CategoriesController < ApplicationController
  def index
    @categories = Category.all
    render inertia: 'Categories/Index', props: { categories: @categories.as_json }
  end

  def new
    @category = Category.new
    render inertia: 'Categories/New', props: { category: @category }
  end

  def create
    @category = Category.new(category_params)
    if @category.save
      redirect_to categories_path, notice: 'Categoria criada com sucesso'
    else
      redirect_to new_category_path, inertia:{ errors: @category.errors.full_messages }
    end
  end

  def edit
    @category = Category.find(params[:id])
    render inertia: 'Categories/Edit', props: { category: @category, categories: @categories }
  end

  def update
    @category = Category.find(params[:id])
    if @category.update(category_params)
      redirect_to categories_path, notice: 'Categoria atualizada com sucesso.'
    else
      render inertia: 'Categories/Edit', props: { category: @category, categories: @categories }
    end
  end

  def destroy
    @category = Category.find(params[:id])

    if @category.destroy
      redirect_to categories_path, notice: 'Registro deletado com sucesso!'
    else
      redirect_to categories_path, alert: 'Erro ao deletar registro'
    end
  end

  private

  def set_categories
    @categories = Category.all
  end

  def category_params
    params.require(:category).permit(:name)
  end
end

Ao acessar /categories, será renderizado o seguinte component

<template>
  <div class="card mt-5">
    <div class="card-body">
      <div class="d-flex justify-content-between mb-3 border-bottom pb-2 align-items-center">
        <h5 class="card-title">Categorias</h5>
        <span>
          <Link :href="`/categories/new`" class="btn btn-dark">Nova</Link>
        </span>
      </div>
      <table class="table">
        <tbody>
          <tr v-for="category in categories" :key="category.id">
            <td>{{ category.name }}</td>
            <td class="text-end">
              <div class="btn-group">
                <Link :href="`/categories/${category.id}/edit`" class="btn btn-fin-default btn-sm" >Editar</Link>
                <Link :href="`/categories/${category.id}`" class="btn btn-danger btn-sm" method="delete" as="button">Excluir</Link>
              </div>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
import { Head, Link } from '@inertiajs/vue3';

export default {
  props: {
    categories: Array,
  },
  components: {
    Head,
    Link
  },
};
</script>

Nosso backend fará a integração direta com o front usando a resposta JSON abaixo

{
  "component": "Categories/Index",
  "props": {
    "flash": {},
    "categories": [
      {
        "id": 4,
        "name": "Supermercado",
        "created_at": "2024-06-27T12:08:04.390Z",
        "updated_at": "2024-06-27T12:08:04.390Z"
      },
      {
        "id": 17,
        "name": "Restaurante",
        "created_at": "2024-06-29T16:49:21.613Z",
        "updated_at": "2024-06-29T16:56:09.789Z"
      },
      {
        "id": 18,
        "name": "Moradia",
        "created_at": "2024-06-30T15:16:05.315Z",
        "updated_at": "2024-06-30T15:16:05.315Z"
      },
      {
        "id": 19,
        "name": "Carro",
        "created_at": "2024-06-30T18:44:55.786Z",
        "updated_at": "2024-06-30T18:46:11.789Z"
      },
      {
        "id": 20,
        "name": "Educação",
        "created_at": "2024-06-30T18:46:50.386Z",
        "updated_at": "2024-06-30T18:46:50.386Z"
      }
    ]
  },
  "url": "/categories/",
  "version": "c464e0528dd145387842d1c04fbc210654fb356d"
}

Conclusão

Vantagens

  1. Desenvolvimento Simplificado: Inertia.js elimina a necessidade de gerenciar uma API separada, simplificando o desenvolvimento.
  2. Integração Suave: A integração entre backend e frontend é direta e simplificada, permitindo um fluxo de trabalho mais coeso.
  3. Transições Suaves: Proporciona transições de página rápidas e suaves, melhorando a experiência do usuário.

Desvantagens

  1. Escalabilidade: Apesar de facilitar o desenvolvimento inicial, uma aplicação monolítica pode enfrentar desafios de escalabilidade à medida que cresce.
  2. Manutenção: A manutenção de uma grande base de código monolítica pode ser complexa e propensa a erros.
  3. Desempenho: O desempenho pode ser um problema em grandes monolitos, especialmente se não forem otimizados adequadamente.

Inertia.js oferece uma abordagem interessante para mitigar alguns dos desafios tradicionais das aplicações monolíticas, permitindo que os desenvolvedores aproveitem os benefícios tanto do desenvolvimento backend tradicional quanto das SPAs modernas.

Referências

0 Comentário