Where to import 'reflect-metadata' in Next.js 14.1.0

391 Views Asked by At

I'm trying to use tsyringe for dependency injection in my Next.js 14.1.0 app. I'm using the new App Router. But for some reason it isn't working correctly when doing import 'reflect-metadata'; at the top of my Root Layout..

It's still throwing the following error on some pages:

Uncaught (in promise) Error: tsyringe requires a reflect polyfill. Please add 'import "reflect-metadata"' to the top of your entry point.

Any ideas where should I import this polyfill? I thought the Root Layout was Next.js 14 entry point but it seems it ain't.

3

There are 3 best solutions below

7
Techno Verse On

Firstly, it would be great if you could share your code and why you want to use dependency injection. Probably, there could be better and cleaner way to do what you want to do.

However, if you must use dependency injection, try following

// app/layout.tsx
import 'reflect-metadata';
import ClientLayoutComponent from '@/app/ClientLayoutComponent';

export default function RootLayout({
  children
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <ClientLayoutComponent />
        {children}
      </body>
    </html>
  );
}
// app/ClientLayoutComponent.ts
'use client';

import 'reflect-metadata';

export default function ClientLayoutComponent(): null {
  return null;
}

Reference - https://github.com/vercel/next.js/discussions/46805#discussioncomment-8261261

You may be facing issues with app router because of the React Server components. By above approach we make sure we are importing the library on client side as well.

6
Damzaky On

I think the problem was that the polyfill is required to be injected to the entry point of client part of your code, and it seems like root layout is server side, so what you need to do is to import the polyfill in the client side. One idea is to wrap the root children with a <ClientRoot> component:

// ClientRoot.tsx, the children wrapper
"use client";
import React from "react";

import "reflect-metadata"; // add polyfill in client side

export default function ClientRoot({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return <>{children}</>;
}

Then update the root layout file to this:

// layout.tsx, entry point
import "reflect-metadata"; // add polyfill in server side
import ClientRoot from "./ClientRoot";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <ClientRoot>{children}</ClientRoot>
      </body>
    </html>
  );
}

Tested this in my local machine with next 14.1.0, and it works.

0
Dinesh Basnet On

In a Next.js application, the entry point is typically the _app.tsx file located in the pages directory. This file is responsible for initializing your application and serves as the wrapper component for all pages.

To ensure that reflect-metadata is imported at the correct entry point, you should add the import statement import "reflect-metadata"; at the top of your _app.tsx file. This ensures that the polyfill is loaded before any other code in your application.

Here's an example of how you can modify your _app.tsx file:

// _app.tsx

import 'reflect-metadata'; // Import the reflect-metadata polyfill
import { AppProps } from 'next/app';

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default MyApp;