Reputation: 336
I have 2 projects.
Project A is written with React but does not use the Next.js framework. It is intended to be served as a headless UI library, allowing any project that imports it to access its components.
Project B is written with React and utilizes the Next.js framework. This project serves as the website's frontend and is the primary focus.
I am attempting to create a link component in Project A that behaves like next/link when imported into Project B.
I have tried solution provided here but but it did not work as expected.
I understand that in Next.js, it's crucial to consider both client-side and server-side rendering. I am seeking an approach that can accommodate both scenarios.
The codes I have tried is as below (from Project A - The headless ui project):
const Link = (props: LinkProps) => {
try {
return createElement(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
require.resolve("next/link").default,
props,
props.children
);
} catch (e) {
console.log("error getting nextLinkPath or create element", e);
return createElement("a", props, props.children);
}
};
export default Link;
When implementing this code into Project B (which uses Next js framework), I encountered an error stating
ReferenceError: require is not defined
,
when used in a client side component. When used in a server side component, it shows that require.resolve("next/link").default
is undefined.
I have also tried using import
const Link = (props: LinkProps) => {
loadNextComponent(props).then((component) => {
return component;
});
};
const loadNextComponent = async (props: LinkProps) => {
try {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
const NextLink = (await (import(/* @vite-ignore */ "next/link") as any)
.default) as string;
return createElement(NextLink, { ...props }, props.children);
} catch (error) {
console.error("Error loading next component:", error);
return <a {...props}>{props.children}</a>;
}
};
The implementation did not work as intended, and it became worse because I couldn't catch errors caused by the import statement during Project A runtime. I have received error stating
[vite] Internal server error: Failed to resolve import "next/link" from "src/components/atoms/Link/Link.tsx". Does the file exist?
I also received this error when implemented into project B
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
In summary, how can I dynamically call next/link component in a react library that does not use nextjs framework, so that it will served as next/link when imported into any project where next/link is available?
Upvotes: 0
Views: 168
Reputation: 1
Same requirments, this works for me:
import { Link as ReactRouterLink } from 'react-router-dom';
import dynamic from 'next/dynamic';
export default function BaseLink({ href, target, className, dataTestId, children }: Props) {
if (typeof process !== 'undefined') {
const NextLink = dynamic(() => import('next/link'));
return (
<NextLink href={href} className={className} data-testid={dataTestId} target={target}>
{children}
</NextLink>
);
}
return (
<ReactRouterLink to={href} className={className} data-testid={dataTestId} target={target}>
{children}
</ReactRouterLink>
);
}
Upvotes: 0