Skip to content
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: (5.x) make access to process.versions lazy #12584

Merged
merged 3 commits into from Feb 20, 2023

Conversation

maciasello
Copy link
Contributor

Summary

This PR (commit: 9396dbb) fixes gh-11943 in 5.x branch. It makes access to process.versions lazy (in a function, not at module level) and thus does not crash mongoose loaded in a browser.

This PR (commit: f9146a3) also contains an attempt to implement a test for this issue. Unfortunately it does not achieve the main goal. I haven't been able to mock/replace value of process.versions to mimic what is available in the browser. Whatever is written to it (or its properties) is lost and the original values are always returned.
I am open for any suggestion on how to achieve that and can work on the PR until it is good enough. I have checked that the main change fixes the issue in our project.

Also it includes a fix (commit: c290eea) to enable running browser.test.js in isolation (npx mocha --exit ./test/browser.test.js). Without the change the driver is not set before being accessed.
It doesn't fail when running all tests in batch, so it raises a question if driver objects set by tests do not interfere with results of other tests.

Examples

No examples needed. For the failure, just load the original dist/browser.umd.js into a browser.

@maciasello
Copy link
Contributor Author

Not sure what is the workflow. Can I get a pair of eyes on this even though in draft still? I would greatly appreciate some hints on:

  • if/how to test the change (I tried a couple approaches, but failed -> see the description)
  • is 5.x still maintained (hopefully)
    CC @vkarpov15

@vkarpov15 vkarpov15 added this to the 5.13.16 milestone Oct 25, 2022
Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor suggestions. Most important is to fix the tests, but would also be nice to handle the case when process.versions.node is undefined

@@ -936,4 +936,6 @@ exports.errorToPOJO = function errorToPOJO(error) {
return ret;
};

exports.nodeMajorVersion = parseInt(process.versions.node.split('.')[0], 10);
exports.nodeMajorVersion = function nodeMajorVersion() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we make nodeMajorVersion() return null if process.versions is undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! Can do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting with this change until the convo below is resolved. ⬇️

@@ -104,7 +104,7 @@ QueryCursor.prototype._read = function() {
return _this.emit('error', error);
}
// for node >= 12 the autoDestroy will emit the 'close' event
if (utils.nodeMajorVersion < 12) {
if (utils.nodeMajorVersion() < 12) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make nodeMajorVersion() return null if process.versions is undefined, add a check: const nodeMajorVersion = utils.nodeMajorVersion(); if (nodeMajorVersion != null && nodeMajorVersion < 12) { ... }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that in the browser scenario any of the variants (entering or not entering the branch) is correct? Shouldn't it be an error if the execution path reached this point in the browser? I understand we don't to crash too much, but this check may create a false appearance that it can still work.
However, to fully assess that I would need to understand if there is any scenario where QueryCursor can work in the browser.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vkarpov15 What do you think about that? ⬆️

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Shouldn't it be an error if the execution path reached this point in the browser?" <-- sure, but we can say the same thing about a lot of the codebase. I'd prefer to avoid having individual snippets of code being aware about browser vs not browser, and instead rely on the browser build to determine what should or shouldn't be in the browser build. Ideally this code wouldn't be in the browser build at all, but that's a little harder to fix.

TLDR; let's do the simple, low-risk fix of checking if nodeMajorVersion is null here.

@@ -18,6 +19,10 @@ describe('browser', function() {
exec('node --eval "require(\'./lib/browser\')"', done);
});

it('require() works in an environment where process.versions is an empty object (gh-5842)', function(done) {
exec('node --eval "const process = require(\\"node:process\\"); process.versions = {}; require(\'./lib/browser\')"', done);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this require('process'). Older node versions don't support require('node:process')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do. This test was just a placeholder as it didn't properly verify the issue.
I found that Object.defineProperty(process, 'versions', { value: {} }) works for replacing the versions object. I pushed an updated version (still without the null handling described in the other comment).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another issue connected to it.
If you do require('./lib.browser.js') with process.versions replaced with {} there is another piece of code that fails. It is located in one of the dependent libraries (bluebird required by mquery).
It seems to be removed by tree shaking done by webpack as it is not present in the final browser bundle.
Thus, I made the test load the bundle file (./dist/browser.umd.js) not ./lib/browser. It may lead to additional quirks when testing locally as the file must be built before running tests.

@maciasello
Copy link
Contributor Author

@vkarpov15 I pushed a fix for the tests. Linter and tests should not fail anymore. Can you look at #12584 (comment) ?

@maciasello maciasello marked this pull request as ready for review November 2, 2022 15:58
Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got some test failures that we'll fix in 5.x branch, but otherwise good to go 👍

@vkarpov15 vkarpov15 merged commit 78d9d91 into Automattic:5.x Feb 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants