webpack 4 - split chunks plugin for multiple entries
Asked Answered
G

2

30

Using split chunks plugin with the following config :

{
    entry: {
        entry1: [entry1.js],
        entry2: [entry2.js],
        entry3: [entry3.js],
        ...
    }
    optimization: {
        splitChunks: {
            chunks: "all"
        }
    } 
}

The code would get perfectly split into:

vendors-entry1-entry2-entry3.js // common for all
vendors-entry1-entry3.js // vendors only required by both entry1, entry3
entry1-entry2.js // common code of entry1 and entry2
entry1.js // unique entry's code
entry2.js
entry3.js

Question is, how do i now use the specific vendors per entry in my html (or ejs in my specific case)?

Using HtmlWebpackPlugin as recommended would simply create an index.html which loads all of the above, although the use case is clearly:

When rendering entry1 page - load:

vendors-entry1-entry2-entry3.js
vendors-entry1-entry3.js
entry1-entry2.js
entry1.js

When rendering entry2 page - load:

vendors-entry1-entry2-entry3.js
entry1-entry2.js
entry2.js

etc..

Guardado answered 8/5, 2018 at 6:20 Comment(9)
@Raviteja CommonsChunkPlugin has been removed in webpack 4. SplitChunksPlugin is it's successor.Guardado
Please explain the downvotes, I'd like to know if i'm missing a very basic thing here..Guardado
seems duplicated to #50163519Gavin
@Gavin I don't know the chunk names since they're auto-generatedGuardado
I have the same issue, I don't understand the downvotes.Capsulate
Daniel or @A. Matías Quezada I am curious if you ever found a solution. Having a similar issue and info on splitChunks with multiple entrypoints is very hard to come by.Horner
@Horner unfortunately not yet.Guardado
I'd suggest renaming this question to "WebPack 4 - how to combine HtmlWebpackPlugin with split chunks?" Because chunk splitting usually means having multiple entry points, and the key problem is in HTML generation for this. Upvoted.Higginson
@EgorNepomnyaschih - it's not always for multiple entries, you'd wanna break your bundle into chunks in case it's too big regardless of the number of entries. and for a single entry the plugins work perfectly.Guardado
O
11

Version 4 of HtmlWebpackPlugin (which is alpha as of now) includes all entries' generated chunks automatically. So just setting chunks: 'entry1' should work:

new HtmlWebpackPlugin({
    template: 'entry1.ejs',
    filename: 'entry1.html',
    chunks: ['entry1']
}),

... and leads to injecting of all dependent chunks in html file:

<script src="/vendors-entry1-entry2-entry3.js">
<script src="/vendors-entry1-entry3.js">
<script src="/entry1-entry2.js">
<script src="/entry1.js">

You can install it with

npm install --save-dev html-webpack-plugin@next
Overarm answered 22/7, 2018 at 9:11 Comment(3)
I'm using webpack 4.29.5 and it does not work exactly this way. It's still needed to specify which chunks to load like this: chunks: ['vendors-entry1-entry2-entry3', 'vendors-entry1-entry3', 'entry1-entry2', 'entry1']. Otherwise (like in the answer) it will load only the entry1.js file.Arioso
Just found that it's still planned for the @next release! github.com/jantimon/html-webpack-plugin/issues/1152Arioso
this doesn't work. It injects only once file which is the entry file but none of the chunks.Tabbatha
H
0

I am having a similar problem and have had some minor success using a config setup I found here. Not sure if it will apply to your specific use case, but I thought I'd share.

The optimization hash in webpack config looks like:

    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    name: "commons",
                    chunks: "initial",
                    minChunks: 2,
                    minSize: 0
                }
            }
        },
        occurrenceOrder: true
    },

So using these entrypoints:

    entry: {
        app: './src/app.js',
        home: './src/home.js',
        product: './src/product.js'
    }

And this as my HtmlWebpackPlugin setup:

    // base template common to all pages
    new HtmlWebpackPlugin({
        hash: true,
        inject: true,
        template: './src/jinja-templates/base.html.j2',
        filename: `${templates}/base.html.j2`,
        chunks: ['commons', 'app']
    }),

    // JUST the homepage
    new HtmlWebpackPlugin({
        hash: true,
        inject: true,
        template: './src/jinja-templates/index.html.j2',
        filename: `${templates}/index.html.j2`,
        chunks: ['home']
    }),

    // JUST the product template
    new HtmlWebpackPlugin({
        hash: true,
        inject: true,
        template: './src/jinja-templates/product.html.j2',
        filename: `${templates}/product.html.j2`,
        chunks: ['product']
    }),

I am successfully getting the "commons" and "app" chunks added to all pages, and on the homepage the "home" chunk (only) is added, and on the product page the "product" chunk (only) is added. Here's an example of the source of the "home" page:

    <body>
        ...
        <script type="text/javascript" src="/static/commons.7ca91fd78182a8eb23f6.js?7ca91fd78182a8eb23f6"></script>
        <script type="text/javascript" src="/static/app.7ca91fd78182a8eb23f6.js?7ca91fd78182a8eb23f6"></script>
        <script type="text/javascript" src="/static/home.7ca91fd78182a8eb23f6.js?7ca91fd78182a8eb23f6"></script>
    </body>

I don't know if/how vendor modules can be split out using this setup. I assume it's possible, but if so a secret cabal of webpack elites is keeping this information well-guarded :P

But given it's already splitting the code into several very small chunks I am not sure it's necessary (for me, anyway).

Horner answered 19/6, 2018 at 17:38 Comment(2)
Thanks, I've actually ended up with a quite similar solution, unfortunately it's not really a solution as it does not scale for N entries and doesn't fully utilize the split chunks pluginGuardado
Regarding scalability, you can create a function that will create the HtmlWebpackPlugin for each entry, then use .concat(entryHtmlPlugins) to add them to the plugins array.Cinema

© 2022 - 2024 — McMap. All rights reserved.