3

What's the best way to automate the generation of (or even manually figure out) the script tags to use for an entry point in a multi-entry webpack setup?

I'm setting up an MVC application to use webpack for an enormous number of javascript dependency libraries. Since the MVC app loads a new page for each route, I have dozens of entry points, each with its own entry script.

I'm using code splitting and hash-naming (for cache-busting).

Since webpack is working out the dependency tree for each entry point, it seems to be doing a great job of breaking out the code into bundles for reuse. Here's my config (minus the code at the top and the plugins):

module.exports = {
    mode: "development",
    entry: {
        products_index: './Scripts/app/pages/Products/index.js',
        users_index: './Scripts/app/pages/Users/index.js',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash:8].js',
    },    
    node: {
        fs: 'empty',
    },
    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('@', '')}`;
                    },
                },
            },
        },
    },

I've limited the entries to 2 for this example, but I've got many more.

The output in dist for this setup is:

 index.html                               
 npm.accounting.acb8cd33.js               
 npm.dropzone.1dcac339.js                 
 npm.jquery.7fe2b020.js                   
 npm.knockout-amd-helpers.356a8521.js     
 npm.knockout-punches.efb33702.js         
 npm.knockout.eaf67101.js                 
 npm.knockout.mapping.e01549c3.js         
 npm.moment.0f7e6808.js                   
 npm.sprintf-js.82f89700.js               
 npm.toastr.c6448676.js                   
 npm.webpack.2aab6b7b.js                  
 runtime.acfdeda3.js                      
 products_index.8ef7831b.js             
 products_index~users_index.02e60e46.js 
 users_index.42c4b7af.js                  

This approach is convincingly presented here and seems logical so I've used it.

Everything seems to go swimmingly until I have to create the script tags for this monster.

On the /users route, for example, how do I know which of these files to include? It seems webpack has done all this dependency mapping and left me to do it all again myself!

I can't find anything in in the Webpack documentation site that mentions how to best do this, except a discussion of the html-webpack-plugin which seems solely focused on creating one useless HTML file that just jams all the script tags into to a single file.

I must be missing something obvious here.

jpt
  • 162
  • 1
  • 11

1 Answers1

4

I finally came across an answer buried in a response to an issue on the html-webpack-plugin github site.

If you specify the entry point chunk to the plugin, it correctly calculates the dependencies from there, so you can create a loop in your webpack config that builds the entry config and the plugin config parts and then add them to your config, like this:

var entry: {
        a: "./a",
        b: "./b",
        c: ["./c", "./d"]
};

var entryHtmlPlugins = Object.keys(entry).map(function(entryName) {
   return new HtmlWebpackPlugin({
      filename: entryName + '.html',
      chunks: [entryName]
  })
});

module.export = {
   entry: entry,
   //....
  plugins: [
      // ..
  ].concat(entryHtmlPlugins)
}

The issue page is here: https://github.com/jantimon/html-webpack-plugin/issues/299#issuecomment-216448896

At least in my preliminary testing, this seems to work. Would be great if it was mentioned somewhere in the docs.

jpt
  • 162
  • 1
  • 11