-
Notifications
You must be signed in to change notification settings - Fork 5.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support meteor.nodeModules.recompile package.json configuration option. #10603
Support meteor.nodeModules.recompile package.json configuration option. #10603
Conversation
Example: "meteor": { "mainModule": ..., "testModule": ..., "nodeModules": { "recompile": { "very-modern-package": ["client", "server"], "alternate-notation-for-client-and-server": true, "somewhat-modern-package": "legacy", "another-package": ["legacy", "server"] } } } The keys of the meteor.nodeModules.recompile configuration object are npm package names, and the values specify for which bundles those packages should be recompiled using the Meteor compiler plugins system, as if the packages were part of the Meteor application. For example, if an npm package uses const/let syntax or arrow functions, that's fine for modern and server code, but you would probably want to recompile the package when building the legacy bundle. To accomplish this, specify "legacy" or ["legacy"] as the value of the package's property, similar to somewhat-modern-package above. These strings and arrays of strings have the same meaning as the second argument to api.addFiles(files, where) in a package.js file. This configuration serves pretty much the same purpose as symlinking an application directory into node_modules, but without any symlinking: https://forums.meteor.com/t/litelement-import-litelement-html/45042/8?u=benjamn The meteor.nodeModules.recompile configuration currently applies to the application node_modules directory only (not to Npm.depends dependencies in Meteor packages). Recompiled packages must be direct dependencies of the application.
612d4a7
to
f61ba60
Compare
In PR #10585, I tried enabling full compiler plugin processing for any modules imported from `node_modules` that were not otherwise handled by compiler plugins, but doing that for all packages was just too slow, not to mention potentially dangerous for modules whose code cannot be safely recompiled by Babel. The primary reasons for wanting to recompile node_modules are 1. to enable "native" ECMAScript `import`/`export` syntax (given that Node.js still does not fully support ESM syntax yet), and 2. to compile standard syntax like `const`, `let`, classes, and arrow functions for legacy browsers. The first goal can be achieved by compiling unanticipated `node_modules` code with Reify, which is much faster than Babel, in part because Reify can avoid doing any parsing when the source contains no `import` or `export` identifiers. This compilation is also cached on disk, so its impact should only be felt during cold builds after a `meteor reset`. The second goal can be accomplished using the new `package.json` configuration option `meteor.nodeModules.recompile`, which causes the recompiled packages to be handled by the normal compiler plugins system, so that the `ImportScanner`'s fallback compilation is not necessary. Before this option was introduced, this recompilation behavior could be achieved by symlinking application directories into `node_modules`, but that always felt like an esoteric hack.
This ensures we wrap modules with a function to rename the `module` identifier to something more reliable when the ImportScanner compiles unanticipated modules imported from node_modules.
This partially reverts f0d39b8 by simply including .js and .mjs modules in the server bundle, rather than delegating to pure Node evaluation. In practice, whether or not the package has a "module" entry point (or "type":"module") in its package.json was not a perfect indicator of whether it should be compiled with Reify and bundled, or left untouched and handled by Node. Truly native modules (such as those with a .node file extension) should always be handled by Node, so module.useNode() definitely still has a role to play in the server bundle.
With appropriate meteor.nodeModules.recompile configuration, that is.
This partially reverts commit 4dfc741. Some server packages, especially those that rely on __dirname or __filename (e.g. puppeteer), simply cannot be included in the server bundle, and must be evaluated natively by Node. As long as we have a Module.prototype._compile hook to process natively evaluated modules with Reify, module.useNode() can still benefit from ESM import/export syntax.
This allows us to take advantage of the features.compileForShell option when compiling code in the `meteor shell` REPL.
This saves us from having to install @babel/parser in the server bundle. There is currently a bug in Reify that prevents it from loading this parser by default, but we can work around that on the Meteor side for now.
We don't need to build a whole new dev bundle just for this upgrade, since we've already worked around the bug that it fixes, but it will get picked up the next time we build the dev bundle for Meteor 1.8.2.
Now that we have the meteor.nodeModules.recompile configuration (#10603), we don't need to guess which packages might need to be recompiled.
Would it be possible to add an additional prop which would override the source entry point defined in "main" or "module". I'm thinking about "material-ui" in particular. It ships ES6+ modules, in addition to pre-transpiled esm files, which is what it links in it's module field. But there's no obvious way to access that. With an override, we could do that ourselves, and possible gain some benefit in the modern bundle. "main": "./index.js",
"module": "./esm/index.js",
"name": "@material-ui/core", That's what shows in "@material-ui/core"'s package.json file. If we could redefine that to use "module": "./es/index.js" that could be very useful. I'm not sure how many packages deploy assets such as this. {
"meteor": {
"nodeModules": {
"recompile": {
"@material-ui/core": true
},
"alternaiveModule": { // or maybe "moduleEntries"
"@material-ui/core": "./es/index.js"
}
}
}
} |
I feel like |
That would be a great feature! Sometimes It could get tricky though, as tsconfig files can vary from project to project (I publish tsconfig files, and in some cases I compile TypeScript from |
@benjamn Thanks for this! I'm in the process of trying to decipher which package is causing my syntax error on IE: Does the pattern you mentioned allow the names of meteor packages as well as npm packages? I.e. Could I use this in my package.json:
At least, the collection2 package is what IE's terrible debugger seems to be pointing to (though I can't see what/why): Ps - If anybody has any tips/tricks on trying to narrow down the package in question that IE doesn't like, then I'd love to hear it. Thanks in advance |
I don't think recompile is meant for atmosphere packages, but you do need a setting for simpl-schema. Try:
|
Ok, after many hours yesterday, I decided to try create a new project from scratch to see if I can find it that way. Repo here: https://github.com/HemalR/meteor-ie-breaker/branches Two branches - the master doesn't work and the 'works' branch does. The only difference between the two is the presence of the aldeed:collection2 package. I tried adding simpl-schema to the recompile list under package.json to see if that makes a difference, but no luck there. So that does seem to be the culprit. As I type this, I'm wondering whether the collection2 package is even necessary or whether it has been replaced (don't know why that thought is going through my head). I'll explore and update here if that is the case... |
There is a bug with the array syntax #10791 try it with the string "legacy" instead. |
@CaptainN YES! That does the trick (on the tester package at least - now to try on production) |
Alright, confirmed that this added to package.json fixes things:
@CaptainN - Thank you SO MUCH - I'm well into double digits of hours spent on this. B****y IE! |
@HemalR You can also just set it to |
I'm a tad confused by that - the server handles ES6 doesn't it? (And so does Svelte?). If so, then what is the reasoning for the server option (clearly I'm missing something obvious). |
The server handles modern syntax, until new syntax is added (maybe like optional chaining or something like that). If a module has that, it won't work without being transpiled. Svelte always needs to be transpiled, since it's a compiler based framework. |
Ah got it, for the Svelte compiler 👍 Svelte is defo on my list of to-try. I imagine it would actually eliminate (or drastically reduce) IE (or any browser specific) issues with any/all packages. |
@benjamn I have a package setup of for recompile and the recompiling is working just fine, however the package imports a few other npm package and the are completely blank with no code, even thought node module is installed. Is there something wrong I am doing? |
will recompile works with babel plugin? i'm writing a babel plugin for our project, but it looks it doesn't work with plugin |
Hi @crapthings checking the code and also this comment from Ben (f61ba60)
It seems that it's going to recompile using Meteor configurations so if your plugin is applied to your Meteor code it should also be applied in the package code. |
@crapthings I don't know - never tried it. I do know that the meteor build system will not respond to changes you make to your local build plugin files until you restart the build system. So, change file, restart meteor, etc. |
In the spirit of
meteor.mainModule
andmeteor.testModule
(#9690), this PR introduces a newpackage.json
-based configuration for selecting npm packages to recompile using the Meteor compiler plugins system. This configuration is intended to replace the unconditional compilation introduced by #10585.Example:
The keys of the
meteor.nodeModules.recompile
configuration object are npm package names, and the values specify for which bundles those packages should be recompiled using the Meteor compiler plugins system, as if the packages were part of the Meteor application.For example, if an npm package uses
const
/let
syntax or arrow functions, that's fine for modern and server code, but you would probably want to recompile the package when building the legacy bundle. To accomplish this, specify”legacy"
or["legacy"]
as the value of the package's property, similar tosomewhat-modern-package
above. These strings and arrays of strings have the same meaning as the second argument toapi.addFiles(files, where)
in apackage.js
file.This configuration serves pretty much the same purpose as symlinking an application directory into
node_modules
, but without any symlinking: https://forums.meteor.com/t/litelement-import-litelement-html/45042/8?u=benjamnThe
meteor.nodeModules.recompile
configuration currently applies to the applicationnode_modules
directory only (not toNpm.depends
dependencies in Meteor packages). Recompiled packages must be direct dependencies of the application.