NodeJS(ES2015) + Heroku


Primeiro, “por que Heroku? ” A ideia na verdade é partir de algo mais simples e que todos possam utilizar, como eu creio que essa plataforma é realmente mais pratica, então ela se torna perfeita para a nossa abordagem, em termos relacionados a trabalho em si, o Heroku fica um pouco mais caro, um pouco, porém ela compensa pela sua praticidade, no fim você tem uma cloud que te atende bem, te fornece add-ons que são uteis para os seus projetos, além de ser possível obter SSL free! O que é muito bom, de toda forma Heroku é ótimo tanto para projetos mais simples como o que vamos fazer agora, como para projetos mais elaborados, projetos reais, e com isso vamos para uma outra questão, como criar uma aplicação em Nodejs com Es2015 que funcione perfeitamente com Heroku?! =]

Eu havia pesquisado diversas soluções para isso, principalmente por conta de alguns projetos que eu recebi e os quais eram construídos em NodeJs e Angular, e atualmente (22/11/2016)  se você for olhar a documentação do heroku, o Getting Starter de como buildar um projeto com Nodejs, ele até tem um repositório e instruções de como fazer, porém com uma sintaxe que não corresponde totalmente ao Es2015, e querendo ou não, JS em ES6 fica mais legível, mais prático e facilita de diversas formas no desenvolvimento da sua aplicação, tanto pela adoção do let e a sua forma comportamental em relação ao escopo, a nova forma de construção de functions, a organização das suas estruturas de classes entre outras coisas mais que contribuem para a manutenção do seu código.

Enfim, vamos ao código! Nosso projeto terá os seguintes arquivos:

.
├── app.js
├── package.json
├── Procfile
└── server.js

Para começar, vamos setar o nosso package.json e para agilizar vamos digitar o seguinte comando: npm init -y E agora vamos adicionar os módulos ao package.json, que são básicos para fazer um deploy desse projeto e rodar o npm install


 "dependencies": {
    "babel": "^6.5.2",
    "babel-cli": "^6.14.0",
    "babel-preset-es2015": "^6.13.2",
    "express": "^4.14.0"
  }

Feito isso, vamos para o nosso próximo arquivo, o app.js, com ele vamos fazer algumas mudanças em torno de sintaxe, até então, em versões mais antigas do Nodejs você fazia requisições de módulos através de requires, por exemplo:

var express = require('express')

No Es2015, a chamada dos módulos são feitos através de imports:

import express from 'express'

Então vamos ficar com o import em nosso arquivo para chamar o modulo do express:

# app.js
# Importação de módulos
import express from 'express'

Em meio a isso, uma outra mudança é a forma de composição, você até então criava uma variável app na qual recebia express e assim fazia uso das funções que derivam do express, algo semelhante a isso:

var express =  require('express')
var app = express()

O ruim dessa abordagem e que a mesma tinha que ser exportada dentro de um module.exports, na verdade um return de todos os middlawares ou functions em um bloco único, por exemplo passar app.set(”port) para poder rodar  a aplicação em produção ou em desenvolvimento, o código até então ficava assim:


var express = require('express')
var app = express()
module.export = function(){

# aqui você colocaria principalmente os seus middlewares
# e no fim retornava somente o app carregando tudo

app.set('port', (process.env.PORT || 3000));
return app
}


Agora com Es6 fica ainda mais simples:

import express from 'express'

const app = express()

app.set('port', (process.env.PORT || 3000))

export default app

Particularmente, penso que dessa forma o código fica mais legível, exatamente por ele ser simples como ele é, mas para um início, o simples de um básico bem feito reflete muito no desenvolvimento de aplicações mais elaboradas.

Outra mudança significativa e a forma de se escrever funções de request e response, você pode escrever elas utilizando arrow functions Por exemplo:

app.route(' / ').get((req, res) => res.end('Hello World'))

Fica mais simples escrever functions assim do que a próxima forma que se encontra a baixo, a leitura é mais fluida, principalmente pela versatilidade de poder nesse caso, escrever a mesma função em uma linha, ao menos isso te traz a sensação de entendimento sobre o que essa função realmente faz, coisa que fica estranho caso você tente concatenar em uma linha a mesma função em es5.


app.route(' / ').get( function(req, res){
      res.end('Hello World')
})

Tudo em es5 tem a seguinte cara:


var express = require('express')

var app = express()
module.export = function(){

app.route(' / ').get( function(req, res){
      res.end('Hello World')
})

app.set('port', (process.env.PORT || 3000));

return app
}

Agora em Es6 o nosso código fica assim:


import express from 'express'

const app = express()

app.route(' / ').get((req, res) => res.end('Hello World'))

app.set('port', (process.env.PORT || 3000))

export default app

O que vimos é o ganho de legibilidade e simplicidade, legibilidade é a palavra-chave nisso tudo, pois em termos de manutenibilidade, essas pequenas mudanças ajudam consideravelmente em projetos de grande escala, na verdade ainda é possível separar e montar uma arquitetura com pequenos módulos para facilitar a organização da nossa aplicação, pois querendo ou não, quando se tem uma aplicação muito grande, não é interessante ter por exemplo, funções de routes em um arquivo que seta os módulos básicos para o funcionamento da aplicação como um todo. Continuando …

Próximo arquivo é o server.js, na verdade é o mais simples já que compreendemos as pequenas modificações que dão um belo açúcar sintático e facilitam a leitura do nosso código, bem, primeiro vamos importar o modulo app que contém a nossa configuração para um server básico e a nossa rota principal.

import app from './app'

Depois vamos adicionar ao nosso server o protocolo de requisição http, que é um modulo nativo node que cria de fato o nosso server, e no fim os nossos imports ficam assim:

import app from "./app"
import http from "http"

Feito isso, vamos criar o nosso servidor de fato:

import app from "./app"
import http from "http"

http.createServer(app.get('port')).listen(port, ()=>{
  console.log('server is running:'+ port)
})

Só para melhorar isso tudo, vamos criar uma nova constante para port:

import app from "./app"
import http from "http"

const port = app.get('port')

http.createServer(app).listen(port, ()=>{
  console.log('server is running:'+ port)
})

Vamos a mais um arquivo .babelrc, ele e um arquivo para carregamento de plugins, no caso teremos o nosso plugin para podermos escrever em es2015:

/ * .babelrc */
{
  "presets": ["es2015"]
}

Ok, estamos quase terminando…quase kkk Agora, se você rodar o código, digitar simplesmente, ```node server````, ele vai dar o seguinte erro:

(function (exports, require, module, __filename, __dirname) { import app from "./app"
                                                              ^^^^^^
SyntaxError: Unexpected token import

Porque não funciona? Por que o node não tem todas a features de es2015 em seu core, então vamos ter que voltar ao nosso package.json e fazer uma pequena modificação ao nosso escopo de scripts, e vamos escrever o nosso start dessa forma, usando o babel-node para rodar o nosso server:


 "scripts": {
       "start": "./node_modules/.bin/babel-node server.js",
       "test": "echo \"Error: no test specified\" && exit 1"
  }

Agora se você digitar o comando npm start, ele vai levantar o server localmente e assim você verá o Hello World da nossa aplicação. Até agora nossos arquivos estão assim:


# app.js

import express from 'express';
const. app = express();
app.route('/') .get((req, res)=>res.end('Hello World'))
app.set('port', (process.env.PORT || 3000))


export default app;


# server.js


import app from "./app"
import http from "http"
const port = app.get('port')
http.createServer(app).listen(port, ()=>{
  console.log('server is running:'+ port)
})


# package.json


{
  "name": "node-heroku",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "./node_modules/.bin/babel-node server.js"
  },
  "dependencies": {
    "babel": "^6.5.2",
    "babel-cli": "^6.14.0",
    "babel-preset-es2015": "^6.13.2",
    "express": "^4.14.0"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


Pronto, agora vamos para o gran finale! O Deploy =] Vamos adicionar o Procfile em nosso repositório, e só um arquivo sem extensão chamado Procfile.


# Procfile


web: ./node modules/.bin/babel-node server.js

Esse arquivo faz com você rode o server da mesma forma que você fez no package.json, mas dessa vez ele irá inicializar nossa aplicação no heroku, é um arquivo muito importante.

Agora para upar todos os nossos arquivos vamos ter que inicializar o git, pois o heroku funciona também por git, na real é a melhor forma de upar o seu repositório e vamos fazer o básico:


git init /* para inicializar a pasta do git no repositório */

Feito isso, para não importar tudo, não custa nada adicionar um simples arquivo .gitignore para não upar node_modules para o heroku.


#  .gitignore


/node_modules

E vamos commitar tudo.

git add .
git commit -m "initial commit"

Bem, para  realizar o deploy você precisa ter uma conta no Heroku  e precisa baixar o cliente do Heroku Toolbelt Após instalar o Heroku toolbelt e ter criado a sua conta, você entrara no repositório onde está o nosso código e digitar o seguinte comando:

heroku login
Ele vai pedir a sua conta do heroku :
Enter  your Heroku credentials.
Email: igor.p.r.vieira@gmail.com
Password (typing will be hidden): 

Já devidamente autenticado, vamos para nosso próximo e último passo, criar a nossa aplicação no Heroku, você pode digitar o comando a seguir para criar uma url automaticamente ou pode criar uma url para você manualmente:


#  URL Automática


heroku create


# URL Especifica


heroku create meu-app-nodejs /*nome da minha aplicacao*/

Após ter criado o nosso app no Heroku e como já comitamos o nosso repositório e só rodar o comando para deploy pelo próprio git.

git push heroku master

Em seguida você vai ver o link para acessar a sua aplicação

No meu caso: https://my-app-nodejs.herokuapp.com/

E por fim o nosso Hello World! E é isso, foi longo, o código fonte está abaixo, qualquer dúvida deixe seu comentário, vlw, obrigado e até mais! =]

Código fonte: Github!