Atualizando na prática: Phoenix 1.5 para 1.6 (Elixir)

Phoenix e o Elixir proporcionam diversas facilidades e velocidade de desenvolvimento. Neste artigo, você confere o passo a passo de como elaborar um projeto Phoenix básico utilizando a versão 1.5 e e atualizá-lo para a versão 1.6.

Guilherme Ferreira

Guilherme Ferreira

January 11, 2022 | leitura de 14 minutos

dev

Hoje em dia, é imprescindível manter um projeto atualizado para acompanhar a evolução tecnológica e evitar vulnerabilidades. Pensando nisso, preparamos um passo a passo recheado de dicas e práticas relacionadas à atualização de um projeto com o framework Phoenix."

Os frameworks estão aí para nos ajudar a manter nossos projetos dentro das novas tendências tecnológicas e longe das ameaças de segurança. Mas não basta criar um projeto utilizando um framework e deixá-lo lá, parado e perdido no tempo. É preciso acompanhar as novidades atualizando-o para as novas versões disponíveis. 

Neste artigo, vamos elaborar um projeto Phoenix básico utilizando a versão 1.5 e depois vamos realizar todos os passos para atualizar para a versão 1.6.

Dicas importantes para a prática deste artigo 

  • Com o objetivo de facilitar sua vida e até para tirar alguma dúvida de algum código, subi o projeto final para o Github.

  • No projeto, foi utilizado um ambiente de desenvolvimento configurado pelo Docker. Mais sobre o Docker aqui.

  • Também é recomendada a instalação do Elixir em sua máquina de desenvolvimento para iniciar o projeto via comando. Acesse.

Já falamos de Elixir aqui

Não conhece o Elixir ou está se perguntando se deve ou não utilizá-lo em seu projeto? Sua resposta pode estar neste artigo aqui, com tudo o que você precisa saber para fazer a sua escolha.

E, se você quiser saber mais sobre a escalabilidade do Elixir, acesse este outro artigo aqui.

Codando com Phoenix

Para os amantes do desenvolvimento utilizando o padrão Model View Controller (MVC), o Phoenix chega com tudo como um framework de desenvolvimento web utilizando o Elixir. O Phoenix busca entregar alta produtividade do desenvolvedor e alto desempenho do aplicativo. 

Para mais detalhes sobre o Phoenix, acesse o guia de introdução disponível na sua documentação.

Colocando a mão na massa

O nosso projeto inicial vai conter um CRUD básico e algumas dependências também básicas encontrados em projetos do nosso dia a dia. 

Para conseguir demonstrar alguns desafios, vou preparar um CRUD básico com todos os testes unitários necessários e vou utilizar o exemplo de layout do próprio Phoenix utilizando um processador de Sass para as folhas de estilos do projeto. 

Com isso, vamos conseguir exercitar o processo de atualização para a versão 1.6 do Phoenix.

Iniciando o projeto Phoenix na versão 1.5

Tudo pronto para colocar a mão na massa? Vamos criar um projeto Phoenix utilizando a versão 1.5. Para isso, vamos rodar o comando:

$ mix archive.install hex phx_new 1.5.0 Esse é o comando que vai atualizar o nosso gerador de projetos para criar projetos com a versão 1.5.

Agora, vamos criar nosso projeto com o nome de blog:

$ mix phx.new blog

Antes de prosseguirmos, vamos preparar o projeto para rodar dentro de um ambiente fornecido pelo Docker que vai simular um ambiente Linux e prover toda a estrutura necessária para a nossa aplicação. 

Para isso, crie dois arquivos na raiz do projeto: docker-compose.yml e Dockerfile.

docker-compose.yml

 app:
  build: .
  tty: true
  stdin_open: true
  volumes:
    - .:/blog
  ports:
    - 4000:4000

web:
  extends: app
  environment:
    - USER
    - USERNAME
    - MIX_ENV=dev
    - PG_HOST=db
    - PG_USERNAME=postgres
    - PG_PASSWORD=postgres
    - METABASE_URL=qwuyiqwtqyu7812617826sajsjhasbaj
    - METABASE_SECRET_KEY=jhadsdiasgdisagig2176217268188sabjsajshaj
  links:
    - db

tests:
  extends: app
  environment:
    - USER
    - USERNAME
    - MIX_ENV=test
    - PG_HOST=db
    - PG_USERNAME=postgres
    - PG_PASSWORD=postgres
  links:
    - db

db:
  image: postgres:9.5
  environment:
    - POSTGRES_PASSWORD=postgres
  ports:
    - 5432:5432

Dockerfile:

 FROM elixir:1.12
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
  apt-get install -y postgresql-client inotify-tools
RUN mix local.hex --force
RUN mix local.rebar --force
RUN mix archive.install hex phx_new 1.5.0 --force
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN apt-get install -y -q nodejs
RUN apt-get install -y -q inotify-tools
# Install hex & rebar
RUN mix local.hex --force && \
  mix local.rebar --force && \
  mix hex.info
RUN mkdir -p /blog
COPY . /blog
WORKDIR /blog
ENV MIX_ENV dev
EXPOSE 4000
EXPOSE 4002
CMD ['mix', 'phx.server']

Esses dois arquivos serão utilizados pelo Docker para a criação de um ambiente com tudo aquilo de que nossa aplicação vai precisar.

O próximo passo é configurar as informações do banco de dados que vamos utilizar no ambiente de desenvolvimento. Altere o arquivo config/dev.exs:

config :blog, Blog.Repo,
  username: Map.get(System.get_env(), 'PG_USERNAME', 'postgres'),
  password: Map.get(System.get_env(), 'PG_PASSWORD', 'postgres'),
  database: 'blog_dev',
  hostname: Map.get(System.get_env(), 'PG_HOST', 'localhost'),
  show_sensitive_data_on_connection_error: true,
  pool_size: 10

Vamos atualizar as configurações do banco de dados para os testes. Altere o arquivo config/tests.exs:

config :blog, Blog.Repo,
  username: Map.get(System.get_env(), 'PG_USERNAME', 'postgres'),
  password: Map.get(System.get_env(), 'PG_PASSWORD', 'postgres'),
  database: 'blog_test#{System.get_env('MIX_TEST_PARTITION')}',
  hostname: Map.get(System.get_env(), 'PG_HOST', 'localhost'),
  show_sensitive_data_on_connection_error: true,
  pool_size: 10,
  pool: Ecto.Adapters.SQL.Sandbox

Com isso, já podemos rodar os próximos comandos e a nossa aplicação.

O comando abaixo vai importar as dependências do projeto, criar a estrutura do banco de dados e processar o CSS e JS do projeto.

$ docker-compose run --rm web mix setup

Já o próximo vai iniciar os containers do Docker para rodar o nosso projeto.

$ docker-compose up -d web

Nesse momento o projeto já está pronto para ser exibido na url: http://localhost:4000

Blog post _ 11.01.2022_Atualizando na prática o Phoenix 1.5 para a versão 1.6 (Elixir)_1.png

Já estamos quase lá com a preparação do nosso projeto inicial. Resta apenas criar um CRUD básico e rodar os testes para ver se está tudo funcionando bem.

Para criarmos um CRUD básico, vamos utilizar o recurso phx.gen.html, que faz parte do conjunto de comandos que facilitam nossa vida durante o desenvolvimento. Vamos criar um CRUD com o cadastro de usuários rodando o seguinte comando:

$ docker-compose run --rm web mix phx.gen.html Accounts User users name:string email:string

Nesse comando, passei o nome do contexto, o módulo, o nome da tabela e seus atributos com suas especificações de tipo. Com isso, o sistema implementa praticamente todo o CRUD faltando apenas a configuração das rotas e rodar um comando para criar a tabela no banco de dados. E é exatamente isso o que vamos fazer agora.

Vamos configurar as rotas para a criação de usuários dentro do nosso projeto. Para isso, podemos acrescentar a nova rota no arquivo de configuração lib/blog_web/router.ex.

O código vai receber a linha:

resources '/users', UserController
E vai ficar assim:
scope '/', BlogWeb do
    pipe_through :browser
    get '/', PageController, :index
    resources '/users', UserController
  end

Basta rodar o comando para criar a tabela no banco de dados:

$ docker-compose run --rm web mix ecto.migrate

Tudo pronto. Nosso CRUD está criado e pode ser acessado pela url: http://localhost:4000/users

Blog post _ 11.01.2022_Atualizando na prática o Phoenix 1.5 para a versão 1.6 (Elixir)_2.png

O último passo é verificar se os testes estão rodando corretamente por meio da execução do comando:

$ docker-compose run --rm tests mix test

Repare que, com esse comando, vamos executar o outro container (tests) do Docker que criamos apenas para os testes. Se tudo der certo, o terminal deve retornar o seguinte:

  • Finished in 0.3 seconds (0.2s async, 0.08s sync)
  • 19 tests, 0 failures

Os recursos do Phoenix 1.5

Nesta versão (comparando com a versão 1.4), o framework recebeu alguns aprimoramentos - com destaque para o mix phx.gen.live para geração LiveView CRUD; para a migração para o PubSub 2.0 com um mecanismo de planejamento rápido mais flexível; e para o render_layout para trabalhar com layouts aninhados. 

Como deprecações, o destaque vai para a alteração de use Phoenix.ChannelTest para import Phoenix.ChannelTest; para a obsolescência de Phoenix.ConnTest - alterado para import Plug.Conn; import Phoenix.ConnTest -; e a mudança nas configurações de layout alterando o:

<%= render @view_module, @view_template, assigns %>

Para:

<%= @inner_content %>

Então, se você está atualizando o seu projeto da versão 1.4 para 1.5, a dica é acompanhar as principais alterações aqui, neste guia.

Novidades do Phoenix 1.6

Antes de iniciarmos nossa atualização, vamos destacar as principais alterações desta nova versão. 

Em primeiro lugar, destaque para a adição do:

--database sqlite3

Ele facilita a nossa vida para criarmos projetos rápidos sem precisarmos configurar um banco de dados local ou utilizarmos o Docker ou outro recurso para rodarmos o projeto, o que é ideal para testes de conceitos.

Destaque também para o novo comando:

$ mix phx.gen.auth

Ele gera todo o sistema de login para uma nova aplicação acelerando ainda mais o desenvolvimento.

Por fim, o grande destaque vai para a utilização do esbuild em vez do webpack, dando uma limpada em nossas dependências desatualizadas de JS e dando uma acelerada na geração e processamento dos assets.

Iniciando a atualização para o Phoenix 1.6

Chegamos ao momento crucial do nosso artigo, no qual vamos evoluir nosso projeto 1.5 para o novo 1.6 com todas essas novidades que citei e muito mais.

A primeira coisa a se fazer é verificar a versão do Elixir que essa nova versão utiliza. No nosso caso, o Phoenix requer a versão 1.9 ou superior do Elixir - e, no nosso projeto, já configuramos o Docker para utilizar a versão 1.12 na configuração do Dockerfile.

Seguindo nessa mesma linha, vamos alterar o Dockerfile para atualizar o phx_new modificando a linha:

RUN mix archive.install hex phx_new 1.5.0 --force

Para:

RUN mix archive.install hex phx_new 1.6.0 --force

Nessa nova versão, vamos utilizar o esbuild. Com isso, vamos poder atualizar a versão do Node JS na configuração do Docker. Vamos alterar o Dockerfile substituindo:

RUN curl -sL https://deb.nodesource.com/setup_10.x

Por:

RUN curl -sL https://deb.nodesource.com/setup_15.x

Essa configuração só é necessária se o seu projeto for utilizar o Node JS para baixar alguma dependência. Aqui no projeto não vamos precisar usar o Node JS e poderíamos até remover essa linha.

Com isso, finalizamos a configuração do Docker para atender e rodar as novidades do Phoenix 1.6.

O próximo passo é atualizar as dependências do framework atualizando o arquivo mix.exs. Vamos modificar as libs: phoenix, phoenix_html, telemetry_metrics, telemetry_poller e phoenix_live_dashboard, assim como adicionar o phoenix_live_view.

def deps do
    [
      {:phoenix, '~> 1.6.0'},
      {:phoenix_html, '~> 3.0'},
      {:phoenix_live_view, '~> 0.16.4'},
      {:phoenix_live_dashboard, '~> 0.5'},
      {:telemetry_metrics, '~> 0.6'},
      {:telemetry_poller, '~> 0.5'},    ]
end

Ainda não precisamos rodar o comando para atualizar essas dependências do projeto porque, antes disso, vamos realizar mais algumas modificações, apagar todos os containers do Docker e rodar tudo novamente para atualizar o ambiente de desenvolvimento. 

Uma alteração opcional é a modificação dos arquivos de template .html.eex e .html.leex para o novo .html.heex, que traz algumas alterações que podem gerar dor de cabeça para devs com projetos grandes.

O que muda, basicamente, é a extensão dos arquivos de template e a sintaxe no código pela alteração apenas das tags de abertura <%= %> dentro das tags de html para {}. Exemplo:

Para:

Repare que as aspas duplas foram removidas também. Eu não tinha notado isso e quebrei a cabeça aqui tentando entender (rsrs). No projeto, vou realizar essa alteração apenas no arquivo app.html.eex, e isso você vai conferir no decorrer da leitura.

Claro que na versão 1.6 essa alteração é opcional, mas pode se tornar obrigatório mais para frente.

Por último e não menos importante, pois acredito que é uma das grandes alterações do projeto, é a possibilidade de utilizar o esbuild em vez do webpack. Claro, é uma alteração opcional também.

Vamos adicionar o esbuild nas dependências do projeto em mix.exs:

{:esbuild, '~> 0.2', runtime: Mix.env() == :dev},

Depois, vamos adicionar a configuração em config/config.exs:

config :esbuild,
  version: '0.12.18',
  default: [
    args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
    cd: Path.expand('../assets', __DIR__),
    env: %{'NODE_PATH' => Path.expand('../deps', __DIR__)}
  ]

Substituir, em config/dev.exs:

watchers: [
    node: [
      'node_modules/webpack/bin/webpack.js',
      '--mode',
      'development',
      '--watch-stdin',
      cd: Path.expand('../assets', __DIR__)
    ]
  ]

Por:

watchers: [
    esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}
  ]

Em mix.exs, adicionar em aliases:

assets.deploy': 'esbuild default --minify', 'phx.digest'

Adicionar esse comando em setup dessa forma:

setup: 'deps.get', 'ecto.setup', 'assets.deploy',

Renomear o lib/blog_web/templates/layout/app.html.eex para lib/blog_web/templates/layout/app.html.heex e substituir:

<link rel='stylesheet' href='<%= Routes.static_path(@conn, '/css/app.css') %>'/>

Por:

<link phx-track-static rel='stylesheet' href={Routes.static_path(@conn, '/assets/app.css')}/>
    <script defer phx-track-static type='text/javascript' src={Routes.static_path(@conn, '/assets/app.js')}></script>

Fiz todas as modificações em app.html.heex para adequar a nova sintaxe do heex. Confira como ficou o arquivo:

<!DOCTYPE html>
<html lang='en'>
  <head>
    <meta charset='utf-8'/>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'/>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'/>
    <title>Blog · Phoenix Framework</title>
    <link phx-track-static rel='stylesheet' href={Routes.static_path(@conn, '/assets/app.css')}/>
    <script defer phx-track-static type='text/javascript' src={Routes.static_path(@conn, '/assets/app.js')}></script>
  </head>
  <body>
    <header>
      <section class='container'>
        <nav role='navigation'>
          <ul>
            <li><a href='https://hexdocs.pm/phoenix/overview.html'>Get Started</a></li>
            <%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
              <li><%= link 'LiveDashboard', to: Routes.live_dashboard_path(@conn, :home) %></li>
            <% end %>
          </ul>
        </nav>
        <a href='https://phoenixframework.org/' class='phx-logo'>
          <img src={Routes.static_path(@conn, '/images/phoenix.png')} alt='Phoenix Framework Logo'/>
        </a>
      </section>
    </header>
    <main role='main' class='container'>
      <p class='alert alert-info' role='alert'><%= get_flash(@conn, :info) %></p>
      <p class='alert alert-danger' role='alert'><%= get_flash(@conn, :error) %></p>
      <%= @inner_content %>
    </main>
  </body>
</html>

Por fim, atualize o Plug.Static :only em lib/app_web/endpoint.ex para:

plug Plug.Static,
    at: '/',
    from: :blog,
    gzip: false,
    only: ~w(assets fonts images favicon.ico robots.txt)

Com isso, já podemos remover as configurações do webpack na pasta assets. Remova os arquivos webpack.config.js, .babelrc, package.json, package-lock.json e a pasta node_modules. 

Você deve ter pensado: 'Nossa, me livrei de tudo isso!' Mas claro que, se você tiver muitas dependências de JS e CSS, poderá configurá-las usando o esbuild - e, para isso, recomendo seu acesso aqui para mais informações.

Altere o arquivo assets/js/app.js removendo a importação do '../css/app.scss' e adicionando o:

import '../css/phoenix.css'

Em assets/css/app.scss vamos remover a linha:

@import './phoenix.css';

Tudo certo. Vamos atualizar agora o Docker e rodar o nosso projeto novamente utilizando o Phoenix 1.6.

$ docker stop $(docker ps -a -q)
$ docker rm $(docker ps -a -q)
$ docker system prune --volumes

Rode novamente os comandos para iniciar o projeto.

$ docker-compose run --rm web mix setup && docker-compose up -d web

Rode o projeto e perceba que apenas o Sass que tínhamos na versão anterior não foi gerado. Vamos resolver isso agora utilizando outra lib em mix.exs:

{:dart_sass, '~> 0.2', runtime: Mix.env() == :dev}

Depois de adicionarmos, vamos configurar em config/config.exs:

config :dart_sass,
  version: '1.43.4',
  default: [
    args: ~w(css/app.scss ../priv/static/assets/app.css),
    cd: Path.expand('../assets', __DIR__)
  ]

Vamos, também, adicionar mais um recurso nos watchers em config/dev.exs:

sass: {
    DartSass,
    :install_and_run,
    [:default, ~w(--embed-source-map --source-map-urls=absolute --watch)]
  }

Ele deve ficar assim:

watchers: [
    esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
    sass: {
      DartSass,
      :install_and_run,
      [:default, ~w(--embed-source-map --source-map-urls=absolute --watch)]
    }
  ]

Vamos rodar novamente o comando:

$ docker-compose run --rm web mix setup

Com isso, nosso projeto vai rodar corretamente processando SASS, CSS e JS sem utilizar o webpack e você pode importar libs externas de JS, SASS ou CSS e configurar da mesma forma que fizemos. Simples assim.

Rode o comando de testes para verificar se continua rodando corretamente.

$ docker-compose run --rm tests mix test

Projeto rodando com Phoenix 1.6

Você deve ter percebido as facilidades e velocidade de desenvolvimento que o Phoenix e o Elixir proporcionam. São poucos minutos para criar e rodar um projeto com uma configuração de banco de dados e ainda um CRUD completo. Espero que tenha ajudado a entender os principais passos para atualizar um projeto Phoenix. Qualquer dúvida, é só entrar em contato com a gente.

Referências:

Guilherme Ferreira
Guilherme Ferreira

Software Engineer formado em Ciência da Computação. Tutor de cursos e desenvolvedor de software. Curte explorar novas tecnologias e estudar inteligência artificial.

LinkedInInstagramGithubMedium