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