Image for post
Image for post
Quem falou que era fácil é porque nunca usou webpack!

webpack e CommonsChunkPlugin — Dividindo seu código automaticamente

Se você vem utilizando webpack há algum tempo, já viu ou ouviu falar do CommonsChunkPlugin.

Na lista de plugins do webpack, ele está dentro da categoria de plugins de otimizações, sendo diretamente relacionado ao code splitting, ou seja:

É a técnica de dividir sua aplicação em pequenos pedaços (chunks) e carregá-los separadamente quando for necessário.

Referências da web e documentação

Se você procurar na documentação e nos exemplos por aí, normalmente você verá algo como:

var webpack = require("webpack");module.exports = {
entry: {
app: "./app.js",
vendor: ["jquery", "underscore", ...],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor”, ”vendor.bundle.js")
]
};

Com a configuração acima, webpack irá criar os seguintes arquivos finais:

  • bundle.js — Que irá conter o código da sua aplicação
  • vendor.bundle.js — Que irá conter o código da chave vendor do objeto entry, que nesse caso, estamos referenciando os módulos jquery, underscore, …. webpack irá comparar o código em ambas as chaves app e vendor e extrair todos os require()/import from que ambas as chaves tem em comum e injetar no vendor.bundle.js, deixando o bundle.js da sua chave app menor.

Seguindo a documentação de otimização do webpack (e outras referências na web), temos a seguinte abordagem:

var webpack = require("webpack");
module.exports = {
entry: { a: "./a", b: "./b" },
output: { filename: "[name].js" },
plugins: [ new webpack.optimize.CommonsChunkPlugin("init.js") ]
}

Na configuração acima, webpack irá mover os módulos comuns ao entry: { a: {}, … } e entry: {…, b: {} } para um arquivo chamado init.js, tudo isso dinamicamente.

Tudo bonito até aqui…

Tá, já vi esses exemplos por aí, mas e aí?

Se analisarmos os dois exemplos acima:

  • Opção 1 — É bem manual, chega a ser chato ter que pensar em adicionar uma lib ou arquivo na chave do webpack toda vez que eu quiser mover esse arquivo para um pedaço separado.
  • Opção 2 — É muito dinâmica, quase sem controle. Eu quero que o webpack mova meus arquivos dinamicamente, mas também quero um pouco de controle no que está sendo separado entre pedaço 1 e pedaço 2.

14/02/2017 — Edição: Na documentação do webpack 2, existe a sessão "Implicit Common Vendor Chunk", porém, nos exemplos abaixo vamos um passo além!

A mágica do CommonsChunkPlugin: Passando uma função para a chave minChunks!

Uma abordagem que você não vê por aí, e que eu venho me divertindo muito com ela, é passar uma função na chave minChunks do plugin CommonsChunkPlugin e testar qual o caminho do arquivo atual que está sendo requisitado pelos require()/import from do seu código, você pode definir qual chave utilizando a opção chunks.

Caso o caminho combine com sua expressão regular, webpack irá mover esse arquivo para um pedaço separado!

Imaginou? Não? Pera aí, deixa eu copiar e colar o código abaixo:

var webpack = require("webpack");module.exports = {
entry: {
app: "./app.js",
},
output: {
filename: “[name].bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: ({ resource }) => /node_modules/.test(resource)
}),
]
};

Com essa configuração, qualquer require()/import from dentro de todas suas chaves de entrada (nesse caso apenas app) que referenciar um caminho para node_modules, será movido para um pedaço separado chamado vendor, no final, teremos app.bundle.js e vendor.bundle.js.

E o legal é que você não precisa se limitar a apenas um CommonsChunkPlugin, você pode fazer:


plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'libs',
chunks: ['app'],
minChunks: ({ resource }) => /client\/libs/.test(resource)
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'admin',
chunks: ['app'],
minChunks: ({ resource }) => /client\/admin/.test(resource)
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'settings',
chunks: ['app'],
minChunks: ({ resource }) => /client\/settings/.test(resource)
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
chunks: ['app'],
minChunks: ({ resource }) => /node_modules/.test(resource)
}),
],

E por aí vai, conseguiu imaginar?

Isso nos dá um pequeno controle, posso até dizer que é como mixar a opção 1 (manualmente dizer quais pedaços) e opção 2 (automaticamente buscar os pedaços), e se basear no caminho do arquivo (ou dos arquivos), e mover todos eles para esse específico pedaço separado.

Não está convencido?

Dá uma olhada nesse repositório exemplo, onde estamos criando 4 chunks finais: admin.bundle.js, dashboard.bundle.js, settings.bundle.js e vendor.bundle.js

Eu também adicionei vários comentários no repositório acima, sinta-se livre para comentar ou criar uma issue!

Obrigado, webpack Team!

Meu muito obrigado ao Tobias Koppers, Sean T. Larkin e Juho Vepsäläinen pela discussão em torno dessa abordagem!

Referências:

Obrigado por ter lido até aqui, se você gostou do post, manda um 💚 e compartilha no Twitter! Valeu! 🙏🏼

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store