Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack 4 - Migrating from CommonsChunkPlugin to SplitChunksPlugin

We have a traditional server rendered application (non SPA) where each page is augmented with vuejs

Our existing webpack 3 configuration is

webpack.config.js

var webpack = require('webpack')
var path = require('path')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
    entry: {
        shared: './shared.js',
        pageA: './pageA.js',
        // pageB: './pageB.js',
        // pageC: './pageC.js',
        // etc
    },

    resolve: {
        alias: { vue: 'vue/dist/vue.esm.js' },
    },

    output: {
        path: path.join(__dirname, './dist'),
        filename: '[name].js',
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: ExtractTextPlugin.extract({
                    use: [
                        {
                            loader: 'css-loader',
                            query: {
                                sourceMap: true,
                            },
                        },
                    ],
                }),
            },
        ],
    },

    plugins: [
        new CleanWebpackPlugin('./dist'),

        new webpack.optimize.CommonsChunkPlugin({
            name: ['shared'],
            minChunks: Infinity,
        }),

        new webpack.optimize.CommonsChunkPlugin({
            name: 'runtime',
        }),

        new ExtractTextPlugin('[name].css'),

        new CopyWebpackPlugin([{ from: 'index.html', to: '.' }]),
    ],
}

shared.js

// import shared dependencies & pollyfills
var vue = require('vue')

// import global site css file
require('./shared.css')

// initialize global defaults
// vue.setDefaults(...)

console.log('shared', { vue })

pageA.js

var vue = require('vue')

// only this page uses axios
var axios = require('axios')

console.log('pageA', { vue, axios })

shared.css

body {
    background-color: aquamarine;
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- included on every page-->
    <link rel="stylesheet" href="shared.css">
</head>
<body>
    <!-- included on every page-->
    <script src="runtime.js"></script>
    <script src="shared.js"></script>

    <script src="pageA.js"></script>
</body>
</html>

With this setup

1) runtime.js contains the webpack loader, so any changes to shared.js don't cause pageA.js to be cache busted and vice versa

2) shared.js contains any shared dependencies (in this case vue) as well as any shared global initializion for every page (setting vue defaults etc). It is also the point we import our shared global css file.

3) pageA.js does not contain any dependencies imported in shared.js (vue in this case) but does contain dependicies it imports (axios in this case).

We have been unable to reproduce this setup using the SplitChunksPlugin

1) SplitChunksPlugin doesn't seem to allow an entry point as a split point.

2) All the examples have split out ALL node module dependices into a vendor chunk. This doesn't work for us as we have 100's of pages but only a few import a graphing library or moment etc... We don't want to have this graphing library or moment included in shared.js as it will then be load for all pages.

3) It wasn't clear how to split the runtime into its own file either

SplitChunksPlugin seems to be targeted at SPA's where javascript can be loaded on demand. Is the scenario we are trageting still supported?

like image 580
kimsagro Avatar asked Sep 16 '18 04:09

kimsagro


1 Answers

Are you trying to migrate to webpack 4?

I find the optimisation cacheGroups test option works well to be specific about what goes where.

optimization: {
  splitChunks: {
    cacheGroups: {
      shared: {
        test: /node_modules[\\/](?!axios)/,
        name: "shared",
        enforce: true,
        chunks: "all"
      }
    }
  }
}

Will load everything from the node modules (except axios) and should therefore be included as part of your page entry point.

like image 155
Eliott Robson Avatar answered Oct 17 '22 02:10

Eliott Robson