Sabemos que aplicações desenvolvidas com frameworks às torna um pouco mais pesadas para o acesso inicial.
Hoje iremos ver algumas técnicas para amenizar isso, e tornar nossas aplicações desenvolvidas com Vue mais performáticas, trazendo uma melhor experiência para o usuário final.
Senhoras e senhores, está no ar mais um tutorial da equipe do Vila do Silício !
Nos últimos dias tive algumas dificuldades com a geração de build para produção com Vue.js, pela falta de conhecimento tínhamos comentado a parte de “production” de nosso Webpack, buildando nossa aplicação final da mesma forma que a versão de desenvolvimento(um erro grotesco). Então busquei estudar e entender um pouco mais sobre o Webpack.
O Webpack segundo sua documentação é um empacotador de módulos estáticos para aplicativos JavaScript modernos. Quando o webpack processa seu aplicativo, ele cria internamente um gráfico de dependência que mapeia todos os módulos que seu projeto precisa e gera um ou mais pacotes configuráveis.
Por padrão, quando utilizamos o Vue-cli para iniciar nossas aplicações Vue, ele já configura previamente o webpack, possibilitando-nos apenas a melhoria da performance e cache da aplicação através de algumas técnicas. O arquivo gerado pelo Vue-cli é o webpack.config.js , nele há algumas regras para guiar nosso empacotador. Na imagem abaixo mostramos como exemplo como nosso arquivo já vem configurado:

Entrada
Vamos entender um pouquinho sobre este arquivo. Para começar, nosso arquivo precisa de um ponto de entrada na qual irá indicar qual módulo o webpack deve utilizar para construir seu gráfico de dependência interno. A partir daí ele irá também verificar quais outros módulos e bibliotecas esse pronto de entrada depende(direta e indiretamente). No nosso caso, este ponto de entrada é o entry: ‘./src/main.js’.

Saída
A propriedade de saída informa ao webpack onde emitir os bundles que ele cria e como nomear esses arquivos, o padrão de arquivo de saída que o Vue-cli cria é ‘.build.js’ e a pasta para qualquer outro arquivo gerado é a ‘./dist’.

Porém como disse inicialmente, o Vue-cli já nos trás o webpack bem otimizado. Então iremos focar ao trecho que possui o process.env.NODE_ENV === ‘production’ . Neste trecho é que o empacotador Webpack faz algumas modificações para a versão final da build. Abaixo uma imagem deste trecho:

Vamos entender o que webpack faz ao buildar nossa aplicação para produção. Ele utiliza alguns plugins para a otimização da aplicação final. Dentre eles tem o UglifyJsPlugin, que faz a compressão de nossos arquivos Javascript.
Se gerarmos uma versão de build com o código atual, e versão gerada será assim:

Mas por qual motivo ele gerou 2 arquivo?
O Lazy Loading
Ao criar aplicativos com um bundler, o pacote JavaScript pode se tornar muito grande e, portanto, afetar o tempo de carregamento da página. Seria mais eficiente se pudéssemos dividir os componentes de cada rota em um bloco separado e apenas carregá-los quando a rota for visitada. Combinando o recurso de componente assíncrono do Vue e o recurso de divisão de código do webpack , é trivialmente fácil carregar componentes de rota de forma lenta.
Nosso arquivo routes.js faz isso desta forma:

O componente Card não será baixado pelo navegador ao iniciar a aplicação, e sim quando ele realmente for necessário para o funcionamento(neste caso, na rota /card).
CommonsChunkPlugin
O comonsChunkPlugin é um recurso que cria um arquivo separado(conhecido como um bloco), conssinstindo em módulos comuns compartilhados entre vários pontos de entrada. Ao separar módulos comuns de pacotes, o arquivo em partes resultantes pode ser carregado uma vez inicialmente e armazenado em cache para uso posterior.
Isso resulta em otimizações de velocidade de carregamento de págionas,pois o navegador pode servir rapidamente o código compartilhado em cache, em vez de ser forçado a carregar um pacote sempre que uma nova páginas é visitada.
No nosso caso, esse bloco irá armazenar toda a nossa pasta node_modules, que são todas as nossas dependências de nossa aplicação Vue, que normalmente ao ir para produção não será modificada, podendo ficar em cache. Para isso iremos adicionar em nosso arquivo o seguinte plugin:

Ao gerar uma nova versão ele irá adicionar em um arquivo vendor.js todas as dependências da node_module usadas no projeto. Geramos uma nova build com o comando npm run build e a nova saída será:

É possível ver que o tamanho do arquivo vendor.js é muito superior aos outros, pelo fato deste arquivo conter todas as dependências. Mas agora com a técnica de chunk ele será carregado apenas no primeiro acesso, e depois utilizado já em cache(sem a necessidade de baixa-lo novamente).
Fingerprinting(impressão digital)
Porém agora teremos que nos preocupar com o cache do navegador do cliente. Como quebramos o cache de um navegador?
Por padrão, somente quando um arquivo em cache expira, ou quando o usuário limpa manualmente o cache, o navegador solicitará o arquivo novamente a partir do servidor. O arquivo será baixado novamente se o servidor indicar que o arquivo foi alterado (caso contrário, o servidor retornará HTTP 304 Not Modified).
Para salvar uma solicitação de servidor desnecessária, podemos alterar o nome de um arquivo toda vez que seu conteúdo for alterado para forçar o navegador a baixá-lo novamente. Para isso podemos criar a “Impressão Digital” ao nome do arquivo, acrescentando um hash.
Com o plugin Common Chunks emite “chunkhash” que é atualizado se o conteúdo do arquivo for alterado. Assim, o webpack pode anexar esse hash aos nomes dos arquivos quando eles são exibidos. Faremos isso no início do nosso arquivo webpack.config.js deixando-o desta forma:

Criamos uma variável env para identificar através do process.env.NODE_ENV se estamos rodando o comando development ou production, estes comando são enviados através de nosso arquivo packge.json já pré-configurado pelo Vue-cli:

E alteramos também o filename através de um if ternário identificando se o env for de produção, para gerar o nome de nossos arquivos com o chunkhash (nossa identidade digital). O resultado após gerarmos nossa nova build é o seguinte:

É claro que se ficarmos adicionando um hash ao nome de nossa build teremos que ficar atualizando a referência do arquivo no index.html, caso contrário o navegador não irá achar o arquivo de destino, pois estará ainda com o build.js que vem por padrão.
Auto injetar arquivos de compilação
Isso seria muito trabalhoso para ser feito manualmemte , então iremos utilizar o Plugin html-webpack-plugin. Primeiro iremos instalar em nosso projeto através do comando:
npm install html-webpack-plugin --save -dev
Após a instalação é necessário importa-lo em nosso arquivo webpack.config.js :

Depois iremos adicionar o plugin na build que será gerada no modo de produção:

Ao rodar o nosso comando de build novamente nossa pasta dist irá conter agora uma cópia de nosso arquivo index principal, mas com a injeção de nossos novos scripts após a build com o hash name.

Por fim, precisaremos apenas remover o antigo arquivo de build,js de nosso novo html gerado, pois não é mais utilizado. Já os arquivos com nossa identidade digital no nome já são inseridos automaticamente.

Na imagem abaixo mostro os arquivos que são baixados numa aplicação em produção, com o gzip ativado no servidor:

Essas são algumas técnicas para otimizar o carregamento de nossas aplicações Single Page Applications desenvolvidas com Vue.js e Webpack.
Referências:
- https://vuejsdevelopers.com/2017/06/18/vue-js-boost-your-app-with-webpack/
- https://webpack.js.org/concepts/
- https://webpack.js.org/plugins/commons-chunk-plugin/
- https://github.com/webpack-contrib/uglifyjs-webpack-plugin