-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Fix Cesium in Node.js 12+. #8659
Conversation
Thanks for the pull request @kring!
Reviewers, don't forget to make sure that:
|
By the way, be very careful when testing anything with
The app will run successfully until you |
I made a project to test some different scenarios for importing Cesium in node.js: |
This branch built for me under Node 12 LTS. The I got about 37 warnings from
|
Thanks for taking a look, Ed. I think those warnings happen even in Node 10, don't they? |
I may have skipped 10 on my way here, sorry... 😄 |
Yeah, npm install is noisy and terrible. Those are in 10 as well. I will hopefully have some time to look over this soon. |
index.cjs
Outdated
var fs = require('fs'); | ||
|
||
var originalFunc = require.extensions['.js']; | ||
require.extensions['.js'] = function(module, filename) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a global change to the node environment, right? Sounds like we don't have a lot of options, just wanted to confirm.
Just to throw out an alternative, we could always use the built version of Cesium in NodeJS and by requiring CesiumUnminified/Cesium.js
we would still get extra debugging and such.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, if esm
is going the way of the dodo, maybe it's better to just use combined in all cases now and we can revisit going full import later on (Node 14?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea! I got rid of the hack and made index.cjs
always load the built version, either Build/Cesium/Cesium.js
or Build/CesiumUnminified/Cesium.js
depending on the NODE_ENV
.
I also hooked up sourcemaps so it still looks like separate source file while debugging. I couldn't get it to work in the minified build for some reason, though. Uglify/Rollup are supposed to be able to do sourcemapping in this scenario, but the generated sourcemaps were rubbish. Step into a Cesium function in a release build and you'd end up somewhere totally random instead of in the function you're actually in.
If you use Node 12 and proper ES module support, you'll use the ES modules directly, with no transpilation by esm
or other shenanigans. However, the debug pragmas won't be removed in this scenario. That's unfortunate, but a problem for another day, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks again for your work on this. We talked offline, but just to summarize for anyone else, rollup-plugin-strip-pragma
can be used for pragma removal, debug sourcemaps are still enabled, release will have to wait for a different PR to figure out the problem.
package.json
Outdated
"coverage": "gulp coverage", | ||
"generateDocumentation": "gulp generateDocumentation", | ||
"generateDocumentation-watch": "gulp generateDocumentation-watch", | ||
"build": "gulp -f gulpfile.cjs build", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can revert all of the -f gulpfile.cjs
and just tell gulp to use it by default, see https://github.com/CesiumGS/cesium/pull/8541/files#diff-a663dcab4db6e595455e0c837b86ee03
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, done.
Thanks for the exemplary PR description and details @kring. Pretty sure I'm okay with all of this except for the those couple of questions/comments. We could potentially do a node-only release of Cesium with this fix once it's in master since it's affecting a lot of people at this point |
I'd love to see this merged in, we could really use this change! :) |
@tmcintire this will definitely go out with the next release on April 1. @kring do you have time to help finish this up? If not I can take it over. |
Yep, thanks for the reminder! I'll do it today. |
Everything looks great, just want to do some final testing once CI passes and than I'll merge. |
Did a quick test with node 12 and 13 and was able to import Cesium in both cases as both commonjs or ES modules. (Node 12 still required a flag, 13 did not). Also tested a rollup based app using node-resolve with Cesium ES6 and that worked as well. Going to merge so this has some time to stew in master. Thanks again @kring! |
@kring I noticed that after this PR the copyright banner is no longer included in the built minified files (for example, check today's release zip) despite using the |
Node.js 12+ requires that ES modules are loaded with
import
rather thanrequire
, and it throws an exception if you get this wrong. An ES module is any module that is named.mjs
or whose closest package.json specifies"type": "module"
(as Cesium's does).The Node.js module docs explain a couple of approaches for making a single package that works when imported as either an ES module or as a CommonJS module. But the first requires that the library be natively CommonJS (which Cesium is not), and the second requires two copies of the library (one CommonJS modules, one ES modules) and a dodgy approach to allow the two to share state 🙄. There's no scenario where the library is natively ES modules and can be loaded in CommonJS apps using
esm
, and short of terrible hackery it appears that this is no longer possible to achieve in Node 12+.So, this PR does some terrible hackery, as suggested here:
standard-things/esm#855 (comment)
(By the way, the commentor above implemented the check and exception that is causing us problems, as well as large parts of Node's module system in general I believe, so presumably knows what he's talking about! nodejs/node#29492)
This PR also adds a
package.json
with"type": "commonjs"
to the Tools directory so that the .js files there are treated as CommonJS. This is needed for several of our build tools to work in Node 12+. It also renames gulpfile.js to gulpfile.cjs so that file isn't interpreted as an ES module, and it adds an explicit parameter to all thenpm run scripts
telling gulp to use it. gulp isn't (yet?) able to look for a gulpfile.cjs itself.Other approaches we could take, not implemented in this PR:
"type": "module"
. If we do that, we don't need any of the other changes in this PR and everything will work great in Node 12+. BUT users won't be able to import Cesium as "real" ES modules using--experimental-modules
anymore. They'll always have to useesm
..mjs
or.cjs
as appropriate (or put a separate package.json in each version's subdirectory with a different"type"
). Ideally break all of Cesium's shared state into separate CommonJS modules as described in Approach 2 in the node.js docs above. That way if one thing imports the CommonJS version and another thing imports the ES version, will "only" have two versions of all the code rather than everything breaking cause there's two versions of the global data.Fixes #8452