Previously, the linker included a "version" hash in each stub entry
corresponding to a dynamic module in the meteorInstall bundle. These stub
entries also contain information about any module identifiers ("deps")
imported by the module, and various other metadata.
This hash was derived from the source code of the dynamic module, instead
of its fully-processed generated code, which created a small risk that the
source hash would remain the same when anything changed in the post-linker
processing logic.
This new implementation uses the same hashes found in program.json
manifest files, which more reliably reflect changes in the actual final
contents of the modules.
Because these hashes are not known at link time, they are now injected as
one blob into the meteor/dynamic-import/dynamic-versions.js module, rather
than appearing in the meteorInstall bundles for their containing packages.
Instead of fetching a bundle of JavaScript from the server, Cordova apps
include the complete bundle in the installed app, so there's no compelling
reason to allow dynamic module fetching.
The dynamic import(...) function will still work on Cordova, of course.
It will just never have to fetch anything from the server.
Keeping track of the latest version for each module identifier was more
important when we were using localStorage, because it helped with
periodically removing unused module sources.
Since the storage limits for IndexedDB are substantially higher than for
localStorage, we can safely keep old versions in the cache, and reap the
benefits if those versions are ever needed again.
Eliminating this extra logic simplifies the caching logic considerably,
and also improves cache read performance.
This reverts commit 027d3e15a7.
This optimization was not safe in all browsers. In particular, Firefox
complained about requests against inactive transactions.
If import(...) is called multiple times in quick succession, these changes
should allow cache.checkMany to avoid the overhead of creating multiple
IndexedDB transactions.
I was able to achieve tolerable performance by using only one (read-only)
transaction for each cache.getMany call, and only one (read+write)
transaction for each cache.setMany call.
Even though localStorage is a synchronous API, I wrote this code in an
asynchronous style so that we can easily switch to an async API when/if
that becomes preferable.
While localStorage has stricter size limits than IndexedDB, retrieving
data from IndexedDB is unbelievably slow (~10ms for each cache.check
call). When developing locally, that delay pretty much destroys any
benefit from caching.