Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack 5 runtime and dependOn property

Tags:

webpack-5

I'm mostly confused as to what the runtime property is actually doing for a webpack entry point. Referenced here:

enter image description here

And even more confused when the documentation makes this statement:

enter image description here

What exactly is the runtime chunk for an entry point and how does it relate to that limitation.

Ty!

Link to full page here

like image 943
rubixibuc Avatar asked Oct 15 '25 15:10

rubixibuc


1 Answers

You have to understand first what runtime and dependOn actually are.

runtime

Take this as an example:

src/myModule.js

export const textToPrint = 'Hello world!';

src/index.js

import { textToPrint } from "./myModule";
console.log(textToPrint);

webpack.config.js

module.exports = {
    entry: {
        myEntry: {
            // runtime: 'myRuntime',
            import: './src/index.js',
        }
    }
};

dist/index.html

<!DOCTYPE html>
<html>
    <head>
        <!-- Don't forget to uncommet this line when using the
             `runtime` property in the webpack configuration -->
        <!-- <script src="./myRuntime.js"></script> -->
        <script src="./myEntry.js"></script>
    </head>
    <body></body>
</html>

Running npx webpack --mode='development' will generate a dist/myEntry.js file wich will, among other things, create and use a __webpack_require__() function:

// ...

/******/    function __webpack_require__(moduleId) {
/******/        // Check if module is in cache
/******/        var cachedModule = __webpack_module_cache__[moduleId];
/******/        if (cachedModule !== undefined) {
/******/            return cachedModule.exports;
/******/        }
/******/        // Create a new module (and put it into the cache)
/******/        var module = __webpack_module_cache__[moduleId] = {
/******/            // no module.id needed
/******/            // no module.loaded needed
/******/            exports: {}
/******/        };
/******/    
/******/        // Execute the module function
/******/        __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/    
/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }

// ...

Now, if you uncomment the runtime: 'myRuntime' line in webpack.config.js and rerun the webpack command, you will see now that the __webpack_require__ function is not generated anywhere in dist/myEntry.js. You might see __webpack_require__ here and there in that file, but they are only references to the parameters of the function, not the function itself.

enter image description here

In dist/myRuntime.js, however...

enter image description here

As you can see, it's there. With this we can conclude that the runtime is the part of the bundle with the functions that are used in other parts to load the modules. Whether those functions are or not in the same file depends on whether you use this option or not. The advantage is that you can have smaller chunks with this code stripped away in a separate file instead of having this code duplicated in all entry points. The disadvantage however is that because this runtime file is meant to be used in other files, Webpack cannot predict what functionalities are not used, so Webpack keeps them (This is just a theory, I am not 100% sure this is the actual reason why the runtime has more things when in a separate file).

Don't forget to uncomment the <script src="./myRuntime.js"></script> line in dist/index.html. Because this script contains the functionality to load modules, it obviously has to be loaded before other scripts.

dependOn

Let's suppose we have now these files in our project:

src/index.js

globalThis.messageToPrint = 'Hello world!';

src/foo.js

console.log(globalThis.messageToPrint);

In this case, because foo.js is using a global variable whose value is set by index.js, it obviously depends on index.js so we tell Webpack about this to have the bundles configured properly:

webpack.config.js

module.exports = {
    entry: {
        myEntry: {
            import: './src/index.js',
        },
        mySecondEntry: {
            import: './src/foo.js',
            dependOn: 'myEntry'
        }
    }
};

We also have to remember to load the scripts in order in our html file, like so:

_index.html

<!DOCTYPE html>
<html>
    <head>
        <script src="./myEntry.js"></script>
        <script src="./mySecondEntry.js"></script>
    </head>
    <body></body>
</html>

Remember what I told you about runtimes? Because we didn't use the runtime property this time, in theory both myEntry.js and mySecondEntry.js should have the runtime code in them. But because the runtime is loaded already in myEntry, it doesn't make sense to also load it in mySecondEntry, so it is automatically stripped from that file.

Why can't we specify both runtime and dependOn in the same entry in the webpack configuration file then?

Because both runtime and dependOn would strip the runtime from the entry file. One because the runtime would be in a separate file so that other entires can reuse it, and the other because the runtime is already loaded by the dependency. Having both wouldn't make sense because the dependency would in some way or another have this runtime loaded anyways. In the same file or in the runtime file, the dependency would load it. If you want both to specify a dependency and have the runtime in a separate file, then using this example you would have to specify the runtime property in myEntry and dependOn in mySecondEntry.

like image 194
Adrian Avatar answered Oct 19 '25 05:10

Adrian