Remove node-fetch and form-data from cli-kit - #8287
Draft
isaacroldan wants to merge 2 commits into
Draft
Conversation
Use undici's fetch and FormData instead. undici replaces both packages with a single zero-dependency package, and its EnvHttpProxyAgent keeps support for the SHOPIFY_HTTP_PROXY family of environment variables, which global-agent cannot provide for fetch traffic. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ch-form-data # Conflicts: # packages/cli-kit/package.json # pnpm-lock.yaml
Contributor
Differences in type declarationsWe detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:
New type declarationsWe found no new type declarations in this PR Existing type declarationspackages/cli-kit/dist/private/node/api.d.ts@@ -1,4 +1,6 @@
-import { Headers } from 'form-data';
+interface Headers {
+ forEach(callbackfn: (value: string, key: string) => void): void;
+}
export type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management';
export declare const allAPIs: API[];
export type NetworkRetryBehaviour = {
packages/cli-kit/dist/public/node/http.d.ts@@ -1,7 +1,7 @@
import { NetworkRetryBehaviour } from '../../private/node/api.js';
-import FormData from 'form-data';
-import { RequestInfo, RequestInit, Response } from 'node-fetch';
-export { FetchError, Request, Response } from 'node-fetch';
+import { FormData, Response } from 'undici';
+import type { RequestInfo, RequestInit } from 'undici';
+export { FormData, Request, Response } from 'undici';
/**
* Create a new FormData object.
*
@@ -46,12 +46,8 @@ export declare function requestMode(preset?: RequestModeInput, env?: NodeJS.Proc
*/
export declare function abortSignalFromRequestBehaviour(behaviour: RequestBehaviour): AbortSignal;
/**
- * An interface that abstracts way node-fetch. When Node has built-in
- * support for "fetch" in the standard library, we can drop the node-fetch
- * dependency from here.
- * Note that we are exposing types from "node-fetch". The reason being is that
- * they are consistent with the Web API so if we drop node-fetch in the future
- * it won't require changes from the callers.
+ * An interface that abstracts away the fetch implementation (undici). The exposed
+ * types are consistent with the Web API.
*
* The CLI's fetch function supports special behaviours, like automatic retries. These are disabled by default through
* this function.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WHY are these changes introduced?
Part of the effort to reduce external dependencies in the CLI.
node-fetch(plusfetch-blob,formdata-polyfill,data-uri-to-buffer) andform-data(plusasynckit,combined-stream,mime-types) predate Node's built-in fetch. cli-kit requires Node >=22.12, which ships a spec-compliant fetch.WHAT is this pull request doing?
http.tsnow usesundici'sfetchandFormDatainstead ofnode-fetchandform-data.undiciis a single zero-dependency package (the same code that powers Node's built-in fetch).global-agentpatches Node'shttpmodule, whichnode-fetchused butfetch(undici) bypasses. To keepSHOPIFY_HTTP_PROXY/SHOPIFY_HTTPS_PROXY/SHOPIFY_NO_PROXYworking for cli-kit's fetch traffic, requests go through anEnvHttpProxyAgentdispatcher when those variables are set. This is also why the PR depends on the npmundicipackage instead of the built-in fetch: Node 22 does not expose the proxy agent classes.useHttpsAgentinternal option is gone: itshttps.Agent({keepAlive: true, rejectUnauthorized: true})matches undici's defaults.headers.raw()(a node-fetch extension) is replaced with standardHeadersiteration andgetSetCookie()inadmin.tsand theme'sstorefront-session.ts.http.test.tsmoves from msw to undici'sMockAgent: msw intercepts the patched global fetch andhttp.ClientRequest, neither of which undici's fetch uses.Breaking API changes
@shopify/cli-kit/node/httpno longer exportsFetchError(a node-fetch class). Connection failures now surface asTypeError: fetch failedwith the system error incause. The one in-repo consumer (send-app-uninstalled-webhook.ts) now detectsECONNREFUSEDthrougherror.cause.formData()returns the spec-compliantFormData(nogetLengthSync/getBoundary/stream appends). No production code in the repo used the form-data-specific API.DOMExceptions with slightly different messages (e.g. "The operation was aborted due to timeout"). The retry classifier already matches them.How to test your changes?
Run any command that hits the network (
shopify app dev,shopify theme devwith a password-protected store,shopify versionupdate check). If you use a proxy, setSHOPIFY_HTTP_PROXYand confirm traffic goes through it.Measuring impact
Checklist
🤖 Generated with Claude Code