Commit Graph

7 Commits

Author SHA1 Message Date
Ben Newman
924c748ecc Avoid bailing out with module.useNode() for ESM modules.
On the server, Meteor attempts to avoid bundling node_modules code by
replacing entry point modules with a stub that calls module.useNode() (see
packages/modules-runtime/server.js). This trick allows evaluating server
node_modules natively in Node.js, faithfully preserving all Node-specific
behaviors, such as module.id being an absolute file system path, the
__dirname and __filename variables, the ability to import binary .node
modules, and so on.

However, starting in Node.js 12.16.0 (Meteor 1.9.1+), modules evaluated
natively by Node are considered ECMAScript modules (ESM) if the closest
package.json file has "type": "module" (or has an .mjs file extension).
This poses a problem for the module.useNode() trick, because ESM modules
cannot be imported synchronously using require (which is currently how
module.useNode() works).

To work around this new error, this commit checks package.json for "type":
"module" in ImportScanner#shouldUseNode to determine whether it's safe to
use the module.useNode() trick.

The good news is that ESM modules don't have access to nearly as many
Node.js-specific quirks: no module, require, or exports variables; no
__dirname, no __filename; no ability to import JSON or other non-ESM file
types (at least right now). So it seems somewhat less important for ESM
code (compared to CommonJS code) to bail out into native Node.js execution
using module.useNode(). In other words, bundling server code should not
affect its execution in nearly as many cases, if that code is ESM rather
than legacy CommonJS.

If this good news turns out to be overly optimistic, we can consider using
a different kind of bailout stub that's capable of importing ESM using
dynamic import(). For now, making sure we avoid bailing out for ESM code
like @babel/runtime/helpers/esm/* is the priority.
2020-02-19 15:24:42 -04:00
Ben Newman
24865b28a0 Wrap Module.prototype.require instead of using options.wrapRequire.
a630b5c2ac
7a9abeca88
2018-06-25 16:43:46 -04:00
Michał Powaga
7b2aba09a0 Print nicer error message for missing Meteor package (#9719) 2018-03-29 09:51:18 -04:00
Ben Newman
971d2b1272 Standardize Npm.require exceptions and limit lookup paths. (#9095)
Ever since Meteor 1.3 first introduced a module system based on something
other than `Npm.require`, we've continued throwing missing module
exceptions that refer to `Npm.depends` and/or `Npm.require`, even if the
developer called `require` or used an `import` declaration. This commit
fixes that, so that all missing module exceptions look like 'Cannot find
module "module/name"'.

I also noticed recently that `Npm.require` is capable of returning modules
installed in `node_modules` directories completely outside the app, which
is bad news for development/production reproducibility. Fixed that too.

CC @hwillson who has spoken of deprecating `Npm.require` entirely, and
just using `require` everywhere, instead.
2017-09-18 11:39:45 -04:00
Ben Newman
9c7778da36 Let the install npm package implement Module.prototype.prefetch.
Now anyone can define meteorInstall.fetch however they see fit, and the
install.js implementation will handle everything else.

This separation of concerns leads to significantly less code, too.
2017-05-01 23:55:00 -04:00
Ben Newman
352f545be2 Record complete module graph, including dynamic stubs, in meteorInstall. 2017-02-07 16:17:42 -05:00
Ben Newman
960ad2266b Refactor modules-runtime into multiple files. 2017-02-07 16:17:40 -05:00