Because in-place rebuilds are disabled by default on Windows, we were
losing .meteor/local/build/programs/web.browser.legacy every time we
rebuilt .meteor/local/build as part of writeSiteArchive, as reported by
@lmachens in this comment: https://github.com/meteor/meteor/pull/9942#issuecomment-406656741
In-place rewriting of .meteor/local/build seems essential for the new
strategy of writing different targets at different times, though I have
attempted to limit the risk of overwriting open files on Windows by
continuing to build the individual target directories from scratch (that
is, by writing a fresh temporary directory and then renaming it over the
existing directory).
Though I don't have any specific ideas in this direction, it may be worth
noting: if we could find a way to make in-place builds safer on Windows
(as they are on Linux and Mac), Windows rebuilds would be significantly
faster than they are with the current strategy of rewriting everything
from scratch every time.
The defaultExtensionHandlers[".json"] function in import-scanner.js sets
file.jsonData as a side effect, which is important because that's what the
linker uses to construct a stub module.exports object for dynamically
imported package.json modules.
When I introduced ImportScanner#_readPackageJson as an alternative to
ImportScanner#_readModule in a recent commit, I intentionally did not call
defaultExtensionHandlers[".json"], but in so doing I neglected to preserve
the behavior of setting file.jsonData.
Without a proper package.json stub with at least a "main" property, the
dynamic import() system can't resolve dynamically imported packages until
the full package.json module has been fetched from the server, which leads
to missing module errors in the initial dynamic import().
Fixes#10073, per
https://github.com/meteor/meteor/issues/10073#issuecomment-405290391
While thinking about this bug, I realized that sending IPC messages to
specific packages in the server process was much less flexible than
sending messages based on an arbitrary topic string, since the topic
string approach allows both `autoupdate` and `dynamic-import` to listen
for the same message.
The topic string approach calls for a listener interface like
`onMessage(topic, callback)`, which elegantly replaces the previous
approach of requiring packages to export a single `onMessage` function.
However, because the `meteor` package does not have access to the module
system, implementing the `onMessage` listener interface in the `meteor`
package would have required exposing an API like `Meteor.onMessage(topic,
callback)`, which has an unpleasant global smell to it. Instead, the
`onMessage` function should be explicitly imported (using the module
system) from a less-generically-named package.
Since I knew I was going to have to move the message dispatch logic out of
the `meteor` package, I decided to create a new package called
`inter-process-messaging` to implement the parent/child components of the
IPC system.
https://github.com/meteor/meteor/pull/10055#discussion_r201855997
As I explained in this comment, Package._on(packageName, callback) was a
bad API because it never called the callback if the package was not
installed, which caused any app not using the autoupdate package to get
stuck trying to communicate with the autoupdate package.
Instead of having every message consumer listen to every message and act
on the ones that seem relevant to its interests, we now have a single
process.on("message", callback) hook that can dispatch messages to
different Meteor packages running in the server process.
Receiving packages should export an onMessage function. The onMessage
function may be async, and its result will be delivered back to the build
process as the result of the sendMessage Promise.
Most importantly, we no longer return a copy of previousBuilders from
bundler.bundle, but simply modify the input object over time. The copying
approach was nice in theory, but incompatible with delaying the bundling
of certain architectures (e.g. web.browser.legacy) until some time after
bundler.bundle returns.
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.
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.
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.
This should be a better fix for the problem I tried to fix with
479e505d71.
If we're going to be using compileOneFileLater by default, that's what we
should be testing in the compiler plugins self-tests.
The concept of a "root" file is specific to MultiFileCachingCompiler, so
we need to normalize it into a representation that makes sense to the rest
of the compiler plugin system.
Should help with #10014.
The previous commit enabled importing index.* modules at runtime, but
unfortunately the build-time Resolver logic also needed updating, which
will require a new Meteor release.