Beruflich Dokumente
Kultur Dokumente
NOTAS DE DOCUMENTAÇÃO
27/02/2019
Quando comecei essas notas, o webpack estava nav versão 4.29.5 e a documentação se
encontrava em http://webpackjs.org.
CONCEITOS E USO BÁSICO
Webpack é um criador de pacotes para distribuição de bibliotecas e aplicações JavaScript.
01 - ENTRY OU ENTRY POINT
Entry Point, ponto de entrada onde começar a rastrear as dependências de código para montar
o pacote de distribuição. Por padrão, usa penas um Entry Point esperado em ./src/index.js, mas
pode ser configurado para mais de um.
module.exports = {
entry: ‘./path/to/entry/file.js’
};
Quando você passa um array para entry, o webpack entende que você deseja usar múltiplas
entradas. Isso é útil quando você deseja usar múltiplos arquivos representando uma única
dependência. Mas não é muito flexível ao escalar seu arquivo de configuração.
Escolher um único entry point significa que sua biblioteca ou aplicação possui apenas um
único ponto de acesso, ou inclusão.
SINTAXE DE OBJETO
É mais trabalhoso, contudo, muito mais flexível e escalável. O que o webpack chama de
escalável é a possibilidade de modularizar e combinar módulos de configuração, permitindo
separar conceitos e funcionalidades na criação de seus pacotes.
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js',
}
};
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
O que isso faz? Estamos dizendo ao webpack que gostaríamos de 3 gráficos de dependência
separados (como o exemplo acima). Isso significa que cada propriedade do entry será um
pacote JavaScript para distribuição. Assim, na pasta ./dist/ você vai encontrar os arquivos
pageOne.js, pageTwo.js e pageThree.js compilados.
Por quê? Em um aplicativo de várias páginas, o servidor buscará um novo documento HTML
para você. A página recarrega esse novo documento e os recursos são carregados novamente.
No entanto, isso nos dá a oportunidade única de fazer várias coisas:
Como regra geral: para cada documento HTML, use exatamente um ponto de entrada.
02 - OUTPUT
Conta ao webpack o destino dos pacotes criados por ele. Por padrão, os pacotes são enviados
para a pasta ./dist no aruivo ./dist/main.js.
Orienta o Webpack sobre como criar os pacotes JavaScript para distribuição. Note que podem
existir múltiplas configurações para pontos de entrada, mas apenas um para output.
USO BÁSICO
module.exports = {
output: {
filename: 'bundle.js'
}
}
O código acima informa o nome do arquivos para o pacote gerado pelo webpack. Note que,
este cenário funciona apenas para um único ponto de entrada. Caso existam mais de um entry
point, o webpack emitirá um erro. A pasta padrão para todos os pacotes do webpack é a
pasta ./dist na raiz do projeto.
ERROR in chunk page [entry]
bundle.js
Conflict: Multiple chunks emit assets to the same filename bundle.js (chunks
dashboard and page)
MULTIPLE ENTRY POINT
Nesse caso, o webpack usa o plugin CommonsChunkPlugin para criar cada pacote com um
nome específico. Ele faz isso usando a técnica de substituição de marcações para compor o
nome de cada pacote.
module.exports = {
output: {
filename: '[name].js'
}
}
O código acima é o padrão para múltiplos pontos de entrada, criando um pacote com o mesmo
nome da entrada na pasta ./dist. Uma boa sugestão é adicionar a terminação *.min.js para
diferenciar seus pontos de entrada dos pacotes compilados.
module.exports = {
entry: {
login: './src/views/login.js',
dashboard: './src/views/dashboard.js',
page: './src/views/page.js'
},
output: {
filename: '[name].min.js'
}
}
Se quiser mudar a pasta padrão onde os pacotes javascript são gerados, basta usar a
propriedade path.
module.exports = {
entry: {
login: './src/views/login.js',
dashboard: './src/views/dashboard.js',
page: './src/views/page.js'
},
output: {
filename: '[name].min.js',
path: __dirname + '/bundle'
}
}
Existe um exemplo mais avançado no site sobre public path que eu não entendi.
https://webpack.js.org/concepts/output
03 - LOADERS
Por padrão, o Webpack trabalha apenas com arquivos JavaScript e JSON. Os Loaders são
pequenos programas que permitem ao Webpack trabalhar com outros tipos de arquivos como
HTML, CSS, SASS…
Por exemplo, podemos instalar e usar dois loaders para carregar arquivos css e transformar
TypeScript em JavaScript.
npm install --save-dev css-loader
npm install --save-dev ts-loader
USANDO LOADERS
Existem três caminhos para usar loaders, no arquivo de configuraçao webpack.config.js, usando
comandos inline em cada “import” de arquivo e via comandos CLI.
LOADERS INLINE
É possível especificar loaders numa expressão import, durante a importação de um arquivo.
Para isso, basta indicar na string do import os loaders separados por (!). Os argumentos de
configuração devem ser adicionados após (?) como uma querystring de nome=valor ou um
objeto JSON {nome=valor}.
import Styles from 'style-loader!css-loader?modules!./styles.css'
LOADERS EM CLI
Isso significa usar um loader em linhas de comando. Nesse caso, você pode seguir o exemplo
do código abaixo:
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
CARACTERÍSTICAS IMPORTANTES
• Cadeia de Loaders: Quando usar múltiplos loaders, o webpack executa o primeiro da
sequência e passa o resultado para o pŕoximo, e segue assim até o último. No fim, o
webpack espera que o resultado final seja código JavaScript.
• Full NodeJs: Assim como o Webpack, Loaders são executados pelo NodeJs, isso permite
que os loaders utilizem todo o poder dessa tecnologia.
04 - PLUGINS
São usados para realizar uma ampla quantidade de tarefas, adicionando mais funcionalidades
ao Webpack. Geralmente essas funcionalidades estão relacionadas a otimização de código,
pacotes, gerenciamento de assets (css, html) e injeção de variáveis de ambiente.
A ideia dos plugins é ir além dos loaders, adicionando mais recursos e funcionalidades. Os
plugins são códigos javascript escritos para um determinado fim. O próprio Webpack é
construído em cima de vários plugins. A base dele são vários plugins prontos para uso pelo
usuário.
ANATOMIA DE UM PLUGIN
Um plugin é uma classe com o método apply, como mostrado abaixo:
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, compilation => {
console.log('The webpack build process is starting!!!');
});
}
}
USANDO PLUGINS
Existem dois caminhos para usar plugins em Webpack, o primeiro deles é no arquivo de
configuração e o segundo como Node API.
CONFIGURAÇÃO DO WEBPACK
Nesse caso, basta passar uma lista de instâncias de plugins na propriedade plugin do objeto
exportado no arquivo de configuração. É necessário importar o plugin e adicionar a instância
dele na lista.
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader'
}
]
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
new webpack.ProgressPlugin().apply(compiler);
compiler.run(function(err, stats) {
// ...
});
05 – MODE OU MODO DE CONSTRUÇÃO
Indica o modo de otimização de um pacote para o Webpack. Você pode indicar os modos
development, production ou none. Por padrão o Webpack usa o modo production.
Em comparação com as versões anteriores, essa é muito boa. Antes, era necessário especificar
cada comportamento para os modos de desenvolvimento e produção em arquivos diferentes.
Agora, basta usar a propriedade mode para utilizar as configurações padrões de
desenvolvimento, produção ou nenhuma das duas.
module.exports = {
mode: 'production',
}
O modo de construção também pode ser modificado via linha de comando, útil para run dev e
run build.
webpack –mode=production
return config;
};
Aqui você pode encontrar uma lista de configurações que podem ser modificadas no Webpack.
https://github.com/webpack/webpack/blob/master/lib/WebpackOptionsDefaulter.js
07 – A CONFIGURAÇÃO
O webpack espera encontrar um arquivo chamado webpack.config.js na raiz de seu projeto.
var path = require('path');
module.exports = {
mode: 'development',
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js'
}
};
BROWSER COMPATIBILITY
Webpack suporta todos os navegadores baseados em ES5 (menos o IE8 e anteriores), uma vez
que o Webpack precisa de Promise para import e require.ensure(). Se você quer manter o
suporte para navegadores antigos, vai precisar de um polyfill para isso.
Em princípio, o Webpack não exige que você use um arquivo de configuração, por padrão ele
assume que seu ponto de entrada está em src/index.js e o resultado deve ficar em dist/main.js,
otimizado e pronto para produção.
Geralmente seus projetos precisam estender alguma funcionalidade, por isto você cria um
webpack.config.js na pasta raiz e o webpack automaticamente passa a usá-lo. Se , por algum
motivo, seu projeto precisar de um arquivo de configuração diferente, basta usar o comando –
config em linha de comando.
"scripts": {
"build": "webpack --config prod.config.js"
}
É comum usar módulos NodeJs para trabalhar os arquivos de configuração, criando mais
flexibilidade para seus projetos.
Existem alguns aplicativos online para criação automatica de arquivos de configuração, com
eles é possível marcar algumas opções e gerar uma configuração básica.
• https://generatewebpackconfig.netlify.com/
• https://webpack.jakoblind.no/
01 – LINGUAGENS DIFERENTES NO ARQUIVO DE
CONFIGURAÇÃO
O webpack utiliza tecnologia NodeJs, particularmente o node-interpret. Graças a ele, é possível
utilizar linguagens de programação diferentes em seu arquivo de configuração. Neste capítulo,
vamos mostrar como utilizar três das principais linguagens utilizadas no front-end de páginas
web.
TYPESCRIPT
Primeiro, precisamos instalar as dependências necessárias para utilizar TypeScript em seu
projeto.
npm install --save-dev typescript ts-node @types/node @types/webpack
# and, if using webpack-dev-server
npm install --save-dev @types/webpack-dev-server
Para que tudo corra perfeitramente, é preciso informar ao webpack para usar o TypeScript
durante sua execução. Para isso, precisamos configurar o arquivo tsconfig-for-webpack-
config.json e usá-lo no package.json.
Instalando o tsconfig-paths...
npm install --save-dev tsconfig-paths
Arquivo de configuração tsconfig-for-webpack-config.json.
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"esModuleInterop": true
}
}
COFFEESCRIPT
Da mesma forma, para o CoffeeScritp, primeiro instalamos as dependências.
npm install --save-dev coffee-script
config =
mode: 'production'
entry: './path/to/my/entry/file.js'
output:
path: path.resolve(__dirname, 'dist')
filename: 'my-first-webpack.bundle.js'
module: rules: [ {
test: /\.(js|jsx)$/
use: 'babel-loader'
} ]
plugins: [
new HtmlWebpackPlugin(template: './src/index.html')
]
module.exports = config
BABEL E JSX
Novamente, instalamos as dependências.
npm install --save-dev babel-register jsxobj babel-preset-es2015
babel.rc
{
"presets": [ "es2015" ]
}
webpack.config.js
import jsxobj from 'jsxobj';
export default (
<webpack target="web" watch mode="production">
<entry path="src/index.js" />
<resolve>
<alias {...{
react: 'preact-compat',
'react-dom': 'preact-compat'
}} />
</resolve>
<plugins>
<CustomPlugin foo="bar" />
</plugins>
</webpack>
);
Particularmente, eu não preciso de tanta coisa, bastaria apenas o Babel para usar a sintaxe
ES6 do JavaScript.
Se você passar –config-name para o webpack, ele deve construir o pacote de acordo com a
configuração especificada.
O CONTEXT
É uma string contendo o caminho absoluto para a pasta onde se encontram todos os pontos de
entrada da aplicação. Como boa prática, é recomandado utilizar o módulo path do NodeJs,
resolvendo caminhos independente do sistema operacional.
module.exports = {
//...
context: path.resolve(__dirname, 'app')
};
Por padrão, a pasta onde se encontram os pontos de entrada é a pasta raiz da aplicação. Mude
apenas quando realmente for necessário.
O PONTO DE ENTRADA
O ponto de entrada é onde sua aplicação começa. Se você passar um array contendo uma lista
de arquivos, todos eles serão compilados para execução ao mesmo tempo.
Siga sempre uma regra simples. Um único ponto de entrada é usado para SPA e múltiplos
pontos de entrada são usados para MPA (Multi Page Application).
module.exports = {
//...
entry: {
home: './home.js',
about: './about.js',
contact: './contact.js'
}
};
Se uma string ou lista de strings é passada para o ponto de entrada, todos eles serão
compilados para main.js. Se um objeto é passado, cada chave se transforma no nome do
arquivo compilado e o valor é usado como ponto de entrada para o arquivo compilado.
Usando esse mesmo mecanismo, é possível passar uma promise para o ponto de entrada,
realizando tarefas antes de determinar o ponto de entrada.
module.exports = {
//...
entry: () => new Promise((resolve) => resolve(['./demo', './demo2']))
};
Se você estiver usando a opção output.library e passar uma lista de arquivos para o entry point
[‘nome.js’, ‘nome.js’…], apenas o último arquivo vai ser exportado.
04 – OPÇÕES DE SAÍDA
O atributo output é o ponto de mais alto nível que instrui o webpack sobre como e onde devem
ser colocados os arquivos compilados, assets e qualquer outro arquivo necessário para sua
aplicação que foi carregado pelo webpack.
Output.filename
Usado apanas para um único ponto de entrada, determina o nome do pacote gerado pelo
webpack.
module.exports = {
//...
output: {
filename: 'bundle.js'
}
};
Além das opções acima, você também pode usar uma função para retonar a configuração
desejada para essa opção.
module.exports = {
//...
output: {
filename: (chunkData) => {
return chunkData.chunk.name === 'main' ? '[name].js': '[name]/[name].js';
},
}
};
Se você estiver usando o ExtractTextWebpackPlugin, use [contenthash] pois nem [hash] nem
[chunkhash] funcionam.
Dentre as muitas opções, a maioria delas me parece inútil para meu contexto de trabalho, vou
procurar ler mais sobre o assunto em artigos e blogs para ver se encontro algo interessante.
https://webpack.js.org/configuration/output
05 – MODULES
Também me pareceu inútil para os projetos com os quais eu trabalho, posso procurar mais
coisas sobre o assunto depois.
https://webpack.js.org/configuration/module
06 – RESOLVE
Resolve é o mecanismo do Webpack que ajuda a facilitar o trabalho com import ou require,
resolvendo caminhos para módulos de terceiros ou nativos do seu código. Todas as opções
desse mecanismo deve ser adicionadas no atributo resolve.
module.exports = {
//...
resolve: {
// configuration options
};
RESOLVE.ALIAS
Cria um alias apontando para alguma pasta onde os módulos se encontram. O objetivo é
facilitar o uso de import ou require. Normalmente ele é usado para criar atalhos para dentro da
pasta src/.
module.exports = {
//...
resolve: {
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
}
}
};
resolve.enforceExtension e
resolve.enforceModuleExtension
Se marcado para true, exige que todos os arquivos importados tenham uma extensão de
arquivo. Por padrão, o código import componente from ‘./componentes/componente’ importa o
arquivo componente.js.
Mas com essa opção preenchida, o webpack emite um erro, exigindo que a extensão .js seja
adicionada no final do import.
resolve.extensions
Resolve extensões automáticamente.
module.exports = {
//...
resolve: {
extensions: ['.wasm', '.mjs', '.js', '.json']
}
};
Isso significa que um import para ‘file’ deve importar um arquivo que tenha uma das extensões
indicadas em extensions.
Existem outras opções que penso serem inúteis para a maioria dos projetos, mas que podem
ser consultadas depois em https://webpack.js.org/configuration/resolve.
07 – PLUGINS
Uma lista de instâncias de plugins adicionado ao Webpack no atributo plugins.
var webpack = require('webpack');
// importing plugins that do not come by default in webpack
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var DashboardPlugin = require('webpack-dashboard/plugin');
As definições de cada plugin vão depender da documentação especifica deles. Não existe outra
opção além dessas.
08 – OTIMIZAÇÃO
Desde da versão 4, o webpack resumiu muitas otimizações com o modo de execução. Contudo,
algumas ainda continuam disponíveis para uso manual.
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
cache: true,
parallel: true,
sourceMap: true, // Must be set to true if using source-maps in
production
terserOptions: {
// https://github.com/webpack-contrib/terser-webpack-
plugin#terseroptions
}
}),
],
}
};