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.
When a CSS (or compiled-to-CSS) module is lazy (e.g., in `imports/` or
`node_modules`) and not otherwise imported by another CSS module, Meteor
automatically turns it into a JS module so that it can be handled by the
`ImportScanner`, and imported dynamically by other JS modules.
Until now, there were two problems with CSS handled in this way: it did
not have proper source maps, and the CSS text was not minified in
production.
This commit introduces a special minification step for dynamic CSS, which
must take place before we create the dynamic JS module. Waiting for the
usual minification of CSS would be a mistake, since that happens long
after the `ImportScanner` and `Linker` have already processed JavaScript
modules. Modifying the contents of JS modules at that point would be
impossible without recomputing source maps, etc.
Since the JS module dynamically creates a `<style>` tag and appends it to
the `<head>` of the document, the code of the JS module has no meaningful
relationship to the lines of CSS text that are actually evaluated by the
browser, so it would be a mistake to give the JS module the same source
map as the original CSS resource.
Instead, when there is a source map, we write it out as an asset that can
be requested at runtime, and append a sourceMappingURL comment to the end
of the CSS text referring to this asset URL. Note that this only happens
in development, which makes sense because minification in production
invalidates the source map, and we don't want to expose source code in
production anyway.
According to traditional Meteor file loading rules, tests/ directories are
completely ignored: https://guide.meteor.com/structure.html#special-directories
However, if you specify a meteor.testModule in your package.json that
refers to a file inside a tests/ directory, Meteor should permit modules
to be loaded from tests/, as well as any modules that are imported by the
meteor.testModule entry point.
Fixes#9991.