0

I'm using Webpack (4.43.0) to code split a NodeJS application for AWS Lambda. I have a main bundle which is small and contains the code I wrote, and I have a vendors bundle which is large and contains all the (tree shaken) node_modules dependencies like Express.JS. The problem is when I run the main chunk (with node ./dist/main.js), it's unable to resolve the dependencies in the vendors bundle. Reading through the output code I can't see how it could resolve the vendors modules as main doesn't have a way to resolve them.

The error I receive is:

modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
TypeError: Cannot read property 'call' of undefined

Reading the code output in dist/main.js, the Webpack bootstrap function receives the following list of modules:

[
  './node_modules/express/lib sync recursive',
  './src/main.ts',
  'buffer',
  'crypto',
  'events',
  'fs',
  'http',
  'net',
  'path',
  'querystring',
  'stream',
  'string_decoder',
  'tty',
  'url',
  'util',
  'zlib'
]

The ./src/main.ts is the entry point and is executed here:

/******/    // Load entry module and return exports
/******/    return __webpack_require__(__webpack_require__.s = "./src/main.ts");

This module tries to include ./node_modules/express/index.js and this throws the error because it doesn't exist in the initial module list:

/******/    // The require function
/******/    function __webpack_require__(moduleId) {
/******/
/******/        // Check if module is in cache
/******/        if(installedModules[moduleId]) {
/******/            return installedModules[moduleId].exports;
/******/        }
/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            i: moduleId,
/******/            l: false,
/******/            exports: {}
/******/        };
/******/
/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/        // Flag the module as loaded
/******/        module.l = true;
/******/
/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }

If I manually inject the following code to import the "vendors" module into the module list the code will work fine but this isn't an ideal solution.

const vendor = require('./vendors~main.js');
Object.keys(vendor.modules).forEach((mod) => {
  modules[mod] = vendor.modules[mod];
});

Does anyone know the correct way of making the "vendors" modules available?

webpack.config.js

const path = require('path');

module.exports = {
    mode: 'development',
    target: 'node',
    entry: './src/main.ts',
    output: {
        path: path.join(__dirname, './dist'),
        filename: '[name].js',
        libraryTarget: 'commonjs',
    },
    resolve: {
        extensions: [ '.tsx', '.ts', '.js' ],
    },
    module: {
        rules: [
            { test: /\.ts$/, use: 'ts-loader' }
        ]
    },
    optimization: {
        sideEffects: false,
        namedModules: true,
        namedChunks: true,
        splitChunks: {
            chunks: 'all'
        }
    },
};

main.ts

import express from 'express';
const port = 3000;
const app = express();

app.get('*', (req: express.Request, res: express.Response) => {
    res.send('Working');
});

app.listen(port, () => {
    console.log(`Listening on port ${port}`);
});

I setup a demo repo https://github.com/rjenkin/nodejscodesplit

Ryan Jenkin
  • 864
  • 8
  • 11
  • Can you use [webpack-node-externals](https://stackoverflow.com/questions/61995331/how-does-dynamic-import-in-webpack-works-when-used-with-an-expression) to extract all npm modules? (this would require a `npm i` before using but would make your bundle significantly smaller. – Elias Schablowski Jun 07 '20 at 19:58
  • If I understand correctly `webpack-node-externals` would exclude all node_modules from the vendors bundle. The problem I have is that "main" isn't able to load the dependencies in the "vendor" bundle. – Ryan Jenkin Jun 07 '20 at 22:15

1 Answers1

0

Apparently target: "node" doesn't support splitChunks with chunks: "initial" or chunks: "all". https://github.com/webpack/webpack/issues/7392

Ryan Jenkin
  • 864
  • 8
  • 11