Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why bother with dependencies list in CommonJS require.ensure()?

From the Webpack documentation (https://webpack.github.io/docs/api-in-modules.html#require-ensure):

Download additional dependencies on demand. The dependencies array lists modules that should be available. When they are, callback is called. If the callback is a function expression, dependencies in that source part are extracted and also loaded on demand. A single request is fired to the server, except if all modules are already available.

If dependencies in the source part are also extracted and loaded on demand, then why bother putting anything in the dependencies list?

I've seen examples like this that are very confusing (https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk):

require.ensure(["./a"], function(require) {
    require("./b");
    require("./d");
});

"b" and "d" are not in the dependencies list, but will be loaded on demand just like "a". So what's the difference?

like image 270
hekevintran Avatar asked Nov 08 '22 18:11

hekevintran


2 Answers

The example in the docs you linked to shows one way that behavior differs. When you specify a dependency, it explicitly creates a new chunk, puts the dependency in it, and adds any other dependencies referenced in the callback. When you don't specify a dependency, any dependencies in the callback are added to the 'current' (last?) chunk, a new chunk is not created.

like image 105
Brendan Gannon Avatar answered Jan 04 '23 03:01

Brendan Gannon


In short: you should not bother.

Origin of the problem

Tobias Koppers, author of Webpack was asked a similar question on Gitter:

Raúl Ferràs: Is there any advantage between these two forms?

require.ensure(['jquery','Backbone','underscore'], function(require){
    var jQuery = require('jquery'),
    Backbone  = require('Backbone'),
    _ = require('underscore');
};

and this

require.ensure(['jquery'], function(require){
    var jQuery = require('jquery'),
    Backbone  = require('Backbone'),
    _ = require('underscore');
};

Tobias Koppers: No difference... even the generated source is equal. But the spec says the dependency should be in the array.

Webpack's require.ensure was implemented according to the CommonJS Modules/Async/A proposal, which says:

"require.ensure" accepts an array of module identifiers as first argument and a callback function as second argument.

The spec doesn't specify if non-listed modules required in the callback will be loaded asynchronously, but has a sample code where only the module listed in the array is required:

require.ensure(['increment'], function(require) {
    var inc = require('increment').inc;
    var a = 1;
    inc(a); // 2
});

Thus, in my opinion, async loading of required but non-listed modules is a feature of Webpack and a deviation from the spec. Such feature makes the first argument pointless in most cases and raises questions.

Use cases

1. Comply with the spec

One use case for the first argument could be to specify all the dependencies for clarity and to comply with the spec. But that's completely optional.

2. Pull modules into specific chunks

Consider you have two split points in different parts of an app. The first split point depends on module a, the second depends on modules a and b. To eliminate the risk of downloading a twice, you could decide to place both modules into a single chunk:

// First split point
require.ensure(['b'], (require) => {
  require('a');
});
like image 27
Vitaly Kuznetsov Avatar answered Jan 04 '23 02:01

Vitaly Kuznetsov