12
respostas

splitChunks e erro "Conflict: Multiple chunks emit assets to the same filename vendor.bundle.js"

Olá Alura!

Ao utilizar o splitChunks (em substituição ao CommonsChunkPlugin) e executar npm run build-dev, está retornando o erro:

ERROR in chunk vendor~main [initial]
vendor.bundle.js
Conflict: Multiple chunks emit assets to the same filename vendor.bundle.js (chunks 1 and 1)
Child mini-css-extract-plugin ../projeto-webpack\client\node_modules\css-loader\dist\cjs.js!../../projeto-webpack\client\css\cssqualquer.css:
    Entrypoint mini-css-extract-plugin = *
    [0] ./node_modules/css-loader/dist/cjs.js!./css/cssqualquer.css 356 bytes {0} [built]
        + 1 hidden module
Child mini-css-extract-plugin ../projeto-webpack\client\node_modules\css-loader\dist\cjs.js!../../projeto-webpack\client\node_modules\bootstrap\dist\css\bootstrap.css:
    Entrypoint mini-css-extract-plugin = *
       2 modules
  • arquivo webpack.config.js
const path = require('path');
const babiliPlugin = require('babili-webpack-plugin');

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const optimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const webpack = require('webpack');

let plugins = [];

plugins.push(new MiniCssExtractPlugin(
  {
    filename: 'styles.css'
  }
));

plugins.push(
  new webpack.ProvidePlugin({
    '$': 'jquery/dist/jquery.js',
    'jQuery': 'jquery/dist/jquery.js'
  })
);

if (process.env.NODE_ENV == 'production') {
  plugins.push(new webpack.optimize.ModuleConcatenationPlugin());

  plugins.push(new babiliPlugin());

  plugins.push(new optimizeCSSAssetsPlugin({
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
      discardComments: {
        removeAll: true 
      }
    },
    canPrint: true
 }));
}

module.exports = {
  mode: 'none',
  entry: path.resolve(__dirname, 'app-src/app.js'),
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'dist'
  },

  optimization: { // substituto do CommonsChunkPlugin
    splitChunks: {
      cacheGroups: {
        vendor: {
          filename: 'vendor.bundle.js', // bundle das bibliotecas de terceiros
          test: /[\\/]node_modules[\\/](jquery|bootstrap|reflect-metadata)[\\/]/, 
          chunks: 'all'
        }
      }
    }
  },

  module: { 
    rules: [ 
      {
        test: /\.js$/,
        exclude: /node_modules/, 
        use: {
          loader: 'babel-loader'
        }
      },
      { 
        test: /\.css$/, 
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      },
      { 
        test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'url-loader?limit=10000&mimetype=application/font-woff' 
      },
      { 
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
      },
      { 
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'file-loader' 
      },
      { 
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'url-loader?limit=10000&mimetype=image/svg+xml' 
      } 
    ]
  },

  plugins
}
  • arquivo package.json

    {
    "name": "client",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "build-dev": "webpack --config webpack.config.js",
      "build-prod": "cross-env NODE_ENV=production webpack --config webpack.config.js",
      "start": "webpack-dev-server"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
      "@babel/runtime": "^7.11.2",
      "bootstrap": "^4.5.2",
      "core-js": "^3.6.5",
      "jquery": "^3.5.1",
      "reflect-metadata": "^0.1.10"
    },
    "devDependencies": {
      "@babel/core": "^7.11.6",
      "@babel/plugin-proposal-decorators": "^7.10.5",
      "@babel/plugin-transform-runtime": "^7.11.5",
      "@babel/preset-env": "^7.11.5",
      "babel-loader": "^8.1.0",
      "babili-webpack-plugin": "^0.1.2",
      "cross-env": "^7.0.2",
      "css-loader": "^4.3.0",
      "cssnano": "^4.1.10",
      "file-loader": "^6.1.1",
      "mini-css-extract-plugin": "^1.0.0",
      "optimize-css-assets-webpack-plugin": "^5.0.4",
      "style-loader": "^2.0.0",
      "url-loader": "^4.1.1",
      "webpack": "^4.44.2",
      "webpack-cli": "^3.3.12",
      "webpack-dev-server": "^3.11.0"
    }
    }
  • arquivo cssqualquer.css

/* comentário teste */
table {
  box-shadow: 5px 5px 5px black; 
} 
  • arquivo app.js
import 'core-js'; // sanar problema com a tag <script> do index.html q n carregava

import { NegociacaoController } from './controllers/NegociacaoController.js';
import { Negociacao } from './domain/index.js';

import 'bootstrap/dist/css/bootstrap.css';
import '../css/cssqualquer.css';

import 'bootstrap/js/dist/modal';

import 'reflect-metadata/Reflect.js';

const controller = new NegociacaoController();

// ...

Aguardo, desde já obrigado.

12 respostas

Fala ai Elías, tudo bem? Nesse caso o problema pode estar na propriedade filename da configuração do output, hoje ela está assim:

filename: 'bundle.js

Repare que o nome de todos os arquivos .js gerados pelo Webpack será bundle.js.

No seu caso, você precisa que o nome seja dinâmico, sendo assim, tente mudar para:

filename: '[name]-[hash].js

Aqui poderia ser apenas name, mas, é bom também ter o hash para trabalhar com cache.

Espero ter ajudado.

Olá Matheus, tudo bem e você?

Obrigado pelo retorno. Tentei o que você falou, mas o erro continua ocorrendo...

Detalhe, se comentar a propriedade optimization (que contém o splitChunks), o erro deixa de ocorrer, porém o splitChunks é o substituto do CommonsChunkPlugin utilizado no curso, com o objetivo de separar o bundle do código do bundle de módulos de terceiros (node_modules).

Neste link (o link funciona uma única vez) tem o meu projeto (154KB) sem os node_modules dos lados client e server, se puder testar.

Aguardo teus comentários.

Atenciosamente.

Fala Eláis, tentei baixar o projeto mas está dizendo que o arquivo foi deletado.

Consegue subir novamente caso ainda esteja com o problema?

Fico no aguardo.

Olá Matheus, obrigado pelo retorno.

Sim, continuo com o problema, segue link do projeto.

Favor me retorne se conseguiu baixar.

Fala ai Elías, dei uma olhada no projeto, para resolver:

  1. Comente o filename no seu cacheGroups
  2. Define um name para identificar o seu chunck depois:
name: 'vendor',

O erro é porque só podemos definir filename quando é um chunk inicial:

Allows to override the filename when and only when it's an initial chunk

Espero ter ajudado.

Olá Matheus, obrigado pelo retorno.

Ajudou, o erro não está mais ocorrendo. Porém não está gerando os chunks da forma que o instrutor orienta.

  • Se você comentar a parte do otimization no webpack.config.js e executar npm run build-dev, na pasta dist serão gerados os arquivos bundle.js e style.js.

  • Agora, com a mudança que você propôs acima, show, não está mais ocorrendo erro, porém na pasta dist estão sendo gerados 4 arquivos: bundle.js, styles.css, 1.bundle.js e 1.styles.css.

O objetivo do instrutor seria continuar gerando apenas um arquivo CSS (styles.css) e, dividir o bundle.js em dois arquivos/bundle, um contendo apenas o código JS do programa em si, e o outro contendo os JS/módulos de terceiros (node_modules), e tendo nomes apropriados, por ex. bundle.js e vendor.bundle.js.

Você poderia me ajudar, como você faria isso?

Aguardo, atenciosamente.

Fala Elias, desculpa a demora, as coisas estão bem corridas por aqui.

Fui fazer o donwload do projeto e o link esta quebrado, está dizendo que o arquivo foi deletado, você consegue subir o projeto novamente para eu olhar com mais calma e ajustar as configurações para você?

Fico no aguardo e novamente peço desculpas pela demora, essa dúvida exige que eu pare e configure com calma o projeto.

Olá Matheus,

Entendo o teu lado, mas espero que você entenda o meu lado também, porque uma semana aguardando é um tempo considerável.Se vocês conseguissem contratar mais gente, tanto para ajudar o lado dos alunos quanto vocês instrutores, etc também.

Enfim, segue link do projeto (o download funciona apenas uma vez).

Aguardo, desde já obrigado.

Fala Elias, vamos aos ajustes:

  1. Mudar o entry para ser um objeto com vendor e app:
entry: {
    app: path.resolve(__dirname, 'app-src/app.js'), // bundle do código do app
    vendor: ['jquery', 'bootstrap', 'reflect-metadata'] // bundle das bibliotecas de terceiros
},

Mudar o cacheGroups para gerar o arquivo vendor.js:

vendor: {
          name: 'vendor',
          filename: 'vendor.js', // bundle das bibliotecas de terceiros
          test: 'vendor', // definição de quais bibliotecas dentro de node_modules ficarão separadas neste bundle
          chunks: 'initial', // tipo de otimização [consulte + detalhes na documentação https://webpack.js.org/guides/code-splitting/]
          enforce: true,
}

Instalar popper.js no projeto: npm i popper.js

Arquivo de configuração final:

const path = require('path');
const babiliPlugin = require('babili-webpack-plugin');

// const extractTextPlugin = require('extract-text-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const optimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const webpack = require('webpack');

let plugins = [];

// plugins.push(new extractTextPlugin("styles.css"));
plugins.push(new MiniCssExtractPlugin(
  {
    filename: 'styles.css'
  }
));

plugins.push(
  new webpack.ProvidePlugin({
    // disponibilizar para todos os módulos o $ (alias do jQuery) e jQuery
    '$': 'jquery/dist/jquery.js',
    'jQuery': 'jquery/dist/jquery.js'
  })
);

// plugins.push(
//   // separar as bibliotecas de terceiros no módulo vendor
//   new webpack.optimize.CommonsChunkPlugin(
//     { 
//       name: 'vendor', 
//       filename: 'vendor.bundle.js'
//     }
//   )
// );

if (process.env.NODE_ENV == 'production') {
  // diminuir a quantidade de closures durante a criação dos módulos (scope hoisting)
  plugins.push(new webpack.optimize.ModuleConcatenationPlugin());

  plugins.push(new babiliPlugin());

  plugins.push(new optimizeCSSAssetsPlugin({
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
      discardComments: {
        removeAll: true 
      }
    },
    canPrint: true
 }));
}

module.exports = {
  mode: 'none',
  entry: {
    app: path.resolve(__dirname, 'app-src/app.js'), // bundle do código do app
    vendor: ['jquery', 'bootstrap', 'reflect-metadata'] // bundle das bibliotecas de terceiros
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'dist'
  },

  optimization: { // substituto do CommonsChunkPlugin
    splitChunks: {
      cacheGroups: {
        vendor: {
          name: 'vendor',
          filename: 'vendor.js', // bundle das bibliotecas de terceiros
          test: 'vendor', // definição de quais bibliotecas dentro de node_modules ficarão separadas neste bundle
          // test: /[\\/]node_modules[\\/]/, // definição de quais bibliotecas dentro de node_modules ficarão separadas neste bundle
          chunks: 'initial', // tipo de otimização [consulte + detalhes na documentação https://webpack.js.org/guides/code-splitting/]
          enforce: true,
        }
      }
    }
  },

  module: { // permite ter varias regras de execução
    rules: [ // cada regra pode usar um módulo específico quando aplicada
      {
        test: /\.js$/,
        exclude: /node_modules/, 
        use: {
          loader: 'babel-loader'
        }
      },
      { 
        test: /\.css$/, 
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      },
      { 
        test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'url-loader?limit=10000&mimetype=application/font-woff' 
      },
      { 
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
      },
      { 
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'file-loader' 
      },
      { 
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 
        loader: 'url-loader?limit=10000&mimetype=image/svg+xml' 
      } 
    ]
  },

  plugins
}

Com isso deve gerar apenas o bundle.js, styles.css e vendor.js.

Espero ter ajudado.

Olá Matheus,

Sim, com essa configuração gerou apenas os 3 arquivos (bundle.js, styles.css, vendor.js), porém o bundle.js, que deveria conter apenas o código da aplicação, está até maior (632 KB), que o vendor.js (557 KB) , que é o arquivo que teoricamente contém as bibliotecas de terceiros. Esses tamanhos consideram o uso do comando build-dev, mas com o build-prod é equivalente (mantém a mesma proporção).

  • No vídeo do instrutor o bundle.js está no mínimo 10x menor que o vendor.js.

  • Nos dois arquivos aparece bastante código relacionado ao bootstrap. Ele não deveria estar apenas no vendor.js?

Aguardo, desde já obrigado.

Status: para uma das mensagens, quando tinha passado no mínimo uma semana sem retorno, enviei 2, 3 mensagens pra Alura no Twitter, eles disseram que avisaram o pessoal do fórum, como não tive retorno, enviei e-mail pro Paulo Silveira, aí acho que tive 2 mensagens deste tópico retornadas, mas pra essa última acima faz 2 semanas e nada. Cansei de esperar, até terminei o curso.

Só pra registrar, antes que o tópico seja fechado e não tenha mais a opção de escrever.

Fala Elías, desculpa, acabei nem reparando nessas questões de tamanho dos bundles, estranho (na teoria era para ter resolvido os problemas).

Consegue subir o projeto novamente? Se possível, sobre no Github, dai eu não preciso ficar pedindo toda hora e consigo pegar as atualizações que tu fizer no projeto.

Sobre o tempo, é bem corrido por aqui, muitas duvidas por dia para responder, dai duvidas do dia acabando indo pro dia seguinte, ai tem as diarias do dia + do dia passado e por ai vai...

A sua duvida é um pouco mais complexa, então ela eu não consigo simplesmente responder no achismo, preciso parar, testar as ideias para ver se vai dar certo, preciso reler a documentação do Webpack para aplica as configurações certas para os problema.

Se a duvida fechar, fica tranquilo, você ainda vai conseguir postar respostas e eu tambem, mas, caso não consiga, a gente cria uma nova e vamos nos falando por lá.

Vamos resolvendo os problemas e aprendendo junto aos poucos.

Abraços e novamente peço desculpas pela demora.