user3612643
user3612643

Reputation: 5772

Webpack: put every external package into its own chunk

I am currently experimenting with code splitting in Webback4.

I'd like to put every external package (from node_modules) into its own chunk. Can someone please provide me a hint how to do it?

This is how far I got so far (except from webpack.config.js)

  optimization: {
    runtimeChunk: {
      name: "runtime"
    },
    splitChunks: {
      chunks: "all",
      name(module) {
        return module.resource && module.resource.replace(/\//g, "_");
      }
    }
  }

But now, every single JS file is a separate chunk. So, I'd like to do it per package.

Ideally, the filename should be of form:

<package-name>-<version>.js

for example:

protobufjs-6.1.3.js

Help?

Bonus: could I also somehow generate content hash for the filename?

Upvotes: 4

Views: 2818

Answers (2)

Dayem Siddiqui
Dayem Siddiqui

Reputation: 215

How about this:

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  plugins: [
    new webpack.HashedModuleIdsPlugin(), // so that file hashes don't change unexpectedly
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: Infinity,
      minSize: 0,
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name(module) {
            // get the name. E.g. node_modules/packageName/not/this/part.js
            // or node_modules/packageName
            const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

            // npm package names are URL-safe, but some servers don't like @ symbols
            return `npm.${packageName.replace('@', '')}`;
          },
        },
      },
    },
  },
};

You can further explanation of this in the following article: https://medium.com/hackernoon/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758

Upvotes: 4

yotke
yotke

Reputation: 1208

Main Answer

Use node_modules folder to test each imported module and put it in it's own file:

optimization: {
    // runtimeChunk: 'single',
    splitChunks: {
        cacheGroups: {
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                name: 'vendors',
                enforce: true,
                chunks: 'all'
            }
        }
    }
}

Bonus Round

Webpack's output filename accepts a function for customization.

I'll try to demo a concept; let's build a file name like you asked: [name]-[version]-[contenthash].js

const pkgJson = require('./package.json');
const namesVersionsObject = pkgJson.dependencies.forEach(...);

output: {
  filename: (chunkData) => {
    return `[${chunkData.chunk.name}]-[${namesVersionsObject[chunkData.chunk.name]}]-[contenthash]`
  },
}

Don't copy and paste this code it won't work. It's just a POC of how to generate custom filename output. You should build an object from package JSON that looks like {name: version}:

{
    "react": "16.5.0"
    ...
}

Alternatively, you can use something like webpack-version-file-plugin to generate a JSON file that have {name: version} in it's output and use that file as your reference namesVersionsObject

Upvotes: -1

Related Questions