3. Uma primeira aplicação [nuxt.js]
3.1. Criação da aplicação
Para o nosso desenvolvimento [nuxt.js], continuaremos a utilizar o VS Code. Criámos uma pasta [dvp] vazia onde colocaremos os nossos exemplos. Em seguida, abrimos esta pasta:

Guardamos o espaço de trabalho com o nome [intro-nuxtjs] [3-5]:

Abrimos um terminal [6-7]:

Até agora, temos utilizado o gestor de pacotes JavaScript [npm]. Para variar, vamos utilizar aqui o gestor [yarn]. Tal como o [npm], este vem instalado nas versões recentes do [node.js]. Para criar uma primeira aplicação [nuxt], utilizamos o comando [yarn create nuxt-app <pasta>] [1]. O comando solicitará algumas informações sobre o projeto a ser gerado e, assim que essas informações forem fornecidas, irá gerá-lo [2]:

Em [2], foi criada uma árvore de ficheiros completa. O ficheiro [package.json] lista as bibliotecas JavaScript descarregadas para a pasta [node-modules] [4]:
{
"name": "nuxt-intro",
"version": "1.0.0",
"description": "nuxt-intro",
"author": "serge-tahe",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore ."
},
"dependencies": {
"nuxt": "^2.0.0",
"bootstrap-vue": "^2.0.0",
"bootstrap": "^4.1.3",
"@nuxtjs/axios": "^5.3.6"
},
"devDependencies": {
"@nuxtjs/eslint-config": "^1.0.1",
"@nuxtjs/eslint-module": "^1.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^6.1.0",
"eslint-plugin-nuxt": ">=0.4.2",
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-prettier": "^3.0.1",
"prettier": "^1.16.4"
}
}
Este ficheiro reflete as respostas fornecidas ao comando [create nuxt-app] para definir o projeto criado (novembro de 2019). O leitor pode ter um ficheiro [package.json] diferente:
- pode ter fornecido respostas diferentes às perguntas;
- o comando [create nuxt-app] pode ter evoluído desde que este documento foi escrito: as dependências e versões podem ter mudado;
A linha 8 do script é o comando que inicia a aplicação:

- em [4], vemos que a aplicação está disponível no URL [localhost:3000];
- em [5-6], vemos que a aplicação gera um servidor [6] e um cliente (desse servidor) [5];
Vamos solicitar a URL [http://localhost:3000/] num navegador:

3.2. Descrição da estrutura de diretórios de uma aplicação [nuxt]
Vamos ver a estrutura de diretórios da aplicação criada:

A função das pastas é a seguinte:
assets | recursos da aplicação não compilados (imagens, etc.); |
estático | os ficheiros nesta pasta estarão disponíveis na raiz da aplicação. Colocamos nesta pasta os ficheiros que precisam de ser encontrados na raiz da aplicação, como o ficheiro [robots.txt] destinado aos motores de busca; |
componentes | os componentes [view] da aplicação utilizados em [layouts] e [pages]; |
layouts | os componentes [Vue] da aplicação utilizados para definir o layout das [páginas]; |
páginas | os componentes [Vue] exibidos pelas várias rotas da aplicação. Estes podem ser chamados de vistas da aplicação. As páginas desempenham um papel especial no [Nuxt]: as rotas são criadas dinamicamente com base na estrutura de diretórios encontrada na pasta [páginas]; |
middleware | scripts executados sempre que uma rota muda. Permitem-lhe controlar estas rotas; |
plugins | tem um nome enganador. Pode conter plugins, bem como scripts padrão. Os scripts encontrados nesta pasta são executados quando a aplicação é iniciada; |
store | se contiver um script [index.js], então este script define uma instância do armazenamento [Vuex]; |
Se uma pasta estiver vazia, pode ser removida da estrutura de diretórios. Acima, as pastas [assets, static, middleware, plugins, store] podem ser removidas [2].
3.3. O ficheiro de configuração [nuxt.config]
A execução da aplicação é controlada pelo seguinte ficheiro [nuxt.config.js]:
export default {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: process.env.npm_package_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',
name: 'description',
content: process.env.npm_package_description || ''
}
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [],
/*
** Plugins to load before mounting the App
*/
plugins: [],
/*
** Nuxt.js dev-modules
*/
buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module
'@nuxtjs/eslint-module'
],
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://bootstrap-vue.js.org
'bootstrap-vue/nuxt',
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios'
],
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {},
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
extend(config, ctx) {}
}
}
- linha 2: o tipo de aplicação gerada:
- [universal]: aplicação cliente/servidor. Quando a aplicação é carregada inicialmente, bem como a cada atualização da página no navegador, o servidor é solicitado a entregar a página;
- [sap]: tipo [Aplicação de Página Única]: um servidor entrega inicialmente toda a aplicação. Depois disso, o cliente opera de forma independente, mesmo quando uma página é atualizada no navegador;
- Linhas 6–18: definem o cabeçalho HTML `<head>` para as várias páginas da aplicação:
- linha 7: a tag <title> para o título da página;
- linhas 8–16: as tags <meta>;
- linha 17: as tags <link>
Na aplicação gerada, a tag <head> é a seguinte (código-fonte da página apresentada no navegador):
<title>nuxt-intro</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="nuxt-intro">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="preload" href="/_nuxt/runtime.js" as="script">
<link rel="preload" href="/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/_nuxt/app.js" as="script">
Agora, vamos modificar o ficheiro [nuxt.config] da seguinte forma:
head: {
title: 'Introduction à [nuxt.js]',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',
name: 'description',
content: 'ssr routing loading asyncdata middleware plugins store'
}
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
},
Quando voltamos a executar a aplicação, a tag <head> mudou para o seguinte (código-fonte da página apresentada no navegador):
<head >
<title>Introduction à [nuxt.js]</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="preload" href="/_nuxt/runtime.js" as="script">
<link rel="preload" href="/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/_nuxt/app.js" as="script">
Voltemos ao ficheiro [nuxt.config]:
export default {
mode: 'universal',
/*
** Headers of the page
*/
head: {
...
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [],
/*
** Plugins to load before mounting the App
*/
plugins: [],
/*
** Nuxt.js dev-modules
*/
buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module
'@nuxtjs/eslint-module'
],
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://bootstrap-vue.js.org
'bootstrap-vue/nuxt',
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios'
],
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {},
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
extend(config, ctx) {}
}
}
- linha 12: entre cada rota no cliente [nuxt], aparece uma barra de carregamento se a mudança de rota demorar algum tempo. A propriedade [loading] permite configurar esta barra de carregamento; aqui, a cor da barra;
- linha 16: os ficheiros [css] globais. Estes serão automaticamente incluídos em todas as páginas da aplicação;
- linhas 24–27: os módulos JavaScript necessários para compilar a aplicação;
- linhas 31–36: os módulos JavaScript utilizados pela aplicação;
- linha 41: configuração da biblioteca [axios] quando esta tiver sido selecionada pelo utilizador para interações HTTP com servidores de terceiros;
- linhas 45–50: configuração de compilação do projeto;
Pode adicionar outras chaves ao ficheiro de configuração. Em particular, pode configurar a porta do serviço (3000 por predefinição) e a raiz do projeto (por predefinição, a pasta raiz do projeto). É isso que vamos fazer agora, adicionando as seguintes chaves:
// source code directory
srcDir: '.',
router: {
// URL root of application pages
base: '/nuxt-intro/'
},
// server
server: {
// service port - default 3000
port: 81,
// network addresses listened to - default localhost=127.0.0.1
host: '0.0.0.0'
}
- linha 2: onde encontrar o código-fonte do projeto. Ele está localizado aqui no diretório atual, ou seja, no mesmo nível do ficheiro [nuxt.config.js]. Este é o valor padrão;
- linhas 8–13: configure o servidor (tenha em mente que uma aplicação [nuxt] do tipo [universal] está instalada tanto no servidor como no navegador do cliente);
- linha 10: as páginas da aplicação serão servidas na porta 81 do servidor;
- linha 12: por predefinição [localhost] (endereço de rede 127.0.0.1). Uma máquina pode ter vários endereços de rede se pertencer a várias redes. O endereço 0.0.0.0 indica que o servidor web escuta em todos os endereços de rede da máquina;
- linhas 3–6: configure o router da aplicação [nuxt];
- linha 5: as páginas da aplicação estarão disponíveis no URL [http://localhost:81/nuxt-intro/];
Vamos adicionar estas linhas ao ficheiro [nuxt.config.js] e, em seguida, executar o projeto (script npm dev). O resultado é o seguinte:

- [1] é o endereço da máquina numa rede pública;
- em [2], a porta do serviço;
- em [3], a URL raiz da aplicação;
3.4. A pasta [layouts]

A pasta [layouts] destina-se a componentes de layout. Por predefinição, é utilizado o componente denominado [default.vue]. Neste projeto, é o seguinte:
<template>
<div>
<nuxt />
</div>
</template>
<style>
html {
font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, 'Helvetica Neue', Arial, sans-serif;
font-size: 16px;
word-spacing: 1px;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: border-box;
margin: 0;
}
.button--green {
display: inline-block;
border-radius: 4px;
border: 1px solid #3b8070;
color: #3b8070;
text-decoration: none;
padding: 10px 30px;
}
.button--green:hover {
color: #fff;
background-color: #3b8070;
}
.button--grey {
display: inline-block;
border-radius: 4px;
border: 1px solid #35495e;
color: #35495e;
text-decoration: none;
padding: 10px 30px;
margin-left: 15px;
}
.button--grey:hover {
color: #fff;
background-color: #35495e;
}
</style>
Comentários
- linhas 1-5: o [template] do componente;
- linha 3: a tag <nuxt /> designa a página de roteamento atual;
- linhas 7–55: o estilo incorporado pelo componente de layout. Uma vez que este componente contém a página de roteamento atual, este estilo será aplicado a todas as páginas roteadas na aplicação;
Podemos ver que o objetivo principal da página [default.vue] aqui é aplicar um estilo às páginas roteadas.
3.5. A pasta [pages]

A pasta [pages] contém as visualizações encaminhadas, que são o que o utilizador vê. A página [index.vue] é a página inicial da aplicação. Com o [nuxt.js], não existe um ficheiro de encaminhamento. As rotas são determinadas com base na estrutura da pasta [pages]. Aqui, a presença de um ficheiro [index.vue] cria automaticamente uma rota chamada [index] com um caminho de [/index], que é encurtado para [/] uma vez que se trata da página inicial. Assim, é criada a seguinte rota:
O ficheiro [index.vue] é o seguinte:
<template>
<div class="container">
<div>
<logo />
<h1 class="title">
nuxt-intro
</h1>
<h2 class="subtitle">
nuxt-intro
</h2>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" class="button--green">
Documentation
</a>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
class="button--grey"
>
GitHub
</a>
</div>
</div>
</div>
</template>
<script>
import Logo from '~/components/Logo.vue'
export default {
components: {
Logo
}
}
</script>
<style>
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
O [template] nas linhas 1–25 apresenta a seguinte visualização:

A imagem [1] é gerada pela linha 4 do [template]. Podemos ver que a página utiliza um componente chamado [logo]. Este está definido nas linhas 27–35 do script da página. Na linha 28, a notação [~] refere-se à raiz do projeto.
3.6. O componente [Logo]

O componente [Logo.vue] é o seguinte:
<template>
<div class="VueToNuxtLogo">
<div class="Triangle Triangle--two" />
<div class="Triangle Triangle--one" />
<div class="Triangle Triangle--three" />
<div class="Triangle Triangle--four" />
</div>
</template>
<style>
.VueToNuxtLogo {
display: inline-block;
animation: turn 2s linear forwards 1s;
transform: rotateX(180deg);
position: relative;
overflow: hidden;
height: 180px;
width: 245px;
}
.Triangle {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
}
.Triangle--one {
border-left: 105px solid transparent;
border-right: 105px solid transparent;
border-bottom: 180px solid #41b883;
}
.Triangle--two {
top: 30px;
left: 35px;
animation: goright 0.5s linear forwards 3.5s;
border-left: 87.5px solid transparent;
border-right: 87.5px solid transparent;
border-bottom: 150px solid #3b8070;
}
.Triangle--three {
top: 60px;
left: 35px;
animation: goright 0.5s linear forwards 3.5s;
border-left: 70px solid transparent;
border-right: 70px solid transparent;
border-bottom: 120px solid #35495e;
}
.Triangle--four {
top: 120px;
left: 70px;
animation: godown 0.5s linear forwards 3s;
border-left: 35px solid transparent;
border-right: 35px solid transparent;
border-bottom: 60px solid #fff;
}
@keyframes turn {
100% {
transform: rotateX(0deg);
}
}
@keyframes godown {
100% {
top: 180px;
}
}
@keyframes goright {
100% {
left: 70px;
}
}
</style>
Este componente consiste principalmente em estilos e animações para criar uma imagem animada.
3.7. Vue DevTools
[Vue DevTools] é a extensão do navegador que permite inspecionar objetos [nuxt.js] e [vue.js] no navegador. Já a utilizámos no capítulo sobre [vue.js]. Vamos examinar o que esta ferramenta encontra quando a página inicial da nossa aplicação é apresentada:

- em [1], o componente [PagesIndex] refere-se à página [pages/index.vue];
- em [2] vemos que este componente tem uma propriedade [$route], que é a rota que conduziu à página [index];
Como exercício simples, vamos exibir esta rota na consola.
3.8. Modificar a página inicial
Vamos modificar o ficheiro [index.vue]. Na configuração do nosso projeto, instalámos duas dependências:
- [eslint]: que verifica a sintaxe dos ficheiros JavaScript e dos componentes Vue. Se a extensão [ESLint] para o VSCode tiver sido instalada, esta sintaxe é verificada à medida que escreve, e os erros são imediatamente assinalados;
- [prettier]: que formata o código JavaScript de forma padronizada;
Estas dependências estão listadas no ficheiro [package.json]:
"devDependencies": {
"@nuxtjs/eslint-config": "^1.0.1",
"@nuxtjs/eslint-module": "^1.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^6.1.0",
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-nuxt": ">=0.4.2",
"eslint-plugin-prettier": "^3.0.1",
"prettier": "^1.16.4"
}
Reparei (em novembro de 2019) que, ao instalar através do comando [yarn create nuxt-app], as ferramentas [eslint, prettier] não funcionam enquanto se escreve. Os erros só são reportados durante a compilação. Após alguma pesquisa, encontrei uma configuração que funciona:

Crie uma pasta [.vscode] na raiz do projeto e coloque o seguinte ficheiro [settings.json] dentro dela:
{
"eslint.validate": [
{
"language": "vue",
"autoFix": true
},
{
"language": "javascript",
"autoFix": true
}
],
"eslint.autoFixOnSave": true,
"editor.formatOnSave": false
}
- linhas 2–11: especificam que, quando o [eslint] validar ficheiros .vue e .js, deve corrigir todos os erros que conseguir;
- linha 12: quando um ficheiro é guardado, o [eslint] deve corrigir todos os erros que conseguir;
- linha 13: desativa a formatação padrão no VSCode ao guardar. O [prettier] tratará disso;
Com esta configuração:
- os erros de sintaxe ou formatação são assinalados assim que o texto é digitado;
- os erros de formatação são corrigidos automaticamente quando o ficheiro é guardado;
A biblioteca [prettier] é configurada pelo ficheiro [.prettierrc]:

Por predefinição, este ficheiro tem o seguinte conteúdo:
{
"semi": false,
"arrowParens": "always",
"singleQuote": true
}
- linha 1: sem ponto e vírgula no final das instruções;
- linha 2: se uma função seta tiver um único parâmetro, este é colocado entre parênteses;
- linha 3: as cadeias de caracteres são colocadas entre aspas simples (não entre aspas duplas);
Adicionamos as duas regras seguintes:
{
"semi": false,
"arrowParens": "always",
"singleQuote": true,
"printWidth": 120,
"endOfLine": "auto"
}
- Linha 5: A linha de código pode ter até 120 caracteres;
- linha 6: o caractere de fim de linha pode ser CRLF (Windows) ou LF (Unix);
Por fim, o ficheiro [package.json] é modificado da seguinte forma:
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"lintfix": "eslint --fix --ext .js,.vue --ignore-path .gitignore ."
},
- Linha 7: Adicionamos o comando [lintfix], que é idêntico ao comando [lint] da linha 6, exceto pelo facto de incluir o parâmetro [--fix]. O comando [lint] verifica a sintaxe e a formatação de todos os ficheiros do projeto e reporta quaisquer erros. O [lintfix] faz o mesmo, exceto que quaisquer problemas de formatação que possam ser corrigidos serão resolvidos automaticamente. O [lintfix] é o comando a utilizar se a compilação falhar devido a problemas de formatação dos ficheiros;
Feito isso, modificamos o ficheiro [index.vue] da seguinte forma:

<script>
/* eslint-disable no-console */
import Logo from '~/components/Logo.vue'
export default {
components: {
Logo
},
// cycle de vie
created() {
console.log('created, route=', this.$route)
}
}
</script>
- linhas 10–12: adicionamos a função [created], que é executada automaticamente quando o componente é criado;
- linha 11: exibimos a rota atual;
- linha 2: um comentário destinado ao [eslint]. Sem este comentário, o [eslint] reporta um erro na linha 11: não permite instruções [console] em funções de ciclo de vida. O [eslint] é configurável. Manteremos a sua configuração padrão e utilizaremos comentários como o da linha 2 para desativar uma regra específica do [eslint]. Utilizaremos dois tipos de comentários:
- /* desativar regra [eslint] */: desativa uma regra para todo o ficheiro;
- // desativar regra [eslint]: desativa uma regra para a linha seguinte;
À medida que escreve, os erros são assinalados e está disponível uma funcionalidade [Quick Fix]:

Executar o projeto:

- em [1], o separador [View] das ferramentas de programador do navegador (F12);
- em [2] e [3], a visualização da rota;
Porquê duas vistas em vez de apenas uma?
Uma aplicação [Nuxt] é composta por dois componentes, um servidor e um cliente:
- o servidor fornece as páginas da aplicação quando esta é iniciada e, posteriormente, sempre que uma página é atualizada no navegador (F5) ou o utilizador introduz manualmente o URL da aplicação;
- Cada página servida pelo navegador contém a página solicitada, bem como o código JavaScript para toda a aplicação, que é então executado no navegador. Este é o cliente. Desde que não haja atualização da página no navegador, a aplicação funciona como uma aplicação Vue clássica no modo [SPA] (Single Page Application). Assim que o utilizador aciona manualmente uma atualização da página, a página é solicitada ao servidor e voltamos ao passo 1 anterior.
O que é preciso compreender é que estas são as mesmas páginas da pasta [pages] que são servidas tanto pelo servidor como pelo cliente. Por esta razão, os programadores do [nuxt] chamam a este tipo de página uma página isomórfica. As mesmas páginas [.vue] podem ser interpretadas tanto pelo cliente como pelo servidor. Tomemos o exemplo da página [index]:
<template>
<div class="container">
<div>
<logo />
<h1 class="title">
nuxt-intro
</h1>
<h2 class="subtitle">
nuxt-intro
</h2>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" class="button--green">
Documentation
</a>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
class="button--grey"
>
GitHub
</a>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable no-console */
import Logo from '~/components/Logo.vue'
export default {
components: {
Logo
},
// cycle de vie
created() {
console.log('created, route=', this.$route)
}
}
</script>
Uma vez que esta é a página inicial, é servida pelo servidor quando a aplicação é iniciada. A página no servidor também tem um ciclo de vida, idêntico ao de uma página clássica [Vue], com exceção das funções [beforeMount, mounted], que não existem no lado do servidor. A função [created] é executada, o que explica o primeiro registo. Isto significa, a propósito, que o servidor é capaz de executar scripts JavaScript. Aqui e, em geral, este servidor é um servidor [node.js]. Assim que a página é criada no servidor, chega ao navegador, onde passa novamente pelo ciclo de vida. A função [created] é executada uma segunda vez, o que produz o segundo registo.
A arquitetura de uma aplicação [nuxt] poderia ser a seguinte:

- [1]: o navegador que hospeda a aplicação [nuxt] depois de esta ter sido carregada no navegador. É a isto que chamamos o cliente [nuxt];
- [3]: o servidor que hospeda inicialmente a aplicação [nuxt]. É carregada no navegador [1] quando a aplicação é iniciada e sempre que o utilizador atualiza a página atual do navegador ou introduz manualmente um URL da aplicação. É aqui que reside a diferença de funcionamento em comparação com uma aplicação Vue clássica. Com uma aplicação Vue clássica, uma vez carregada no navegador, o servidor nunca mais era chamado. Outra diferença importante que ainda não vimos é que o servidor de uma aplicação Vue é um servidor estático, incapaz de interpretar páginas [.vue], enquanto o servidor de uma aplicação Nuxt [universal] é um servidor JavaScript. Antes de enviar uma página para o navegador, o servidor pode executar scripts e, por exemplo, buscar dados do servidor [2];
- [2]: é o servidor que fornece dados tanto ao cliente [nuxt] [1] como ao servidor [nuxt] [3];
No diagrama acima, podemos distinguir três subsistemas cliente/servidor:
- [1, 3]: hospeda a aplicação [nuxt]. [3] fornece-a quando a aplicação é iniciada com a página inicial e sempre que o utilizador solicita manualmente uma página. [1] hospeda a aplicação [nuxt] recebida de [3], que passa a operar no modo [SAP] enquanto as páginas não forem solicitadas manualmente a partir de [3];
- [1, 2]: No modo [SAP], o cliente [nuxt] recupera dados externos de um ou mais servidores;
- [3, 2]: ao gerar a página solicitada pelo utilizador, o servidor [3] também pode recuperar dados externos de um ou mais servidores;
É, portanto, o servidor [3] que distingue uma aplicação [Nuxt] de uma aplicação [Vue]. Este servidor é chamado sempre que o utilizador solicita manualmente uma página. Ele processa as mesmas páginas [.vue] que o cliente [Vue] [1]. Trata-se de um servidor JavaScript capaz de executar os scripts presentes na página. Isto pode, por exemplo, alterar a forma como a página inicial é gerada utilizando dados externos: enquanto uma aplicação [vue] obtém necessariamente estes dados a partir do cliente [1], aqui podem ser obtidos pelo servidor [3] antes de a página ser enviada para o cliente. A página inicial torna-se assim significativa e pode ajudar a melhorar o SEO da aplicação.
Nota: No modo de desenvolvimento, as três entidades [1, 2, 3] encontram-se frequentemente na mesma máquina. Será este o caso aqui para todos os nossos exemplos.
3.9. Mover o código-fonte da aplicação para uma pasta separada
A seguir, iremos criar várias aplicações [nuxt] na mesma pasta [dvp]. Isto porque a pasta de dependências [node_modules] gerada para cada projeto [nuxt] pode ter vários centenas de megabytes. Iremos criar várias pastas [nuxt-00, nuxt-01, ...] dentro da pasta [dvp] para armazenar o código-fonte dos exemplos a serem testados. Em seguida, utilizaremos o ficheiro de configuração [nuxt-config.js] para especificar a localização do código-fonte do projeto [dvp], que continuará a ser o único projeto [nuxt] neste tutorial.
Movemos o código-fonte da aplicação inicialmente gerada pelo comando [yarn create nuxt-app] para uma pasta [nuxt-00]:

- em [2], movemos as pastas [components, layouts, pages] para uma pasta [nuxt-00];
- Em [3], precisamos de modificar o ficheiro [nuxt.config.js];
Modificamos o ficheiro [nuxt.config.js] da seguinte forma:
export default {
mode: 'universal',
/*
** Headers of the page
*/
...
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
extend(config, ctx) {}
},
// source code directory
srcDir: 'nuxt-00',
// router
router: {
// application URL root
base: '/nuxt-00/'
},
// server
server: {
// service port, default 3000
port: 81,
// network addresses listened to, default localhost: 127.0.0.1
// 0.0.0.0 = all the machine's network addresses
host: '0.0.0.0'
}
}
O ficheiro é modificado em dois locais:
- linha 17: especificamos que o código-fonte do projeto [dvp] está localizado na pasta [nuxt-00];
- linha 21: especificamos que a URL raiz da aplicação é agora [/nuxt-00/]. Esta alteração não era obrigatória. Poderíamos ter omitido esta propriedade, caso em que a raiz das URLs seria [/]. Aqui, isto irá ajudar-nos a lembrar que o código-fonte que está a ser executado é da pasta [nuxt-00];
Depois de feito isto, o projeto [dvp] é executado como antes:

3.10. Implantação da aplicação [nuxt-00]
Vamos executar a aplicação [nuxt-00] num ambiente diferente do ambiente integrado do VSCode.
Primeiro, compilamos a aplicação:

- em [3], o resultado da compilação do cliente. Este será executado pelo navegador;
- em [4], o resultado da compilação do servidor. Este será executado pelo servidor [node.js];
O resultado da compilação é colocado na pasta [.nuxt]:

Copiamos as pastas [.nuxt, node_modules] e os ficheiros [package.json, nuxt.config.js] para uma pasta separada:

O ficheiro [package.json] é simplificado da seguinte forma:
{
"scripts": {
"start": "nuxt start"
}
}
- Mantemos apenas o script [start], que executa a versão compilada do projeto;
O ficheiro [nuxt.config.js] é simplificado da seguinte forma:
export default {
// router
router: {
// application URL root
base: '/nuxt-00/'
},
// server
server: {
// service port, default 3000
port: 81,
// network addresses listened to, default localhost: 127.0.0.1
// 0.0.0.0 = all the machine's network addresses
host: '0.0.0.0'
}
}
- linha 5: define o URL base da aplicação compilada;
- linhas 8–14: definem a porta do serviço e os endereços de rede a monitorizar;
Depois de fazer isto, abra um terminal Laragon e navegue até à pasta que contém a versão compilada do projeto. Pode abrir qualquer tipo de terminal, mas o executável [npm] deve estar no PATH do terminal. É o que acontece no terminal Laragon.
Depois de fazer isso, digite o comando [npm run start]:

Em [3], vemos que um servidor foi iniciado e está a escutar na URL [http://192.168.1.128:81/nuxt-00/]. Agora, vamos aceder a esta URL utilizando um navegador [4]. Vemos o mesmo resultado que antes. No terminal, foram gravados registos [5]. Este é o registo colocado no método [created] da página [index.vue], que foi executado pelo servidor [node.js].

No lado do navegador [6], também vemos o registo do método [created] da página [index.vue], mas desta vez executado pelo cliente.
3.11. Configurar um servidor seguro
Acima, o URL da aplicação é [http://192.168.1.128/nuxt-00/]. Gostaríamos que fosse [https://192.168.1.128/nuxt-00/]. Por isso, precisamos de configurar um servidor seguro. Eis como o fazer.
Nota: Este método foi retirado do artigo [https://stackoverflow.com/questions/56966137/how-to-run-nuxt-npm-run-dev-with-https-in-localhost].
Primeiro, criamos uma chave privada e uma chave pública utilizando o [openssl]. O [openssl] é normalmente instalado juntamente com o servidor Laragon. Como resultado, este comando está disponível em qualquer terminal Laragon. Por isso, vamos abrir um terminal Laragon e navegar até à pasta da aplicação implementada:


- em [2], digite o comando [openssl genrsa 2048 > server.key];
- em [3], é criado um ficheiro [server.key];
- em [4], digite o comando [openssl req -new -x509 -nodes -sha256 -days 365 -key server.key -out server.crt];
- em [5], é criado um ficheiro chamado [server.crt];
Estes dois ficheiros constituem um certificado autoassinado. A maioria dos navegadores só os aceita após aprovação pelo utilizador que solicitou a página.
Os ficheiros [server.key, server.crt] devem agora ser utilizados pela aplicação web. Para tal, o ficheiro [nuxt.config.js] deve ser modificado da seguinte forma:
import path from 'path'
import fs from 'fs'
export default {
// router
router: {
// application URL root
base: '/nuxt-00/'
},
// server
server: {
// service port, default 3000
port: 81,
// network addresses listened to, default localhost: 127.0.0.1
// 0.0.0.0 = all the machine's network addresses
host: '0.0.0.0',
// self-signed certificate
https: {
key: fs.readFileSync(path.resolve(__dirname, 'server.key')),
cert: fs.readFileSync(path.resolve(__dirname, 'server.crt'))
}
}
}
As linhas 18–21 implementam o protocolo [https].
Agora vamos executar a aplicação novamente:

3.12. Fim do primeiro exemplo
O primeiro exemplo está agora concluído. Ele ensinou-nos muitos conceitos [nuxt]. Vamos agora desenvolver outros exemplos que colocaremos nas pastas [nuxt-01, nuxt-02, ...]. Uma vez que estes exemplos irão utilizar um ficheiro [nuxt.config.js] diferente, iremos guardar o ficheiro [nuxt.config.js] utilizado para executar cada um deles nas respetivas pastas:
