Ao trabalhar com Vue, frequentemente utilizamos o vue-cli para configurar rapidamente o ambiente de desenvolvimento. Embora o vue-cli seja uma excelente ferramenta que nos permite começar a escrever código de negócio sem nos preocuparmos com configurações complexas do webpack, isso pode criar uma dependência excessiva e obscurecer a importância do webpack. Em cenários especiais, como configuração de múltiplas entradas em Vue ou otimização da velocidade de empacotamento, essa falta de compreensão pode se tornar problemática.
O código-fonte relacionado a este artigo está disponível no repositório https://github.com/WindrunnerMax/webpack-simple-environment, na branch webpack--vue-cli. Por padrão, o webpack suporta apenas arquivos js e json, então precisamos converter arquivos css, img, html, vue e outros em formato JavaScript para que o webpack possa processá-los. O foco principal ao construir um ambiente de desenvolvimento Vue é lidar com componentes de arquivo único (.vue), exigindo principalmente loaders adequados.
Configuração inicial
Vamos começar criando um ambiente webpack básico. Primeiro, inicializamos o projeto e instalamos as dependências:
$ yarn init -y
$ yarn add -D webpack webpack-cli cross-env
Podemos testar o empacotamento do webpack com configuração zero. A estrutura do diretório é:
webpack-simple
├── package.json
├── src
│ ├── index.js
│ └── calculate.js
└── yarn.lock
// src/calculate.js
export const multiply = (x, y) => x * y;
// src/index.js
import { multiply } from "./calculate";
console.log(multiply(2, 3));
Adicionamos um comando de build no package.json:
// package.json
{
// ...
"scripts": {
"build": "webpack"
},
// ...
}
Executamos npm run build e o webpack cria automaticamente uma pasta dist com o arquivo main.js:
(()=>{"use strict";console.log(6)})();
Arquivo de configuração do Webpack
Normalmente não usamos configuração zero. Criamos um arquivo webpack.config.js:
// package.json
{
// ...
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js"
},
// ...
}
const path = require("path");
module.exports = {
mode: process.env.NODE_ENV,
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
}
}
Plugin HtmlWebpackPlugin
Para processar arquivos HTML, usamos o plugin html-webpack-plugin:
$ yarn add -D html-webpack-plugin
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: process.env.NODE_ENV,
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
new HtmlWebpackPlugin({
title: "Vue Development Environment",
filename: "index.html",
template: path.resolve("./public/index.html"),
hash: true,
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
minifyCSS: true,
minifyJS: true,
},
inject: "body",
scriptLoading: "blocking"
})
]
}
Criamos o arquivo /public/index.html:
<html lang="pt-br">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>
Webpack Dev Server
Para desenvolvimento local, usamos o webpack-dev-server:
$ yarn add -D webpack-dev-server
// webpack.config.js
module.exports = {
devServer: {
hot: true,
open: true,
compress: true,
port: 8080
},
// ...
}
// package.json
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
}
Configuração básica do Vue
Instalamos o Vue e criamos nosso componente principal:
$ yarn add vue
// /src/main.js
import Vue from "vue";
new Vue({
el: "#app",
template: "<div>Exemplo Vue</div>"
})
Atualizamos a configuração do webpack para usar o compilador completo do Vue:
module.exports = {
resolve: {
alias: {
"vue$": "vue/dist/vue.esm.js"
}
},
// ...
}
Processamento de componentes .vue
Criamos um arquivo App.vue e configuramos os loaders necessários:
$ yarn add -D vue-loader vue-template-compiler css-loader vue-style-loader
// main.js
import Vue from "vue";
import App from "./App.vue";
const app = new Vue({
...App,
});
app.$mount("#app");
<!-- App.vue -->
<template>
<div class="container">{{ message }}</div>
</template>
<script>
export default {
name: "App",
data: () => ({
message: "Hello Vue"
})
}
</script>
<style scoped>
.container {
font-size: 24px;
color: #333;
}
</style>
const VueLoaderPlugin = require("vue-loader/lib/plugin")
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
use: "vue-loader",
},
{
test: /\.css$/,
use: [
"vue-style-loader",
"css-loader"
],
},
],
},
plugins: [
new VueLoaderPlugin(),
]
}
Tratamento de recursos
Para lidar com imagens e outros recursos:
$ yarn add -D url-loader file-loader
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: "url-loader",
options: {
esModule: false,
limit: 8192,
fallback: {
loader: "file-loader",
options: {
esModule: false,
name: "[name].[hash:8].[ext]",
outputPath: "assets",
}
},
}
}
]
},
],
},
}
Configuração do Babel
Para compatibilidade com navegadores antigos:
$ yarn add -D @babel/core @babel/preset-env babel-loader
$ yarn add core-js@3
// babel.config.js
module.exports = {
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3,
"modules": false
}
]
]
}
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
],
},
}
Processamento de CSS
Para usar Sass e PostCSS:
yarn add -D sass sass-loader@10.1.1 postcss postcss-loader
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
"vue-style-loader",
"css-loader",
"postcss-loader"
],
},
{
test: /\.(scss)$/,
use: [
"vue-style-loader",
"css-loader",
"postcss-loader",
"sass-loader",
]
},
],
},
}
Integração do Vue Router
Instalamos e configuramos o Vue Router:
$ yarn add vue-router
Criamos os componentes e rotas conforme necessário, integrando o sistema de roteamento.
Integração do Vuex
Instalamos e configuramos o Vuex para gerenciamento de estado:
yarn add vuex
Configuramos o store e integramos com nossos componentes.
Configuração do ESLint
Para manter o padrão de código:
$ yarn add -D eslint eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue prettier vue-eslint-parser
Configuramos os arquivos de configuração do ESLint, Prettier e EditorConfig.
Integração do TypeScript
Para adicionar suporte a TypeScript:
yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser @babel/plugin-syntax-typescript typescript vue-property-decorator vue-class-component ts-loader vuex-class
Configuramos o TypeScript com decorators e integração com Vue, incluindo arquivos de declaração e configuração do tsconfig.json.