Vamos começar!
Demo App
Para os fins desta demonstração, definiremos uma configuração do webpack a partir do zero usando o webpack 4. Nosso aplicativo usará apenas JavaScript vanilla para que não fiquemos atolados em nenhum detalhe específico da estrutura. O código do aplicativo real será bem pequeno para que possamos focar mais no webpack.
Se você quiser acompanhar, todo o código deste artigo pode ser encontrado no GitHub. o ponto de partida é encontrado aqui, e as resultado final é encontrado aqui.
Ponto de partida
Para começar, começaremos com apenas alguns arquivos em nosso diretório de projetos. A estrutura de diretórios é assim:
webpack-demo |_ src |_ index.js |_ .gitignore |_ index.html |_ package.json |_ README.md |_ yarn.lock
o index.html
arquivo é simples e agradável, apenas um cabeçalho de página e um script
tag:
Treinamento Webpack 1 Treinamento Webpack 1
o script
tag referencia nossa ./src/index.js
arquivo, que contém apenas algumas linhas de JavaScript que produz o texto “Hello from webpack!”:
const p = document.createElement('p')p.textContent = 'Hello from webpack!'document.body.append(p)
Se você arrastar o index.html
arquivo no seu navegador, você poderá visualizar nossa página da Web simples:
Instalar dependências
Eu incluí webpack
e webpack-cli
Como devDependencies
no package.json
Arquivo.
Para instalá-los, execute:
yarn install
Execução de teste do Webpack
O Webpack 4 é configurado como uma ferramenta “zero config”, o que significa que você pode executá-lo imediatamente, sem fazer nenhuma configuração inicial. Agora, para qualquer projeto real que você vai precisa fazer algumas configurações, mas é bom que você possa pelo menos fazer uma verificação rápida de sanidade para garantir que o webpack seja capaz de executar sem ter que passar por várias etapas de configuração inicial.
Então, vamos dar uma olhada. Corre:
yarn webpack
Agora você deve ver um dist
diretório criado no diretório do projeto. E dentro dele você deve ver um main.js
arquivo, que é o nosso código minificado.
Ótimo! O Webpack parece estar funcionando.
Consulte o código de saída
Ok, agora que temos o código JavaScript em nossa dist
diretório, vamos ter o nosso index.html
referência de arquivo que. Ao invés de script
tag assim:
Vamos mudar para isso:
Agora, atualize a página no seu navegador e você ainda verá exatamente a mesma saída, somente desta vez o “Hello from webpack!” texto está sendo gerado pelo ./dist/main.js
arquivo agora.
Criar um arquivo de configuração do Webpack
Ok, agora que instalamos o webpack e passamos por um rápido exercício de verificação de integridade, vamos criar um arquivo de configuração real do webpack. Vamos criar um arquivo chamado webpack.config.js
e coloque o seguinte código dentro dele:
const path = require('path')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }}
o entry
A propriedade informa ao webpack onde nosso código fonte está localizado. É o “ponto de entrada” para o nosso aplicativo.
o output
A propriedade diz ao webpack como chamar o arquivo de saída e em qual diretório colocá-lo.
Simples o suficiente, certo?
Agora vamos criar um script npm em nosso package.json
Arquivo:
"scripts": { "build": "webpack --config=webpack.config.js"}
Agora podemos executar nosso processo de compilação com o comando yarn build
. Vá em frente e execute esse comando para verificar se você configurou as coisas corretamente. Você pode até excluir seu dist
diretório antes de executar o yarn build
comando para verificar se o diretório está sendo gerado.
Alterar o nome do arquivo de saída
Agora, apenas por diversão, vamos mudar o nome do arquivo de saída. Para fazer isso, abriremos nossa webpack.config.js
arquivo e altere o output
propriedade a partir disso:
output: { filename: 'main.js', path: path.resolve(__dirname, 'dist')}
Para isso:
output: { filename: 'tacos.js', path: path.resolve(__dirname, 'dist')}
Agora corra yarn build
novamente para gerar a saída. Você deve ver um tacos.js
arquivo em seu dist
diretório agora.
Mas espere! Também vemos o velho main.js
arquivo em nosso dist
diretório também! Não seria bom se o webpack pudesse excluir a saída desnecessária antiga toda vez que fizermos uma nova compilação?
Tem que haver um plugin para isso.
Plugins Webpack
O Webpack possui um rico ecossistema de módulos chamado “plugins“, que são bibliotecas que podem modificar e aprimorar o processo de compilação do webpack. Vamos explorar vários plugins úteis à medida que continuamos a melhorar nossa configuração do webpack durante o restante deste artigo.
CleanWebpackPlugin
Ok, voltando ao nosso problema. Seria bom se pudéssemos limpar o dist
diretório antes de cada nova compilação. Existe um plugin para isso!
Nós podemos usar o CleanWebpackPlugin para nos ajudar aqui. Primeiro, precisamos instalá-lo em nosso projeto:
yarn add --dev clean-webpack-plugin
Para usá-lo, vamos simplesmente require
o plugin em nossa webpack.config.js
e inclua-o no diretório plugins
matriz em nossa configuração:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin() ]}
Agora corra yarn build
novamente e você deve ver apenas um único arquivo de saída no seu dist
diretório. Problema resolvido!
HTMLWebpackPlugin
Outra coisa que é um pouco chata com a nossa configuração é que sempre que alteramos o output
nome do arquivo em nosso webpack.config.js
também precisamos alterar o nome do arquivo que referimos em nosso script
tag em nossa index.html
Arquivo. Não seria bom se o webpack pudesse gerenciar isso para nós?
Existe um plugin para isso! Nós podemos usar o HTMLWebpackPlugin para nos ajudar a gerenciar nosso arquivo HTML. Vamos instalá-lo em nosso projeto agora:
yarn add --dev html-webpack-plugin
Ok, agora vamos mudar nossa index.html
arquivo dentro do nosso src
diretório para que seja um irmão do index.js
Arquivo.
webpack-demo |_ src |_ index.html |_ index.js |_ .gitignore |_ package.json |_ README.md |_ yarn.lock
Também podemos excluir o script
tag em nossa index.html
arquivo, já que teremos o manipulador do webpack inserindo o apropriado script
tag para nós. Exclua essa linha para que seu index.html
o arquivo fica assim:
Webpack Training 1 Webpack Training 1
Agora vamos require
este plugin em nossa webpack.config.js
e inclua-o no diretório plugins
array em nossa configuração, como fizemos no primeiro plugin:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ]}
Nessas opções para o HtmlWebpackPlugin
, especificamos o filename
para o que gostaríamos que o arquivo de saída fosse chamado.
Nós especificamos para inject
que gostaríamos que nosso arquivo JavaScript fosse injetado no body
marca definindo o valor como true
.
E finalmente, para o template
nós fornecemos a localização do nosso index.html
arquivo no src
diretório.
Verificação de sanidade
Ok, vamos ter certeza de que tudo ainda está funcionando corretamente. Corre yarn build
e verifique se você vê dois arquivos no seu dist
diretório: index.html
e main.js
.
Se você olhar atentamente em seu index.html
arquivo, você verá o main.js
arquivo referenciado.
Agora, abra o ./dist/index.html
no navegador para verificar se a página é carregada corretamente. Se você seguiu essas etapas corretamente, sua página ainda deve estar funcionando:
Crie um servidor de desenvolvimento
Até agora, fizemos algumas boas melhorias usando o CleanWebpackPlugin
e a HtmlWebpackPlugin
. Como fizemos essas alterações, tivemos que executar manualmente o yarn build
comando a cada vez para ver novas alterações em nosso aplicativo. Também acabamos de visualizar o arquivo em nosso navegador, em vez de exibir o conteúdo exibido em um servidor em execução localmente. Vamos melhorar nosso processo criando um servidor de desenvolvimento.
Para fazer isso, usaremos webpack-dev-server
. Primeiro, precisamos instalá-lo:
yarn add --dev webpack-dev-server
Agora, vamos dividir nosso single webpack.config.js
em dois arquivos de configuração separados, um para produção e outro para desenvolvimento. Vamos chamar o arquivo para produção webpack.config.prod.js
e o arquivo para desenvolvimento webpack.config.dev.js
.
Configuração do Webpack de desenvolvimento
Aqui está o nosso arquivo de configuração de desenvolvimento:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { mode: 'development', devtool: 'inline-source-map', devServer: { contentBase: './dist', }, entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ]}
Observe que especificamos o mode
Como development
agora, e especificamos que gostaríamos de inline-source-map
para nossos arquivos JavaScript, o que significa que um mapa de origem é incluído no final de cada arquivo JavaScript. Para o nosso servidor de desenvolvimento, especificamos que nosso conteúdo será encontrado no diretório dist
diretório.
Todo o restante da configuração de desenvolvimento permaneceu o mesmo.
Configuração do Webpack de produção
Agora, aqui está o nosso arquivo de configuração de produção:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { mode: 'production', devtool: 'source-map', entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ]}
Este arquivo também se parece muito com o nosso arquivo de configuração original. Aqui nós especificamos que o mode
é production
e que gostaríamos do source-map
opção para mapas de origem, que fornece arquivos de mapas de origem separados para código minificado.
Scripts NPM de produção e desenvolvimento
Por fim, vamos adicionar mais alguns scripts npm em nosso package.json
para que possamos trabalhar com nossas configurações de webpack de desenvolvimento e produção:
"scripts": { "build": "webpack --config=webpack.config.prod.js", "build-dev": "webpack --config=webpack.config.dev.js", "start": "webpack-dev-server --config=webpack.config.dev.js --open"}
Agora, vamos experimentar cada um desses scripts.
Corre yarn build
para ver a produção construir saída. Você deve ver que o main.js
arquivo em seu dist
diretório é minificado e que possui um acompanhamento main.js.map
arquivo de mapa de origem.
Agora corra yarn build-dev
para ver o desenvolvimento criar saída. Você deve ver o main.js
arquivo em seu dist
diretório, mas agora observe que é não minificado.
Por fim, corra yarn start
para iniciar o servidor de desenvolvimento. Isso abrirá o aplicativo em http://localhost:8080/
. Não é mais necessário visualizar os arquivos diretamente, basta puxá-los para o seu navegador! Agora temos um servidor de desenvolvimento ao vivo real!
A saída que você vê ainda deve ser a mesma de sempre:
Fazendo alterações durante o desenvolvimento
Agora que temos um servidor dev funcionando, vamos experimentar fazer algumas alterações simples em nosso ./src/index.js
Arquivo. Em vez de emitir “Hello from webpack!”, Vamos alterá-lo para dizer “Hello from dev server!”.
Salve o arquivo e veja a página no servidor de desenvolvimento automaticamente recarregada e atualizada para você! Isso será um bom impulso para a produtividade do desenvolvedor.
Não se repita (SECO)
Agora que temos dois arquivos de configuração separados do webpack, um para desenvolvimento e outro para produção, você deve ter notado que temos muito código duplicado entre os dois arquivos.
Todo desenvolvedor lá fora teve o princípio DRY em suas cabeças desde o primeiro dia: não se repita. Se você estiver escrevendo o mesmo código em vários locais, pode ser uma boa ideia transformá-lo em código compartilhado que pode ser gravado em um local e depois usado em vários locais. Dessa forma, quando você precisar fazer alterações, precisará implementá-las em um só lugar.
Então, como podemos limpar a duplicação em nossos arquivos de configuração do webpack? Existe um plugin para isso!
WebpackMerge
Nós podemos usar o webpack-merge plugin para gerenciar código compartilhado no qual vários arquivos de configuração se baseiam. Para fazer isso, primeiro instalaremos o pacote:
yarn add --dev webpack-merge
Agora, criaremos um terceiro arquivo de configuração do webpack chamado webpack.config.common.js
. É aqui que manteremos nosso código compartilhado. No momento, nossos arquivos de configuração de desenvolvimento e produção compartilham o mesmo ponto de entrada, saída e plugins. Tudo o que difere entre os dois arquivos é o modo, o mapa de origem e o servidor de desenvolvimento.
Então, o conteúdo do nosso webpack.config.common.js
O arquivo será:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ]}
E agora, podemos mesclar esse objeto de configuração compartilhado em nossa configuração de desenvolvimento, como esta:
const merge = require('webpack-merge')const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, { mode: 'development', devtool: 'inline-source-map', devServer: { contentBase: './dist', },})
E podemos mesclar o objeto de configuração compartilhado em nossa configuração de produção, assim:
const merge = require('webpack-merge')const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, { mode: 'production', devtool: 'source-map',})
Veja como os dois arquivos ficam mais curtos e limpos! Bonita!
Styling Our App
As coisas estão parecendo muito boas com nossas configurações de webpack até agora. Temos um servidor dev de trabalho e dividimos nosso código em arquivos de desenvolvimento, produção e configuração compartilhada.
Vamos começar a trabalhar no nosso código de aplicativo atual agora. A página em preto e branco é um pouco chata de se ver. Vamos estilizar!
Na nossa src
diretório, vamos criar um index.css
e coloque as seguintes linhas de CSS dentro dele:
body { background: deeppink; color: white;}
Então, no nosso ./src/index.js
arquivo, vamos importar esse arquivo CSS:
import './index.css'
Agora corra yarn start
para colocar nosso servidor de desenvolvimento em execução novamente.
Ah não! Temos um erro!
ERROR in ./src/index.css 1:5Module parse failed: Unexpected token (1:5)You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders> body {| background: deeppink;| color: white; @ ./src/index.js 1:0-20
De que são esses “carregadores” de que fala?
Carregadores Webpack
Anteriormente, discutimos plugins do webpack, que permitem estender o processo de criação do webpack. Há também um ecossistema de webpack “carregadores“, que ajuda o webpack a entender e carregar diferentes tipos de arquivos. Pronto, o webpack entende como lidar com nossos arquivos JavaScript, mas ainda não sabe o que fazer com os arquivos CSS. Vamos corrigir isso.
StyleLoader e CSSLoader
Existem dois carregadores em particular que serão úteis para nós aqui: carregador de estilo e css-loader. Vamos incluí-los em nosso projeto e depois discutir como eles funcionam.
Para começar, como sempre, precisaremos instalar essas duas dependências:
yarn add --dev style-loader css-loader
Então podemos adicioná-los ao nosso webpack.config.common.js
na seção de regras do módulo, na parte inferior:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ], module: { rules: [ { test: /.css$/, use: ['style-loader', 'css-loader'] } ] }}
Esta seção define regras para o webpack para que ele saiba o que fazer com cada arquivo encontrado. o test
A propriedade é uma expressão regular que o webpack verifica no nome do arquivo. Nesse caso, queremos lidar com arquivos com um .css
extensão.
Então o use
A propriedade informa ao webpack qual carregador ou carregadores usar para manipular arquivos que correspondem aos critérios. Observe que a ordem aqui é importante!
Os carregadores Webpack são lidos da direita para a esquerda. Então primeiro o css-loader
será aplicado e, em seguida, o style-loader
vai ser aplicada.
Agora, o que esses carregadores realmente fazem por nós?
css-loader
interpreta e resolve arquivos CSS importados que você faz referência no seu JavaScript. Então, neste caso, css-loader
ajuda a fazer esta linha funcionar:
import './index.css'
Próximo, style-loader
injeta o CSS no DOM. Por padrão, style-loader
pega o CSS que encontra e o adiciona ao DOM dentro de um style
tag.
Vamos reiniciar nosso servidor de desenvolvimento, matando o processo atual (se você ainda o estiver executando) e iniciando-o novamente com yarn start
. Agora, no navegador da web, você deve ver isso em https://localhost:8080/
:
Oooh, tão colorido!
Uma observação sobre outros carregadores Webpack
Não abordaremos carregadores para outros tipos de arquivo neste artigo, mas esteja ciente de que existe um carregador para tudo o que se possa imaginar! Você pode usar carregador de arquivos ou carregador de url para carregar imagens e outros ativos. Você pode usar sass-loader para gerenciar a conversão de arquivos Sass / SCSS para CSS antes de canalizar essa saída para css-loader
e style-loader
. O Webpack também pode lidar com menos arquivos com menos carregador se essa é a sua preferência.
A moral da história é: para qualquer tipo de arquivo, existe um carregador que pode lidar com isso.
BabelLoader
Ok, de volta ao nosso aplicativo de demonstração. Até agora, escrevemos apenas algumas linhas de JavaScript. Seria bom se pudéssemos escrever nosso JavaScript usando novos recursos que ainda não são bem suportados em todos os navegadores. Babel é um compilador JavaScript que pode transformar o código ES6 + em código ES5.
E (você adivinhou), há um carregador para isso: babel-loader.
Para configurar babel-loader
, seguiremos as instruções no guia de instalação vinculado acima.
Primeiro, instalaremos nossas dependências:
yarn add --dev babel-loader @babel/core
Em seguida, adicionaremos uma nova regra à nossa matriz de regras do módulo em nossa webpack.config.common.js
Arquivo:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ], module: { rules: [ { test: /.css$/, use: ['style-loader', 'css-loader'] }, { test: /.(js|jsx)$/, exclude: /[\/]node_modules[\/]/, use: { loader: 'babel-loader', }, }, ] }}
Isso informará ao webpack que, quando encontrar .js
ou .jsx
arquivos para usar o Babel para transformar o código. Nós usamos o exclude
para garantir que Babel não tente transformar arquivos Javascript em nosso node_modules
diretório. Essas são dependências de terceiros que já deveriam ter sido cuidadas por seus criadores.
Em seguida, adicionaremos mais uma dependência para uma predefinição de Babel:
yarn add --dev @babel/preset-env
E então criaremos um .babelrc
arquivo onde podemos fazer outra configuração do Babel conforme necessário. Manteremos nosso arquivo bem simples e apenas especificaremos a predefinição de Babel que queremos usar:
{ "presets": ["@babel/preset-env"]}
E, finalmente, vamos escrever um código ES6 em nosso ./src/index.js
Arquivo:
import './index.css'const p = document.createElement('p')p.textContent = 'Hello from webpack!'document.body.appendChild(p)const p2 = document.createElement('p')const numbers1 = [1, 2, 3, 4, 5, 6]const numbers2 = [7, 8, 9, 10]const numbers3 = [...numbers1, ...numbers2]p2.textContent = numbers3.join(' ')document.body.appendChild(p2)
Este é um exemplo realmente trivial, mas estamos usando o operador de propagação aqui para concatenar duas matrizes.
Agora, se matarmos nosso processo de execução e executarmos yarn start
novamente, devemos ver isso no navegador:
Ótimo! Tudo está funcionando bem.
Estilos temporariamente ausentes
Se você desativar o cache no navegador e recarregar a página para o nosso aplicativo de demonstração, poderá observar um pequeno toque no qual a página aparece apenas com o HTML sem estilo e, em seguida, o fundo da página fica rosa e o texto fica branco como o estilos são aplicados.
Esse comportamento resulta de como style-loader
trabalho. Como acima mencionado, style-loader
pega CSS e o coloca em um style
tag no seu HTML. Por isso, há um breve período de tempo em que o style
a tag ainda não foi anexada!
Agora, isso é bom para um ambiente de desenvolvimento, mas definitivamente não queremos que esse tipo de comportamento ocorra na produção. Vamos consertar isso.
Em vez de injetar CSS em nosso HTML como style
tags, podemos usar o MiniCssExtractPlugin para gerar arquivos CSS separados para nós. Usaremos isso em nossa configuração de produção enquanto ainda estiver usando style-loader
na nossa configuração de desenvolvimento.
Primeiro, vamos instalar a dependência em nosso projeto:
yarn add --dev mini-css-extract-plugin
Agora em nossa webpack.config.common.js
Vamos remover a regra CSS, já que lidaremos com isso de maneira diferente no desenvolvimento e produção. Ficamos com isso em nossa configuração compartilhada:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ], module: { rules: [ { test: /.(js|jsx)$/, exclude: /[\/]node_modules[\/]/, use: { loader: 'babel-loader', }, }, ] }}
Agora, no nosso webpack.config.dev.js
arquivo, vamos adicionar novamente style-loader
e css-loader
que acabamos de remover de nossa configuração compartilhada:
const merge = require('webpack-merge')const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, { mode: 'development', devtool: 'inline-source-map', devServer: { contentBase: './dist', }, module: { rules: [ { test: /.css$/, use: ['style-loader', 'css-loader'] }, ] }})
E finalmente, no nosso webpack.config.prod.js
arquivo, vamos adicionar no nosso novo mini-css-extract-plugin
:
const merge = require('webpack-merge')const MiniCssExtractPlugin = require('mini-css-extract-plugin');const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, { mode: 'production', devtool: 'source-map', module: { rules: [ { test: /.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].[contenthash].css', }), ]})
Este é um pouco diferente, porque na verdade é um plugin e um carregador, por isso vai nas regras do módulo e nas seções de plugins.
Observe também que usamos colchetes no nome do arquivo para definir dinamicamente o name
ao nome do arquivo de origem original e também inclua o contenthash
, que é um hash (uma sequência alfanumérica) que representa o conteúdo do arquivo.
Agora se você correr yarn build
desta vez para gerar a produção, você deve obter uma saída em seu terminal semelhante a esta:
Observe que atualmente ele gera um arquivo CSS e o hash do conteúdo está incluído no nome do arquivo.
Tudo bem, problema resolvido! Não há mais problema quando a página é carregada em produção, pois temos os estilos incluídos como link
para um arquivo CSS real.
Rebentação de cache
Como incluímos o hash do conteúdo no arquivo CSS gerado, agora é uma boa hora para falar sobre o bloqueio de cache. Por que, você pergunta, gostaríamos que o hash de conteúdo fosse incluído em nossos nomes de arquivo? Para ajudar o navegador a entender quando um arquivo foi alterado!
Seu navegador tenta ser útil armazenando em cache os arquivos que ele já viu antes. Por exemplo, se você visitou um site e seu navegador precisou fazer o download de ativos como JavaScript, CSS ou arquivos de imagem, seu navegador pode armazenar em cache esses arquivos para que não seja necessário solicitá-los novamente no servidor.
Isso significa que, se você visitar o site novamente, seu navegador poderá usar os arquivos em cache em vez de solicitá-los novamente, para obter um tempo de carregamento da página mais rápido e uma experiência melhor.
Então, qual é o problema aqui? Imagine se tivéssemos um arquivo chamado main.js
usado em nosso aplicativo. Em seguida, um usuário visita seu aplicativo e o navegador armazena em cache os main.js
Arquivo. Agora, em algum momento posterior, você lançou um novo código para seu aplicativo. O conteúdo do main.js
arquivo foi alterado. Porém, quando esse mesmo usuário visita seu aplicativo novamente, o navegador vê que precisa de um main.js
arquivo, observa que ele possui um cache main.js
e apenas usa a versão em cache. O usuário não recebe seu novo código!
Para resolver esse problema, uma prática comum é incluir o hash do conteúdo no nome de cada arquivo. Conforme discutido anteriormente, o hash do conteúdo é uma representação em cadeia do conteúdo do arquivo. Se o conteúdo do arquivo não for alterado, o hash do conteúdo não será alterado. Mas, se o conteúdo do arquivo Faz mudar, o hash do conteúdo Ademais alterar.
Como o nome do arquivo agora será alterado quando o código for alterado, o navegador fará o download do novo arquivo, pois não terá esse nome de arquivo específico em seu cache.
Incluindo o hash de conteúdo
Para incluir o hash do conteúdo em nossos nomes de arquivo JavaScript, modificaremos apenas uma linha de código em nosso webpack.config.common.js
Arquivo. Está linha:
filename: 'main.js'
Mudará para esta linha:
filename: '[name].[contenthash].js'
Para que o arquivo inteiro fique assim:
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: "https://www.freecodecamp.org/./src/index.js", output: { filename: '[name].[contenthash].js', // this line is the only difference path: path.resolve(__dirname, 'dist') }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, template: path.resolve(__dirname, 'src', 'index.html'), }), ], module: { rules: [ { test: /.(js|jsx)$/, exclude: /[\/]node_modules[\/]/, use: { loader: 'babel-loader', }, }, ] }}
Agora se você correr yarn build
, você verá que seu JavaScript e seu CSS têm hashes de conteúdo incluídos:
Se você correr yarn build
novamente e compare sua nova saída com a saída antiga, você notará que os hashes de conteúdo são exatamente os mesmos nas duas vezes.
Mas se você editar seu ./src/index.js
arquivo de qualquer forma e, em seguida, execute yarn build
novamente, você obterá um novo hash de conteúdo porque o conteúdo foi alterado! Tente!
Minificando CSS
Por último, mas não menos importante, podemos querer reduzir o nosso CSS. Já estamos diminuindo nosso JavaScript para a compilação de produção, mas ainda não estamos diminuindo nosso CSS. Vamos fazer isso.
Podemos minimizar nosso CSS usando o método optimize-css-assets-webpack-plugin. Vamos instalar essa dependência agora:
yarn add --dev optimize-css-assets-webpack-plugin
Agora podemos adicionar isso a uma seção de otimização do nosso webpack.config.prod.js
Arquivo:
const merge = require('webpack-merge')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, { mode: 'production', devtool: 'source-map', module: { rules: [ { test: /.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].[contenthash].css', }), ], optimization: { minimizer: [ new OptimizeCssAssetsPlugin({ cssProcessorOptions: { map: { inline: false, annotation: true, }, }, }), ], },})
Agora, se corrermos yarn build
e depois confira o conteúdo da nossa dist
diretório, podemos ver que o CSS resultante é minificado. Agradável!
body{background:#ff1493;color:#fff}/*# sourceMappingURL=main.66e0d6aeae6f3c6fb895.css.map */
Mas espere! Se observarmos o arquivo JavaScript resultante, ele não será minificado! Hummm. isto foi minificado antes, então o que aconteceu aqui?
O problema é que agora estamos configurando manualmente a seção minimizador de otimização da nossa configuração do webpack. Quando essa seção não está no arquivo de configuração do webpack, o webpack usa como padrão suas próprias preferências de minimizador, o que inclui a redução do JavaScript quando o mode
está configurado para production
.
Como agora estamos substituindo esses padrões adicionando nossas preferências para reduzir os recursos CSS, também precisamos incluir explicitamente instruções sobre como queremos que o webpack reduza os recursos JavaScript.
TerserWebpackPlugin
Podemos reduzir nossos arquivos JavaScript usando o TerserWebpackPlugin. Vamos começar instalando essa dependência:
yarn add --dev terser-webpack-plugin
Então, no nosso webpack.config.prod.js
arquivo, vamos adicionar o terser-webpack-plugin
às nossas configurações do minimizador de otimização na parte inferior do arquivo:
const merge = require('webpack-merge')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')const TerserPlugin = require('terser-webpack-plugin')const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, { mode: 'production', devtool: 'source-map', module: { rules: [ { test: /.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].[contenthash].css', }), ], optimization: { minimizer: [ new OptimizeCssAssetsPlugin({ cssProcessorOptions: { map: { inline: false, annotation: true, }, }, }), new TerserPlugin({ // Use multi-process parallel running to improve the build speed // Default number of concurrent runs: os.cpus().length - 1 parallel: true, // Enable file caching cache: true, sourceMap: true, }), ], },})
Agora, se corrermos yarn build
e veja a saída no dist
No diretório, devemos ver que nossos arquivos CSS e JavaScript estão minificados. Aqui vamos nós!
Empacotando
Se você seguiu até aqui, recomendo!
Vamos revisar o que aprendemos até agora:
- O Webpack é uma ferramenta de construção para empacotamento de ativos e gerenciamento de dependências.
- O Webpack pode ser configurado por um arquivo de configuração.
- Os plug-ins modificam e ampliam o processo de criação do webpack.
- Os carregadores instruem o webpack como lidar com diferentes tipos de arquivos.
- o
clean-webpack-plugin
pode ser usado para remover artefatos de construção antigos dodist
diretório. - o
html-webpack-plugin
ajuda a gerenciar o arquivo HTML, incluindo a injeção de JavaScript no arquivo viascript
Tag. webpack-dev-server
cria um servidor de desenvolvimento para facilitar o desenvolvimento local.- É útil ter configurações separadas do webpack para desenvolvimento e produção. Você pode compartilhar e mesclar arquivos de configuração usando o
webpack-merge
plugar. - Podemos lidar com o estilo de nosso aplicativo incluindo carregadores como
css-loader
,style-loader
,sass-loader
,less-loader
, e asmini-css-extract-plugin
(que funciona como um plug-in e um carregador). - Podemos incluir nova sintaxe e recursos JavaScript usando Babel e
babel-loader
. - Podemos incluir hashes de conteúdo em nossos nomes de arquivos para ajudar a impedir o cache e gerenciar novas versões de nosso código lançado.
- Podemos reduzir nosso CSS com o
optimize-css-assets-webpack-plugin
. - Podemos reduzir nosso JavaScript com o
terser-webpack-plugin
.
Qual é o próximo?
Ao longo deste artigo, criamos uma configuração bastante respeitável do webpack. Todas essas técnicas que discutimos são padrões do setor e são comuns para uso em projetos de nível empresarial.
Mas ainda há mais! Outros tópicos avançados do webpack incluem divisão de código, carregamento lento, árvore tremendo, e mais!
Se você estiver interessado em explorar mais o webpack por conta própria, recomendo ler o site oficial guias do webpack.
Novamente, todo o código que passamos neste tutorial pode ser encontrado no GitHub. o ponto de partida é encontrado aqui, e as resultado final é encontrado aqui.
Obrigado pela leitura e feliz codificação!