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 atualizá-lo para a versão 1.6.
Guilherme Ferreira | 11 de janeiro de 2022

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 Phoenix 1.5 e depois vamos realizar todos os passos para atualizar para a versão Phoenix 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= --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:

'/>

Por:

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


Get Started
<%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
<%= link 'LiveDashboard', to: Routes.live_dashboard_path(@conn, :home) %>
<% end %>
<%= get_flash(@conn, :info) %>
<%= get_flash(@conn, :error) %>
<%= @inner_content %>

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= --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
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.