Skip to content

refactor(#1136): replace http-proxy w/ httpxy#1160

Open
SukkaW wants to merge 8 commits intochimurai:masterfrom
SukkaW:replace-http-proxy
Open

refactor(#1136): replace http-proxy w/ httpxy#1160
SukkaW wants to merge 8 commits intochimurai:masterfrom
SukkaW:replace-http-proxy

Conversation

@SukkaW
Copy link
Copy Markdown

@SukkaW SukkaW commented Feb 7, 2026

Description

Another attempt to fix #1136.

Unlike #1159, instead of replacing http-proxy w/ http-proxy-3, the PR chooses httpxy, because:

  • httpxy is way more popular and more battle-tested:
    • http-proxy-3 only has about 45K weekly downloads right now
      image
    • while httpxy has about 1.1M weekly downloads right now
      image
  • httpxy has a smaller installation size, hence a smaller footprint:
  • Though http-proxy-3 claims it is used by the Vite, httpxy is actually widely used by the Nuxt.js community, and is actually getting contributions from the Vite.js Team (refactor!: code improvements unjs/httpxy#78)!

Motivation and Context

See #1136

How has this been tested?

image image image

Unlike #1159, I actually get all the tests to pass and TypeScript happy! You can check the action log here: SukkaW#1

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

@SukkaW
Copy link
Copy Markdown
Author

SukkaW commented Feb 7, 2026

cc @chimurai

Please check my PR as another attempt to fix #1136. Unlike #1159, I get all the tests to pass both on my machine locally and on CI (check SukkaW#1):

image image

Also, I get rid of all TypeScript errors with tsc --build runs perfectly:

image

@chimurai
Copy link
Copy Markdown
Owner

chimurai commented Feb 7, 2026

Hi @SukkaW

Thanks for the PR! Didn't know about httpxy

Did a quick check and looks really nice so far. Most of the types are working.

Found a small issue in the typing where req somehow is now type any.

image

Added an extra check to prevent req: any (#1161)
image

🔧 Can you rebase with master?
You'll see the same error in:

// responseInterceptor
proxyServer.on(
'proxyRes',
responseInterceptor(async (buffer, proxyRes, req, res) => {
req.params;
res.status(200).send('OK');
return buffer;
}),
);

"strict": true,
"noImplicitAny": false
"noImplicitAny": false,
"skipLibCheck": true
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Why was skipLibCheck: true needed?

Copy link
Copy Markdown
Author

@SukkaW SukkaW Feb 8, 2026

Choose a reason for hiding this comment

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

httpxy's types rely on a default export on node:http (in its .d.ts it uses import http from 'node:http').

But this only works with moduleResolution: node16/nodenext/bundler + module: node16/nodenext/preserve setup, not with moduleResolution: node + module: commonjs setup.

So rather than changing the moduleResolution and module (which will most likely result in a huge breaking change), I just enabled skipLibCheck to avoid that.

@SukkaW
Copy link
Copy Markdown
Author

SukkaW commented Feb 8, 2026

Did a quick check and looks really nice so far. Most of the types are working.

Found a small issue in the typing where req somehow is now type any.

The httpxy usage of EventEmitter is not typed. I have submitted a PR to the upstream to fix it: unjs/httpxy#96

After httpxy merges that PR and releases a new version, the any we are seeing here should be gone.

@SukkaW SukkaW force-pushed the replace-http-proxy branch from b1801dd to c10521e Compare February 9, 2026 09:09
@SukkaW
Copy link
Copy Markdown
Author

SukkaW commented Feb 11, 2026

@chimurai

The types are fixed, and all tests passed on my machine locally:

image

type Interceptor<TReq = http.IncomingMessage, TRes = http.ServerResponse> = (
buffer: Buffer,
proxyRes: TReq,
proxyRes: http.IncomingMessage,
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

proxyRes comes from the http client instead of the call site (express.js), thus this should not be TReq.

Comment on lines +19 to 21
if (!req || !res) {
throw err; // "Error: Must provide a proper URL as target"
}
Copy link
Copy Markdown
Author

@SukkaW SukkaW Feb 11, 2026

Choose a reason for hiding this comment

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

Technically, req and res should either be both specified or both nullish.

However, currently, httpxy can't implement this kind of overload due to how NodeJS.EventEmitter types its event arguments via a generic (which ProxyServer is extending from), so the && is replaced with || to make the TypeScript happy down the road.

@SukkaW
Copy link
Copy Markdown
Author

SukkaW commented Feb 11, 2026

@chimurai Also, I am currently actively working on httpxy's HTTP/2 listener support (unjs/httpxy#38).

Update: almost done unjs/httpxy#102

@SukkaW
Copy link
Copy Markdown
Author

SukkaW commented Mar 5, 2026

@chimurai Hello, what else is required for the PR to merge? All TypeScript error has been fixed and the lint is now happy.

@SukkaW
Copy link
Copy Markdown
Author

SukkaW commented Apr 2, 2026

@chimurai Just a friendly ping, would you like to review this? All TypeScript errors have been fixed, the lint is happy, and all the tests have passed.

@chimurai chimurai force-pushed the replace-http-proxy branch from 13848fb to 548b23c Compare April 2, 2026 17:26
@coveralls
Copy link
Copy Markdown

coveralls commented Apr 2, 2026

Coverage Status

coverage: 96.544% (-0.6%) from 97.15%
when pulling dacea34 on SukkaW:replace-http-proxy
into 48ed092 on chimurai:master.

@chimurai
Copy link
Copy Markdown
Owner

chimurai commented Apr 2, 2026

Hi @SukkaW. Thanks for the reminder. PR looks good.

CI is failing because patches need to be removed which are not needed anymore:

patches/http-proxy+1.18.1.patch

You can verify if the other patches are still needed with:

yarn patch-package

Once this is fixed, this PR can be merged 👍

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR attempts to resolve #1136 by replacing the unmaintained http-proxy dependency with httpxy, updating the middleware implementation and exported types to match httpxy’s API/behavior.

Changes:

  • Swap http-proxy / @types/http-proxy for httpxy and update lockfile/spellcheck dictionary.
  • Refactor core proxying logic to use httpxy’s promise-based web/ws APIs and adjust error handling + shutdown behavior.
  • Update public TypeScript types and response interception types to align with the new proxy library.

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
package.json Replaces proxy dependency with httpxy (but note patch-package implications).
yarn.lock Removes http-proxy transitive deps and adds httpxy.
tsconfig.json Enables skipLibCheck.
src/http-proxy-middleware.ts Migrates to httpxy (createProxyServer, async web/ws), adjusts error emitting and close handling.
src/types.ts Switches exported proxy types from http-proxy to httpxy and redefines event callback shapes.
src/plugins/default/proxy-events.ts Adjusts on option iteration to improve typing/narrowing.
src/plugins/default/error-response-plugin.ts Changes error guard condition for rethrow behavior.
src/handlers/response-interceptor.ts Corrects proxyRes typing to http.IncomingMessage and updates decompression call site.
cspell.json Adds httpxy to allowed words list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"@types/http-proxy": "^1.17.15",
"debug": "^4.3.6",
"http-proxy": "^1.18.1",
"httpxy": "^0.2.2",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You should update to see how it behaves in this version, since things have changed.

Suggested change
"httpxy": "^0.2.2",
"httpxy": "^0.5.0",

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

There were a few breaking changes: httpxy@0.3.0 dropped Node.js legacy Url support, and httpxy@0.4.0 became ESM-only. Both will break http-proxy-middleware's support range (which is Node.js 14.18.0+)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Proposing to ship the current version + some bugfixes queued in the PRs for v4

In v5 we can make http-proxy-middleware future ready with ESM + CJS, so we can use httpxy@0.3.0+

I'll make this more visible in the roadmap 👍

@SukkaW SukkaW force-pushed the replace-http-proxy branch from 548b23c to dacea34 Compare April 3, 2026 06:10
@SukkaW
Copy link
Copy Markdown
Author

SukkaW commented Apr 3, 2026

cc @chimurai

I have rebased the PR to the latest master, and I have dropped patches/http-proxy+1.18.1.patch in dacea34 (this PR).

@erictheswift
Copy link
Copy Markdown

Omg folks, I’m so excited and it took less time than to implement esmodules after es2015 release😜

@erictheswift
Copy link
Copy Markdown

Kudos!

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 3, 2026

npm i https://pkg.pr.new/http-proxy-middleware@1160

commit: 058d409

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.

feat(http-proxy-3): migrate from http-proxy to http-proxy alternative

6 participants