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

lib: refactor lazy loading of undici for fetch method #52275

Merged

Conversation

YCChenVictor
Copy link
Contributor

Object.defineProperty is updated to lazily load the undici dependency for the fetch method. This change allows for simpler and more reliable mocking of the fetch method for testing purposes, resolving issues encountered with premature method invocation during testing.

Fixes: #52015

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/startup
  • @nodejs/web-standards

@nodejs-github-bot nodejs-github-bot added lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Mar 30, 2024
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

Note that this setup slows down every invocation of fetch() by adding an additional function call and the require logic. The previous logic added lazy loading that should be kept in.

Could you add a test? I don't understand what would not be possible in the previous setup.

@MoLow
Copy link
Member

MoLow commented Mar 31, 2024

Could you add a test? I don't understand what would not be possible in the previous setup.

see #52015
mocking globalThis.fetch is harder without this fix.

1 similar comment
@MoLow
Copy link
Member

MoLow commented Mar 31, 2024

Could you add a test? I don't understand what would not be possible in the previous setup.

see #52015
mocking globalThis.fetch is harder without this fix.

@mcollina
Copy link
Member

The test should be added and the lazyloading kept in.

@regseb
Copy link
Contributor

regseb commented Apr 4, 2024

@mcollina

I think this configuration is faster on the first call (there's no need to replace get and set by value). And the speed is the same for next calls.


console.log("BEFORE");
console.log(Object.getOwnPropertyDescriptor(globalThis, "fetch"));
console.log(Object.getOwnPropertyDescriptor(globalThis, "fetch").set.toString());
console.log(Object.getOwnPropertyDescriptor(globalThis, "fetch").get.toString());

fetch;

console.log("AFTER");
console.log(Object.getOwnPropertyDescriptor(globalThis, "fetch"));
console.log(Object.getOwnPropertyDescriptor(globalThis, "fetch").value.toString());

When I run the above code in Node.js v21.7.0:

BEFORE
{
  get: [Function: get],
  set: [Function: set],
  enumerable: true,
  configurable: true
}

function set(value) {
    ObjectDefineProperty(globalThis, 'fetch', {
      __proto__: null,
      writable: true,
      value,
    });
  }

get() {
      function fetch(input, init = undefined) {
        // Loading undici alone lead to promises which breaks lots of tests so we
        // have to load it really lazily for now.
        const { fetch: impl } = require('internal/deps/undici/undici');
        return impl(input, init);
      }
      set(fetch);
      return fetch;
    }

AFTER
{
  value: [Function: fetch],
  writable: true,
  enumerable: true,
  configurable: true
}

function fetch(input, init = undefined) {
        // Loading undici alone lead to promises which breaks lots of tests so we
        // have to load it really lazily for now.
        const { fetch: impl } = require('internal/deps/undici/undici');
        return impl(input, init);
      }

With this pull request, the AFTER configuration is directly available.


Lazyloading is kept, as undici is only imported when fetch() is run.

value: function fetch(input, init = undefined) { // eslint-disable-line func-name-matching
// Loading undici alone lead to promises which breaks lots of tests so we
// have to load it really lazily for now.
const { fetch: impl } = require('internal/deps/undici/undici');
Copy link
Member

Choose a reason for hiding this comment

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

do we really need to lazily load it every time?
Can't we have something around the lines of:

let impl;

value: function fetch(input, init = undefined) {
  impl ??= require('internal/deps/undici/undici');
  return impl(input, init)
},

Copy link

Choose a reason for hiding this comment

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

Technically require would cache it anyway, right?

Copy link
Member

Choose a reason for hiding this comment

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

Well, technically it will, but the cost for calling require would still be higher (I don't have benchmarks, but it has more overhead than holding a local variable in memory)

@mcollina
Copy link
Member

mcollina commented Apr 5, 2024

What @atlowChemi wrote in #52275 (comment)

@@ -59,27 +59,16 @@ installObjectURLMethods();

{
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the curly bracket is no longer necessary. It was probably used to avoid creating the set function in the root scope.

Object.defineProperty is updated to lazily load the undici dependency
for the fetch method. This change allows for simpler and more reliable
mocking of the fetch method for testing purposes, resolving issues
encountered with premature method invocation during testing.

Fixes: nodejs#52015
@YCChenVictor YCChenVictor force-pushed the feature/lazy-fetch-undici-loading branch from 796a413 to 9ee922e Compare April 7, 2024 05:58
@MoLow MoLow requested a review from mcollina April 7, 2024 07:33
Copy link
Member

@atlowChemi atlowChemi left a comment

Choose a reason for hiding this comment

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

Other than lint errors, LGTM

lib/internal/bootstrap/web/exposed-window-or-worker.js Outdated Show resolved Hide resolved
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

lgtm

Instead of importing undici upfront, the module is now conditionally
required using require only when the fetch function is called for the
first time and the undici implementation is not already available. This
lazy loading approach improves resource usage and test reliability by
loading undici only when needed.
@YCChenVictor YCChenVictor force-pushed the feature/lazy-fetch-undici-loading branch from 9ee922e to 5c6a889 Compare April 9, 2024 01:14
@MoLow MoLow added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Apr 9, 2024
@mcollina mcollina added the request-ci Add this label to start a Jenkins CI on a PR. label Apr 9, 2024
@MoLow
Copy link
Member

MoLow commented Apr 9, 2024

@YCChenVictor can you add a test that checks #52015 won't regress?

@panva panva added the commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. label Apr 9, 2024
@YCChenVictor YCChenVictor force-pushed the feature/lazy-fetch-undici-loading branch from b42ee5b to 2eddeda Compare April 9, 2024 13:25
Copy link
Contributor

@Ethan-Arrowood Ethan-Arrowood left a comment

Choose a reason for hiding this comment

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

how does this work with the following lines (just below your contribution?):

exposeLazyInterfaces(globalThis, 'internal/deps/undici/undici', [
  'FormData', 'Headers', 'Request', 'Response',
]);

If I use any of those interfaces, should fetch be loaded as well?

@YCChenVictor YCChenVictor force-pushed the feature/lazy-fetch-undici-loading branch from 2eddeda to 7937b69 Compare April 11, 2024 08:08
@MoLow MoLow added the request-ci Add this label to start a Jenkins CI on a PR. label Apr 11, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Apr 11, 2024
@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@YCChenVictor
Copy link
Contributor Author

I'm uncertain why the checks failed. Perhaps I should rebase this branch on the latest node commit? Any guidance would be greatly appreciated, and I'm sincerely grateful for any corrections or suggestions. Thank you!

@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@joyeecheung
Copy link
Member

The failures are most likely flakes.

@nodejs-github-bot
Copy link
Collaborator

@joyeecheung joyeecheung added the commit-queue Add this label to land a pull request using GitHub Actions. label Apr 12, 2024
@nodejs-github-bot nodejs-github-bot added commit-queue-failed An error occurred while landing this pull request using GitHub Actions. and removed commit-queue Add this label to land a pull request using GitHub Actions. labels Apr 12, 2024
@nodejs-github-bot
Copy link
Collaborator

Commit Queue failed
- Loading data for nodejs/node/pull/52275
✔  Done loading data for nodejs/node/pull/52275
----------------------------------- PR info ------------------------------------
Title      lib: refactor lazy loading of undici for fetch method (#52275)
Author     Victor Chen  (@YCChenVictor, first-time contributor)
Branch     YCChenVictor:feature/lazy-fetch-undici-loading -> nodejs:main
Labels     lib / src, needs-ci, commit-queue-squash
Commits    3
 - lib: refactor lazy loading of undici for fetch method
 - lib: implement lazy loading for fetch function
 - lib: test for fetch mock without prior invocation
Committers 1
 - YCChen 
PR-URL: https://github.com/nodejs/node/pull/52275
Fixes: https://github.com/nodejs/node/issues/52015
Reviewed-By: Moshe Atlow 
Reviewed-By: Matteo Collina 
Reviewed-By: Chemi Atlow 
Reviewed-By: James M Snell 
------------------------------ Generated metadata ------------------------------
PR-URL: https://github.com/nodejs/node/pull/52275
Fixes: https://github.com/nodejs/node/issues/52015
Reviewed-By: Moshe Atlow 
Reviewed-By: Matteo Collina 
Reviewed-By: Chemi Atlow 
Reviewed-By: James M Snell 
--------------------------------------------------------------------------------
   ⚠  Commits were pushed since the last approving review:
   ⚠  - lib: test for fetch mock without prior invocation
   ℹ  This PR was created on Sat, 30 Mar 2024 14:26:41 GMT
   ✔  Approvals: 4
   ✔  - Moshe Atlow (@MoLow) (TSC): https://github.com/nodejs/node/pull/52275#pullrequestreview-1990083304
   ✔  - Matteo Collina (@mcollina) (TSC): https://github.com/nodejs/node/pull/52275#pullrequestreview-1985970496
   ✔  - Chemi Atlow (@atlowChemi): https://github.com/nodejs/node/pull/52275#pullrequestreview-1988005649
   ✔  - James M Snell (@jasnell) (TSC): https://github.com/nodejs/node/pull/52275#pullrequestreview-1992479891
   ✔  Last GitHub CI successful
   ℹ  Last Full PR CI on 2024-04-12T14:12:32Z: https://ci.nodejs.org/job/node-test-pull-request/58323/
- Querying data for job/node-test-pull-request/58323/
   ✔  Last Jenkins CI successful
--------------------------------------------------------------------------------
   ✔  Aborted `git node land` session in /home/runner/work/node/node/.ncu
https://github.com/nodejs/node/actions/runs/8665947485

@joyeecheung joyeecheung added commit-queue Add this label to land a pull request using GitHub Actions. and removed commit-queue-failed An error occurred while landing this pull request using GitHub Actions. labels Apr 12, 2024
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Apr 12, 2024
@nodejs-github-bot nodejs-github-bot merged commit 2cd3073 into nodejs:main Apr 12, 2024
63 checks passed
@nodejs-github-bot
Copy link
Collaborator

Landed in 2cd3073

aduh95 pushed a commit that referenced this pull request Apr 29, 2024
Object.defineProperty is updated to lazily load the undici dependency
for the fetch method. This change allows for simpler and more reliable
mocking of the fetch method for testing purposes, resolving issues
encountered with premature method invocation during testing.

Fixes: #52015
PR-URL: #52275
Reviewed-By: Moshe Atlow <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
marco-ippolito pushed a commit that referenced this pull request May 2, 2024
Object.defineProperty is updated to lazily load the undici dependency
for the fetch method. This change allows for simpler and more reliable
mocking of the fetch method for testing purposes, resolving issues
encountered with premature method invocation during testing.

Fixes: #52015
PR-URL: #52275
Reviewed-By: Moshe Atlow <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
marco-ippolito pushed a commit that referenced this pull request May 3, 2024
Object.defineProperty is updated to lazily load the undici dependency
for the fetch method. This change allows for simpler and more reliable
mocking of the fetch method for testing purposes, resolving issues
encountered with premature method invocation during testing.

Fixes: #52015
PR-URL: #52275
Reviewed-By: Moshe Atlow <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

breaking change in 21.7.0 when mocking fetch