Follow-up to https://github.com/meteor/meteor/pull/9933.
As recommended by @abernix, the sha1 hash of every file is now computed
from the file's sha512 hash, so we don't have to hash the entire contents
of the file twice with two different algorithms.
Other changes/improvements:
* Invalidate the hashes when/if `File#setContents` is called.
* Ignore `options.hash` and just compute hashes from actual file contents.
Disagreement here would be worse than any performance benefits from
precomputing the hash.
Because of 8b04c25390, there may now be
multiple calls to meteorInstall in the modules package bundle.
The code for extracting module sizes from the minified bundle previously
assumed there would be only one call to meteorInstall, so this commit
allows for more than one call.
While I was at it, I deleted the simplistic Visitor implementation this
code was using in favor of the more sophisticated Visitor provided by the
reify package, which has the abitlity to skip whole subtrees that do not
contain the identifier(s) we care about.
This may help with lots of issues, most recently #10044 but also #10034, #9976, #9711, and #9568,
to name a few. In particular, since we silently fall back to
`Babel.minify` when `uglify-es` (now `terser`) fails, there should be
fewer problems with `Babel.minify` (parse errors, performance, memory
usage) if `terser` succeeds more often.
Note: because we have bumped the minor versions of `minifier-js` and
`standard-minifier-js`, and they are core packages, you'll have to be
using the next beta version of Meteor 1.7.1 in order to update to these
versions, unless you clone those packages into your local `packages/`
directory. However, if we can validate that `terser` is fully backwards
compatible with `uglify-es`, we might be able to back-port this fix as a
patch update, or publish a Meteor 1.7.0.4 release that permits
`minifier-js@2.4.x`.
Static CSS gets merged in development as well as production by
ClientTarget#minifyCss; the only difference is that the CSS is also
minified in production. This development-time merging is especially
expensive because it involves source maps, and happens on every rebuild of
the app. That's why ClientTarget#minifyCss consistently shows up in
METEOR_PROFILE output for rebuilds.
The standard-minifier-css package tries to cache the merging based on the
hashes of the input files:
8a562523a4/packages/standard-minifier-css/plugin/minify-css.js (L58-L62)
However, not all CSS minifier plugins use a strategy like this, and
https://atmospherejs.com/juliancwirko/postcss is an increasingly popular
one that does not.
The time has come to move this caching logic into the Meteor build tool
itself, so that CSS minifier plugins no longer have to worry about basic
caching, and everyone who uses CSS minifiers with Meteor will benefit.
This implementation leverages Meteor's powerful optimistic caching
techniques to keep previous results in memory only as long as the minifier
object remains reachable.
Since markBoundary is essentially creating a bound wrapper function,
there's no reason we can't actually bind the function to a specific
context (this) object at the same time, instead of having to bind the
function and then wrap it with buildmessage.markBoundary.
With lazy compilation, it should be cheap to pass a ton of files to
processFilesForTarget, as long as only a small percentage of them are
actually used by the application.
Before this change, every inputFile passed to processFilesForTarget would
get its own async function, which took considerably more time to resolve
than using Promise.await inside getResult to handle any Promise returned
by the compileOneFile method.
In other words, this change should significantly reduce the METEOR_PROFILE
timings for items like "other plugin less..." especially during rebuilds,
when very few files actually need to be recompiled.
I recently noticed a bug whereby modules transferred from the application
bundle to the modules bundle would lose their application-specific import
extensions, since all modules installed in the modules bundle have only
.js and .json as import extensions, matching default Node behavior.
This commit fixes that bug by emitting one meteorInstall call per distinct
meteorInstallOptions object. This logic would work if every module had a
different meteorInstallOptions object, but in practice the modules bundle
should end up with exactly two meteorInstall calls, because a single
options object is shared among all modules from the same source batch.