Criando aplicação VueJS usando Flask como servidor web. (Python/Javascript)

Criando aplicação VueJS usando Flask como servidor web. (Python/Javascript)

Overview

Neste post, vamos embarcar juntos na aventura de combinar o dinamismo do VueJS com a robustez do Python para criar uma aplicação full-stack que é tanto poderosa quanto elegante. Se você, assim como eu, teve dificuldades para navegar pela integração dessas tecnologias, ou simplesmente deseja aprender a fazer isso do jeito certo desde o início, chegou ao lugar certo. Preparado para dominar Flask e VueJS de uma forma descomplicada? Então, vamos lá!

Quando comecei a estudar VueJS, logo pensei: Vou criar uma aplicação com a API + Backend feitos em Python, o frontend em VueJS e vai ficar muito foda!

Só que na hora que eu fui tentar, acabei apanhando um tanto. Especialmente por estar usando o vue-cli3, pois os exemplos que eu encontrava utilizavam versões mais antigas.

Conforme eu pesquisava, fui chegando a conclusão de que estava fazendo algo de errado. Então resolvi começar o projeto novamente e descobri que sim: Estava problematizando algo simples.

Então, para evitar que você perca tanto tempo quanto eu perdi, fiz este tutorial para mostrar como montei meu projeto VueJS + Flask .

Para este tutorial, vou presumir que você já possui o Python 3.6+ e o Node (+npm) instalado em sua maquina.

Pré-requisitos

Um aviso para todos os comandos desta seção: Se estiver no Linux/Mac, provavelmente vai precisar colocar sudo na frente deste comando. Se estiver no Windows, vai precisar de estar com uma janela do prompt aberta com privilégios de administrador.

1. Instalar Flask

pip install Flask

2. Instalar VueJS

npm install vue

(Se o VueJS já estiver instalado na sua maquina, ignore este passo.)

3. Atualize o Vue CLI para a versão 3

npm install @vue/cli -g

Preparando ambiente

1. Local para o projeto.

A primeira coisa que precisamos fazer é criar um local para o nosso projeto. Você (provavelmente) tem uma estrutura de diretórios propria que gosta de utilizar, mas para este exemplo, vamos criar da seguinte forma:

  1. c:\\Flask-VueJS: Este diretório vai ser o root do projeto;
  2. .\backend: Vai armazenar o código em python e o código pronto (após build) do VueJS.
  3. .\frontend: Onde o fonte da aplicação VueJS vai ficar.

Eu sei que estes nomes não condizem exatamente com os conceitos de frontend/backend, mas acho que fica assim fica mais simples (em termos didáticos).

No Windows:

mkdir c:\Flask-Vue\backend

No Linux, utilize:

mkdir -p \Flask-Vue\backend

Tanto o comando para Windows quanto o para Linux vão criar tanto o diretório Flask-Vue quanto o backend de uma vez. Você deve ter reparado que eu não criei o diretório frontend. Foi de propósito. O Vue irá cria-lo para nós.

Criando o projeto em VueJS (e o diretório frontend).

No diretório raiz do nosso projeto, utilize o vue-cli para criar o projeto.

cd c:\Flask-Vue
vue create frontend

Neste caso, frontend é o nome do projeto em VueJS que estamos criando. a interface do vue-cli vai cuidar de criar um diretório com o nome do projeto (que, no nosso caso, é o frontend) e vai colocar lá os arquivos necessários.

Opcional: As configurações que utilizei para o projeto em VueJS

Esta seção do post é opcional, apenas para mostrar as opções que escolhi na hora de criar o projeto. O bloco abaixo representa a última “tela” das configurações e ela mostra todas as opções que marquei.

Vue CLI v3.0.3
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) N

1. Incluindo o VuetifyJS

Se você não conhece, VuetifyJS é um framework de componentes visuais que utiliza o estilo Material Design (da Google). Você não precisa instalar este framework mas, na minha opinião, ele é muito bom, fácil de usar e possui uma quantidade grande de componentes.

Se quiser instalar, acesse o diretório do projeto e utilize o comando abaixo:

cd frontend
vue add vuetify

Opcional: As configurações que utilizei para instalar o VuetifyJS

Assim como na criação do projeto VueJS, vou listar aqui as opções que escolhi na hora de instalar o framework. Você pode alterar as opções da forma que preferir. Novamente, para não poluir demais o post, vou deixar apenas a última “tela” da configuração, mas ela mostra todas as opções que escolhi.

? Use a pre-made template? (will replace App.vue and HelloWorld.vue) Yes
? Use custom theme? Yes
? Use custom properties (CSS variables)? No
? Select icon font md
? Use fonts as a dependency (for Electron or offline)? Yes
? Use a-la-carte components? No
? Use babel/polyfill? Yes
? Select locale
  1) English (default)
  2) Catalan
  3) Chinese (simplified)
  4) Chinese (traditional)
  5) Dutch
  6) Farsi
(Move up and down to reveal more choices)
  Answer: 1

Alterando configurações de build do projeto VueJS

Quando você realiza o build do projeto, ou seja, prepara o projeto do VueJS para ser utilizado em produção, os scripts executados apagam o diretório de saída dos arquivos. Todavia, os arquivos gerados pelo VueJS devem ficar nos diretórios templates e static (do Flask).

Para conseguir fazer isso, devemos criar o arquivo vue.config.js, que vai sobrescrever algumas configurações padrão do framework.

No diretório frontend, adicione um arquivo com o nome vue.config.js e inclua o seguinte conteúdo:

module.exports = {
  outputDir: '../backend/templates/vue',
  indexPath: './index.html',
  assetsDir: '../../static/vue'
}

Acima estamos exportando algumas variáveis:

  • outputDir: Indica o diretório base onde os arquivos “de produção” serão gerados. Lembrando que este arquivo está no diretório frontend, o que eu fiz foi voltar um diretório, acessar o diretório backend, depois o templates e defini o diretório vue como o local onde os templates serão salvos para o Flask consumir;
  • indexPath: Indica o caminho para o arquivo index.html. Este caminho é relativo ao que você definiu na variável outputDir;
  • assetsDir: Indica o caminho onde os recursos (assets) da aplicação serão salvos. Estes assets são as imagens, arquivos .js, .css e outros. Como este também é um valor relativo ao que foi definido na outputDir. Neste caso, para aderir aos padrões do Flask, precisamos colocar os assets dentro do diretório static, que existe dentro do backend. Como o diretório do output (outputDir) está definido para backend/templates/vue e nós precisamos chegar no diretório /backend/static/vue, temos que voltar dois diretórios primeiro.

Caso tenha ficado confusa a explicação acima, veja os caminhos absolutos equivalentes aos que inseri nas variáveis acima:

  • outputDir: c:\Flask-Vue\backend\templates\vue
  • indexPath: c:\Flask-Vue\backend\templates\vue\index.html (outputDir + index.html)
  • assetsDir: c:\Flask-Vue\backend\static\vue

Você deve ter reparado que eu inclui o diretório vue nestes caminhos. Fiz isso por duas razões:

  1. Como mencionei anteriormente, toda vez que você executar o build, o diretório que foi definido no outputDir será deletado. Para evitar que arquivos importantes do backend sejam apagados, melhor deixar os arquivos do VueJS isolados.
  2. Falando em isolar arquivos. Esta foi a outra razão pela qual deixei estes arquivos em lugares separados. Desta forma, evitamos que os arquivos criados pelo VueJS ou utilizados por ele acabem se misturando com os que (eventualmente) serão criados no Flask.

Para executar o build do seu frontend, utilize o comando:

npm run build

Criando o servidor web usando Flask

Sei que este post está grande, mas estamos quase terminando. 🙂

No diretório backend, crie um arquivo chamado app.py e inclua o seguinte conteúdo nele:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from flask import Flask, render_template, jsonify

app = Flask(__name__)

No código acima faço as importações necessárias e crio uma instância do Flask. Não vou me preocupar muito com configurações do Flask ou nos procedimentos para criar/utilizar um virtualenv, mas isso não deve se rum problema. O código deve funcionar da forma que está. (Caso queira, faça as alterações que achar importantes.)

Nesta aplicação que criamos, quem vai gerenciar as rotas será a propria aplicação VueJS, o Flask disponibilizará os arquivos dele e acesso à urls de API. Sendo assim, precisamos criar uma rota que capture todos os endereços utilizados na nossa aplicação. Para isso, vou utilizar o snippet “catch-all” (não é da minha autoria, mas funciona e é o exemplo mais comum que encontramos pelo Google a fora.)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    print("Path: {}".format(path))
    return render_template("vue/index.html")

A única alteração que fiz neste snippet foi utilizar a função render_template, passando o caminho do template que quero renderizar. Como no passo anterior, salvei o index.html dentro do diretório templates/vue, precisei passar o caminho “vue/index.html” para que a função retorne o template correto.

Para testar, vou adicionar outra rota, mas ela deve retornar um json e não o template (index.html).

@app.route('/api/v1/foo')
def api_foo():
    return jsonify("API V1 FOO"), 200

A rota acima vai retornar a string “API V1 FOO” com o status code 200, mas qualquer outra rota vai cair no “catch all” e quem vai gerenciar é o VueJS.

Para executar sua aplicação toda usando o Flask, basta executar o run() do Flask:

if __name__ == '__main__':
    app.run()

Lembre-se de que você precisa ter feito o build no frontend primeiro.

Espero ter ajudado.