在现有 React 应用程序中逐渐 Next.js 采用

Gradual Next.js adoption from within existing React application

我正在尝试寻找任何示例来概述如何采用现有的 React 应用程序并逐渐开始向 Next.js 迁移。我已经阅读了所有关于增量采用策略(例如子路径、重写、微前端、代理)的 Next.js 文档,但还没有找到一个可靠的例子来展示这在现实生活中的实际情况“我已经有了一个庞大的 React 代码库”场景。

期望的结果是关闭我现有应用程序的子路径,比如 /workshop,并让 /workshop 成为 Next.js 应用程序的入口点。然后我希望能够在这两个应用程序之间无缝导航,尽管一旦您进入 Next.js 领域并需要导航回代理之外,这种机制似乎很模糊。

为了增加上下文,React 和 Next.js 应用程序都将在 Netlify 上提供服务。我已经仔细阅读了他们的文档以及 Vercel 的文档,寻找一个有效的示例,但我仍然不走运。非常感谢任何关于如何最好地解决此类问题的知识或指导!

对于那些感兴趣的人,我能够创建一个工作演示。

https://hybrid-next-react.vercel.app/

https://github.com/coloradocolby/hybrid-next-react

它的工作方式相当简单。这是一个基本的 Next.js 应用程序,具有 [...app].js 的捕获所有路由,它服务于 React SPA 的入口点。一个简单的 isMounted 变量(可以很容易地重构为一个钩子)确保服务器永远不会处理 React SPA(可能具有特定于浏览器的代码)。

import { useEffect, useState } from "react";
import CreateReactAppRoot from "../src/App";

const App = () => {
  const [isMounted, setIsMounted] = useState(false);

  useEffect(() => {
    setIsMounted(true);
  }, []);

  // Don't render client-side app unless window is available.
  // NOTE: Page not statically pre-rendered nor server-side renderable
  return isMounted ? <CreateReactAppRoot /> : null;
};

export default App;

最后一步是确保实现从 React SPA 到任何用于 Next.js 的路由的整页重新加载。这确保了 Next.js 路由机制被触发。在上面的演示中,我创建了 Next.js 和 React 特定的导航栏。

import React from "react";
import Link from "next/link";
import { useRouter } from "next/router";

export const NextNavbar = () => {
  const router = useRouter();
  return (
    <nav>
      {!router.pathname.includes("[...app]") && (
        <ul className="flex p-4">
          <li className="mr-3">
            <Link href="/" passHref>
              <div className="inline-block px-4 py-2 rounded cursor-pointer">
                Home
              </div>
            </Link>
          </li>
          ...
        </ul>
      )}
    </nav>
  );
};

再一次,虽然 Next.js 可以智能地 link 到 React SPA,因为我们的 catch all 路由,React SPA 需要整页重新加载到任何用于 Next.js 的路由.如您所料,如果目标路由要保留在 React SPA 内,则没有必要。

import React from "react";
import { Link } from "react-router-dom";

export const ReactNavbar = () => (
  <nav>
    <ul className="flex p-4">
      <li className="mr-3">
        <a href="/">
          <div className="inline-block px-4 py-2 rounded cursor-pointer">
            Home
          </div>
        </a>
      </li>
      ...
      <li className="mr-3">
        <Link to="/faq">
          <div className="inline-block px-4 py-2 rounded cursor-pointer">
            FAQ
          </div>
        </Link>
      </li>
      ...
    </ul>
  </nav>
);

此设计的一个重要警告是,如果 CreateReactApp 具有全局 css 导入,它将无法工作,因为 Next.js 需要在 _app.js 文件中导入所有全局样式. From their documentation:

Due to the global nature of stylesheets, and to avoid conflicts, you may only import them inside pages/_app.js.

我想你可以通过在不同的主机上提供 Next.js 和 React SPA 并在两者之间进行代理来解决这个问题(注意:这需要在 catch-all 路由中自定义外部路由),但是它可能比它的价值更麻烦。更简单的解决方案可能只是将全局 CSS 重构为 CSS modules.