Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fallback-local-proxy-origin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@vercel/microfrontends": patch
---

Send the browser-facing local proxy origin to local and fallback applications in the `x-vercel-mfe-local-proxy-origin` request header.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The local development proxy can preserve the origin used to reach it. Set it exp

The origin must be an absolute `http` or `https` origin, such as `https://myapp.localhost`, with no path, query string, hash, username, or password. The proxy uses this origin anywhere it needs to preserve the URL clients used to reach the proxy.

Proxied requests include this value in the `x-vercel-mfe-local-proxy-origin` header, including requests that fall back to a deployed application. When no origin is configured, the header contains the proxy's default `http://localhost:<port>` origin.

## Need help?

Reach out for help in the [Vercel Community](https://community.vercel.com).
2 changes: 2 additions & 0 deletions packages/microfrontends/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The local development proxy can preserve the origin used to reach it. Set it exp

The origin must be an absolute `http` or `https` origin, such as `https://myapp.localhost`, with no path, query string, hash, username, or password. The proxy uses this origin anywhere it needs to preserve the URL clients used to reach the proxy.

Proxied requests include this value in the `x-vercel-mfe-local-proxy-origin` header, including requests that fall back to a deployed application. When no origin is configured, the header contains the proxy's default `http://localhost:<port>` origin.

## Need help?

Reach out for help in the [Vercel Community](https://community.vercel.com).
16 changes: 7 additions & 9 deletions packages/microfrontends/src/bin/local-proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ describe('class LocalProxy', () => {
'x-forwarded-proto': 'https',
'x-forwarded-host': 'vercel.localhost',
'x-forwarded-port': '443',
'x-vercel-mfe-local-proxy-origin': '1',
'x-vercel-mfe-local-proxy-origin': 'https://vercel.localhost',
}),
}),
);
Expand Down Expand Up @@ -832,7 +832,9 @@ describe('class LocalProxy', () => {
},
);

const req = mockRequest('/a-path-that-surely-does-not-match-any-routes');
const req = mockRequest('/a-path-that-surely-does-not-match-any-routes', {
'x-vercel-mfe-local-proxy-origin': 'https://spoofed.example.com',
});
(req as unknown as { on: jest.Mock }).on = jest.fn();
const res = mockResponse();
(res as unknown as { on: jest.Mock }).on = jest.fn();
Expand All @@ -847,15 +849,11 @@ describe('class LocalProxy', () => {
'x-forwarded-proto': 'https',
'x-forwarded-host': 'vercel.localhost',
'x-forwarded-port': '443',
'x-vercel-mfe-local-proxy-origin': 'https://vercel.localhost',
}),
}),
expect.any(Function),
);
const [requestOptions] = (https.request as unknown as jest.Mock).mock
.calls[0] as [{ headers: Record<string, string | string[]> }];
expect(requestOptions.headers).not.toHaveProperty(
'x-vercel-mfe-local-proxy-origin',
);
expect(res.writeHead).toHaveBeenCalledWith(
307,
expect.objectContaining({
Expand Down Expand Up @@ -1101,7 +1099,7 @@ describe('class LocalProxy', () => {
'x-forwarded-proto': 'https',
'x-forwarded-host': 'vercel.localhost',
'x-forwarded-port': '443',
'x-vercel-mfe-local-proxy-origin': '1',
'x-vercel-mfe-local-proxy-origin': 'https://vercel.localhost',
}),
}),
);
Expand Down Expand Up @@ -1137,7 +1135,7 @@ describe('class LocalProxy', () => {
expect(options.headers).not.toHaveProperty('x-forwarded-host');
expect(options.headers).not.toHaveProperty('x-forwarded-port');
expect(options.headers).toMatchObject({
'x-vercel-mfe-local-proxy-origin': '1',
'x-vercel-mfe-local-proxy-origin': 'http://localhost:6720',
});
});
});
Expand Down
12 changes: 7 additions & 5 deletions packages/microfrontends/src/bin/local-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ import { localAuthHtml } from './local-auth';
import { logger } from './logger';
import type { LocalProxyApplicationResponse, LocalProxyOptions } from './types';

// This is a header set to `1` by the local proxy on all outgoing requests to locally running applications.
// Applications may optionally route all traffic that they receive without the header to the local proxy.
// This allows the application to appear as if it is serving routes from another microfrontend.
// This header is set by the local proxy on all outgoing requests and contains the
// browser-facing origin. Applications may optionally route all traffic that they
// receive without the header to the local proxy. This allows the application to
// appear as if it is serving routes from another microfrontend.
const MFE_LOCAL_PROXY_HEADER = 'x-vercel-mfe-local-proxy-origin';

// This is a query parameter that can be passed to the local proxy to be used as the value of any flags
Expand Down Expand Up @@ -735,7 +736,7 @@ export class LocalProxy {
const headers: Record<string, string> = this.configuredOrigin
? forwardedHeadersForOrigin(this.getOrigin())
: {};
headers[MFE_LOCAL_PROXY_HEADER] = '1';
headers[MFE_LOCAL_PROXY_HEADER] = this.getOrigin();
this.proxy.ws(req, socket, head, {
target: target.url,
headers,
Expand Down Expand Up @@ -818,6 +819,7 @@ export class LocalProxy {
...fallbackHeaders,
host: hostname,
...forwardedHeaders,
[MFE_LOCAL_PROXY_HEADER]: origin,
cookie: Object.entries(cookies)
.reduce<string[]>((acc, [name, value]) => {
if (
Expand Down Expand Up @@ -920,7 +922,7 @@ export class LocalProxy {
});
} else {
const headers: Record<string, string> = { ...forwardedHeaders };
headers[MFE_LOCAL_PROXY_HEADER] = '1';
headers[MFE_LOCAL_PROXY_HEADER] = origin;
if (mfeFlagValue !== undefined) {
headers[MFE_FLAG_VALUE_HEADER] = mfeFlagValue.toString();
}
Expand Down
Loading