Webpack Internal Module Caching Demonstration
Description
This repo attempts to offer a simple model that demonstrates how Webpack module caching works as well as the problems that can arise due to module id collision.
Problems that this repo demonstrates
In traditional full page reload application lifecycles, module id collision would not be a problem. However, in the TSheets application lifecycles, modules are loaded in on the fly. That is, within a single application lifecycle a module could be loaded into Webpack's internal cache and attempted to be reloaded multiple times.
Under the covers, Webpack's module loading system has a cache. You can
get a taste of this by looking for __webpack_require__
in your
compiled javascript assets.
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
...
Here you can see that internally Webpack has a cache is implemented as a
map keyed by module id to the compiled module implementation. This is
known internally as installedModules
.
With the above snippet of code, it is possible that a module of name
foo
if already loaded, would not override the pre-existing module
if it was attempted to be loaded again.
Steps
First start up the application:
npm run build
npm run dev-server
Then check out the application at localhost:8080
.
Open the dev tools and run the following in the dev console:
a.testAlert();
You should see the alert pop up as a1
. Now you would intuitively
expect that if you change a1
to a2
and bring the script into
the app runtime (without refreshing the page), that the script would
be updated and if you ran a.testAlert()
the alert would show you
a2
. This is not the case, let's demonstrate that with the following.
While the dev server is still running, run
npm run repro-steps
This will update a1
to a2
and rebuild the bundle for you.
Now open the dev console in the same page that you had originally opened up the browser in. Make sure the network tab is open before you run the following command.
common.loadScript('./build/a/a.min.js');
This will load the new version of the script. You should be able to see
this in the network tab of the dev tools. Basic browser cache busting is
done with the current time in UTC added as a query string. You can
check the implementation if you'd like in ./src/common/index.js
.
Now once the new script has been loaded into the browser check to see if the new reference is being used by Webpack.
a.testAlert();
You should still see a1
even though you've loaded the new source that
contains a2
. So it has not been updated.