Search code examples
webpackcode-splittingwebpack-plugindllplugin

Webpack vendor libs not splitted into separate bundle


I am trying to separate my vendor and app packages with the autodll-webpack-plugin (v0.4.2). this package is a top level plugin over the DllPlugin of webpack and the add-asset-html-webpack-plugin for auto-ordering the imports in the index.html.

What this plugin should do is separating the vendor libraries and the app code. I could do this with the CommonsChunkPlugin from webpack, but that way the bundle is regenerated on every recompile. Which is less efficient then generating the vendor bundle once and only recompile it when a lib has been changed.


The problem

I got this plugin to "work" (it is outputting a vendor.bundle.js). The only problem here is that when I inspect the app.bundle.js with webpack-bundle-analyzer (v2.13.1). I can see that all the node_modules that are in the vendor.bundle.js are also loaded into this bundle, thus the plugin is not working correctly.

app.bundle.js


Versions

I am using:

  • webpack v4.11.0
  • babel-loader v7.1.4
  • babel-core v6.26.3
  • autodll-webpack-plugin v0.4.2

Project structure

My project has the following document structure:

App
-- build //Here are the output bundles located
-- node_modules
-- public
  -- index.html
-- src // App code
-- webpack
  -- webpack.common.js
  -- webpack.dev.js
  -- webpack.prod.js
-- package.json 

My webpack.common.js (This code is shared with the Dev & prod builds)

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AutoDllPlugin = require('autodll-webpack-plugin');

module.exports = {
  entry: {
    app: [
      'babel-polyfill',
      './src/index.js',
    ],
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, '../build'),
    publicPath: '', // Is referenced by the autodll-webpack-plugin
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        options: {
          plugins: ['react-hot-loader/babel'],
          cacheDirectory: true,
          presets: ['env', 'react'],
        },
      }
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),
    new AutoDllPlugin({
      inject: true, // will inject the DLL bundle to index.html
      debug: false,
      filename: '[name]_[hash].js',
      context: path.join(__dirname, '..'),
      path: '',
      entry: {
        vendor: [
          'react',
          'react-dom'
        ]
      },
    }),
  ],
};

According to the docs of the autodll-webpack-plugin the context key should be used for separating. So I think this is where the problem lies.

The docs describe that you should reference the folder where the webpack.config.js is, but I have 3 of them, which one do I need to reference? And my folder is called webpack and not config that you see in the docs, is .. also correct here?


Solution

  • So in the end I didn't get the DLL setup to work. After reading some more I realized that the creator of the autodll-webpack-plugin advises to use the hard-source-webpack-plugin instead, because webpack is possibly going to use as a default option this in the future.

    After reading some more I also realized that it is not advised to use the DLL plugin in production, since you have to recompile it anyways (dev build adds stuff). So you should use the hard-source-webpack-plugin for the dev build and the SplitChunksPlugin for production.

    I got these two to work quite easily:

    Webpack.dev.js

    const merge = require('webpack-merge');
    const webpack = require('webpack');
    const path = require('path');
    const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
    
    const common = require('./webpack.common.js');
    
    module.exports = merge(common, {
      mode: 'development',
      devtool: 'eval-source-map',
      devServer: {
        hot: true,
        contentBase: path.resolve(__dirname, 'build'),
        historyApiFallback: true, // Allow refreshing of the page
      },
      plugins: [
        // Enable hot reloading
        new webpack.HotModuleReplacementPlugin(),
    
        // Enable caching
        new HardSourceWebpackPlugin({
          cacheDirectory: '.cache/hard-source/[confighash]',
          configHash: function(webpackConfig) {
            return require('node-object-hash')({ sort: false }).hash(webpackConfig);
          },
          environmentHash: {
            root: process.cwd(),
            directories: [],
            files: ['package-lock.json'],
          },
          info: {
            mode: 'none',
            level: 'warn',
          },
        }),
      ],
    });
    

    webpack.prod.js

    const merge = require('webpack-merge');
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
    
    const common = require('./webpack.common.js');
    
    module.exports = merge(common, {
      mode: 'production',
      plugins: [
        // Clean the build folders
        new CleanWebpackPlugin(['build'], {
          root: process.cwd(), // Otherwise the 'webpack' folder is used
        }),
    
        //Make vendor bundle size visible
        new BundleAnalyzerPlugin({
          analyzerMode: 'static',
          openAnalyzer: false,
          reportFilename: 'stats/prod-report.html',
        }),
      ],
      optimization: {
        splitChunks: {
          chunks: 'all',
          cacheGroups: {
            vendor: {
              name: 'vendor',
              chunks: 'all',
              test: /[\\/]node_modules[\\/]/,
            },
          },
        },
        minimizer: [
          // Optimize minimization
          new UglifyJsPlugin({
            cache: true,
            parallel: true,
            uglifyOptions: {
              ecma: 6,
              mangle: true,
              toplevel: true,
            },
          }),
        ],
      },
    });
    

    I hope this helps anyone.