Reputation: 26085
I worked at a company that has a custom JS module bundler. The implementation has a function requireIfLoaded
that allows you to require a module, but only if it has already been loaded. If the module isn't loaded yet, it throws an error. Using requireIfLoaded
doesn't bundle the module. This drastically reduced our file size.
Here's an example of how it can be useful:
if (page === PROFILE) {
// ProfileHelper should already be downloaded if we're on the profile page.
const ProfileHelper = requireIfLoaded('ProfileHelper');
ProfileHelper.doSomething();
} else if (page === FEED) {
// FeedHelper should already be downloaded if we're on the feed page.
const FeedHelper = requireIfLoaded('FeedHelper');
FeedHelper.doSomething();
}
A separate bundle is generated for the profile page and for the feed page. require('ProfileHelper')
isn't called in the feed page codepaths, so ProfileHelper
isn't included in the feed bundle. require('FeedHelper')
isn't called in the profile page codepaths, so FeedHelper
isn't included in the profile bundle. Does Webpack have something like this?
Edit for clarification:
If I required both ProfileHelper
and FeedHelper
all the time, then one of the modules will be unused. At most one of them is loaded on any given page. On the profile page, ProfileHelper
is loaded, but not FeedHelper
. Vice-versa for the feed page.
Also, I don't want to use require.ensure
because it's async.
Upvotes: 17
Views: 2303
Reputation: 721
I found a documentation which explains this. it says "Despite the various options for loading JavaScript, there is still no way to download a JavaScript file and set it to execute at an arbitrary time. You can say execute immediately, or you can defer until the DOM document is complete, but you can’t specify any other point in time to execute the code. "
for more information Seperating javascript download and installation
Upvotes: 0
Reputation: 938
From your question and your comments it seems that ProfileHelper
is loaded via a separate <script>
tag, and is available under the window
scope for immediate use, with no further asynchronous loading.
Also this helpers do not appear to be managed by requireIfLoaded
, and if they aren't already loaded it will throw.
So, under these assumptions, the role of requireIfLoaded
is just to check if the module is available under window
, and throw an error if it doesn't.
So... why not create your own requireIfLoaded
?
function requireIfLoaded(file) {
let m = window[file];
if(m) {
return m;
} else {
throw new Error(`Cannot find module '${file}'`)
}
}
Did I miss something?
Upvotes: 0
Reputation: 3443
This approach is antithetical to bundling with webpack.
The require statements are the very thing that instruct webpack on what to compile. It won't ever compile your conditional requires because those will be evaluated at runtime (but webpack bundles are pre-compiled) and webpack won't have added any of them into your bundles.
What you are looking for is code-splitting: https://webpack.js.org/guides/code-splitting-require/
Tutorials:
Upvotes: 3
Reputation: 3476
Webpack will deduplicate all modules required multiple times, and modules that are already loaded will not be initialized again (following the CommonJS spec). So, basically, just require all your dependencies directly and you're set!
More importantly: don't wrap your requires if you use webpack. The static analysis to determine what modules you are actually using will stop working accurately, and webpack will bundle too much.
Upvotes: 4