Testing & troubleshooting microfrontends
The @vercel/microfrontends package includes test utilities to help avoid common misconfigurations.
The validateMiddlewareConfig test ensures Middleware is configured to work correctly with microfrontends. Passing this test does not guarantee Middleware is set up correctly, but it should find many common problems.
Since Middleware only runs in the default application, you should only run this test on the default application. If it finds a configuration issue, it will throw an exception so that you can use it with any test framework.
/* @jest-environment node */
import { validateMiddlewareConfig } from '@vercel/microfrontends/next/testing';
import { config } from '../middleware';
describe('middleware', () => {
test('matches microfrontends paths', () => {
expect(() =>
validateMiddlewareConfig(config, './microfrontends.json'),
).not.toThrow();
});
});The validateMiddlewareOnFlaggedPaths test checks that Middleware is correctly configured for flagged paths by ensuring that Middleware rewrites to the correct path for these flagged paths. Since Middleware only runs in the default application, you should only run this testing utility in the default application.
/* @jest-environment node */
import { validateMiddlewareOnFlaggedPaths } from '@vercel/microfrontends/next/testing';
import { middleware } from '../middleware';
// For this test to work, all flags must be enabled before calling
// validateMiddlewareOnFlaggedPaths. There are many ways to do this depending
// on your flag framework, test framework, etc. but this is one way to do it
// with https://flags-sdk.dev/
jest.mock('flags/next', () => ({
flag: jest.fn().mockReturnValue(jest.fn().mockResolvedValue(true)),
}));
describe('middleware', () => {
test('rewrites for flagged paths', async () => {
await expect(
validateMiddlewareOnFlaggedPaths('./microfrontends.json', middleware),
).resolves.not.toThrow();
});
});The validateRouting test validates that the given paths route to the correct microfrontend. You should only add this test to the default application where the microfrontends.json file is defined.
import { validateRouting } from '@vercel/microfrontends/next/testing';
describe('microfrontends', () => {
test('routing', () => {
expect(() => {
validateRouting('./microfrontends.json', {
marketing: ['/', '/products'],
docs: ['/docs', '/docs/api'],
dashboard: [
'/dashboard',
{ path: '/new-dashboard', flag: 'enable-feature-x' },
],
});
}).not.toThrow();
});
});The above test confirms that microfrontends routing:
- Routes
/and/productsto themarketingmicrofrontend. - Routes
/docsand/docs/apito thedocsmicrofrontend. - Routes
/dashboardand/new-dashboard(with theenable-feature-xflag enabled) to thedashboardmicrofrontend.
See debug routing for how to enable debug logs to see where and why the local proxy routed the request.
Debug headers expose the internal reason for the microfrontend response. You can use these headers to debug issues with routing.
You can enable debug headers in the Vercel Toolbar, or by setting a cookie VERCEL_MFE_DEBUG to 1 in your browser.
Requests to your domain will then return additional headers on every response:
x-vercel-mfe-app: The name of the microfrontend project that handled the request.x-vercel-mfe-target-deployment-id: The ID of the deployment that handled the request.x-vercel-mfe-default-app-deployment-id: The ID of the default application deployment, the source of themicrofrontends.jsonconfiguration.x-vercel-mfe-zone-from-middleware: For flagged paths, the name of the microfrontend that middleware decided should handle the request.x-vercel-mfe-matched-path: The path frommicrofrontends.jsonthat was matched by the routing configuration.x-vercel-mfe-response-reason: The internal reason for the MFE response.
Microfrontends routing information is stored in Observability and can be viewed in the team or project scopes. Click on the Observability tab, and then find Microfrontends in the CDN section.
Microfrontends routing is captured by Vercel Session tracing. Once you have captured a trace, you can inspect the Microfrontends span in the logs section in the sidebar.
You may need to zoom in to the Microfrontends span. The span includes:
vercel.mfe.app: The name of the microfrontend project that handled the request.vercel.mfe.target_deployment_id: The ID of the deployment that handled the request.vercel.mfe.default_app_deployment_id: The ID of the default application deployment, the source of themicrofrontends.jsonconfiguration.vercel.mfe.app_from_middleware: For flagged paths, the name of the microfrontend that middleware decided should handle the request.vercel.mfe.matched_path: The path frommicrofrontends.jsonthat was matched by the routing configuration.
The following are common issues you might face with debugging tips:
A build that ends with Could not find a microfrontends.json file in the repository that contains the "<application>" application means the application couldn't locate a microfrontends.json that lists it when it builds. Every application in the group reads microfrontends.json at build time through withMicrofrontends.
In a monorepo, each application searches the repository for the configuration automatically and matches applications by name. The build fails when:
- The application isn't listed under
applicationsinmicrofrontends.json. - The application's name in
microfrontends.jsondoesn't match its Vercel project name. If thepackage.jsonname differs from the Vercel project name, add apackageNamefield to the application inmicrofrontends.json. See Configuration.
In a polyrepo, the configuration lives in only one repository, so the other applications can't find it unless you give them access:
- Pull the configuration into the application with
vercel microfrontends pull, which writes it to the application's.verceldirectory. See Accessing the configuration file. - Or set the
VC_MICROFRONTENDS_CONFIGenvironment variable to the path of the configuration file. - If the configuration uses a custom file name, set
VC_MICROFRONTENDS_CONFIG_FILE_NAME. See File naming.
Add any environment variables to every project in the microfrontends group so they apply during each build.
See debug routing for how to enable debug logs to see where and why the local proxy routed the request.
To validate where requests are being routed to in production, follow these steps:
- Verify that the path is covered by the microfrontends routing configuration.
- Inspect the debug headers or view a page trace to verify the expected path was matched.
Pages Router pages that use getStaticProps or getServerSideProps rely on
/_next/data/...json requests during client-side navigation. If Pages Router
support or the required proxy and routing behavior is missing, the page can work
on direct load but fail when you navigate to it from another microfrontend. This
can happen when navigating from an App Router page to a Pages Router page.
Check for these symptoms:
/_next/datarequests return a404response./_next/datarequests route to the wrong microfrontend.- The page loads stale or incorrect data after navigation.
For any Next.js microfrontend that uses the Pages Router, enable
supportPagesRouter in withMicrofrontends().
See Set up microfrontends with your framework.
Use this checklist before promoting a microfrontends change that includes any Next.js Pages Router routes:
- Test a direct page load.
- Test client-side navigation from another microfrontend into the Pages Router page.
- Test navigation from App Router pages to Pages Router pages.
- Test Pages Router pages that use
getStaticProps. - Test Pages Router pages that use
getServerSideProps. - Inspect network requests for
/_next/data. - Test through the local microfrontends proxy.
- Test on a Preview deployment.
Was this helpful?