Search code examples
typescriptwebpackwebpack-4commonjs

How to make splitChunks generate commonjs requires() statements?


I have the following Webpack configuration. My application consists of a bunch of scripts deployed to AWS Lambdas, so the target is Node and CommonJS. Each script is entry point, though I've limited it just to two for the sake of the example.

The entry points often use the same libraries/dependencies as one another so the resulting files contain a lot of duplication which I'm trying to reduce.

I added the optimization section containing splitChunks and the output files in /dist look a lot better. Each entry point file has been reduced a lot, and the new vendor.js is a lot bigger. The total filesize was reduced by more than 5x.

The problem is that doing so has broken my application. It can no longer resolve the dependencies properly. I put Webpack into development mode so that I could skim the output. I checked inside the generated add-comment.js and there is no reference to anything like require('./vendor.js'), and in fact no uses of the word 'vendor' at all.

Is there some configuration I can change so that each entry point gets a reference to vendor.js? Or maybe I'm misunderstanding how this is supposed to work?

module.exports = [
    {
        name: 'Server',
        mode: 'development',
        entry: {
            'add-comment': './server/add-comment.ts',
            'delete-comment': './server/delete-comment.ts'
        },
        output: {
            filename: 'server/[name].js',
            libraryTarget: 'commonjs'
        },
        target: 'node',
        resolve: {
            extensions: ['.ts', '.js']
        },
        module: {
            rules: [
                {
                    test: /\.ts$/,
                    exclude: /node_modules/,
                    use: [{
                        loader: 'ts-loader',
                        options: {
                            configFile: "server/tsconfig.json"
                        }
                    }]
                }
            ]
        },
        externals: ['aws-sdk'],
        optimization: {
            splitChunks: {
                name: 'vendor',
                chunks: 'all'
            }   
        }
    }
]

Not sure if it's relevant, but this my tsconfig. "module": "commonjs" and a few other thing are brought in by the extends directive. Here's the rest

{
    "$schema": "https://json.schemastore.org/tsconfig",
    "extends": "@tsconfig/node14/tsconfig.json",
    "compilerOptions":
    {
        "moduleResolution": "node",
        "target": "ES2019",
        "strict": false,
        "types": ["jest", "webpack-env"]
    }
}

If I use the HtmlWebpackPlugin (which is not applicable to my situation since I'm targeting Node, not a browser) then it will generate the scripts in the following order.

<script src="server/vendor.js"></script>
<script src="server/add-comment.js"></script>
<script src="server/delete-comment.js"></script>

So Webpack clearly knows that that vendor needs to be loaded first, but something about my configuration means that it doesn't understand how my code is being invoked. I have target: 'node' already, maybe I need something else.


Solution

  • This has been implemented in Webpack 5. As far as I know there is no plan to backport it.

    There's an incompatibility between Webpack 4 and Webpack 5. The output section needs to change to this:

    output: {
        filename: 'server/[name].js',
        library {
            type: 'commonjs'
        }
    },