介绍 NEXT.js 的替代方案

2025-06-10

介绍 NEXT.js 的替代方案

介绍

当我们开发 React 应用程序时,分离服务器和客户端是最好的选择之一。

但在这些情况下,我们必须在服务器端为客户端实现很多 API。

另一方面,像 handlebars 或 ejs 这样的服务器渲染视图的传统方法并不适用于 React 单页应用程序或服务器端渲染应用程序。

虽然不可能像 Express 服务器那样使用 NEXT.js 作为视图模板引擎,但需要一些像这样的技巧:

// pages/index.tsx

const IndexPage = ({ articles }) => {
  return (
    <ul>
      {articles.map((article, index) => (
        <li key={index}>{article.title}</li>
      ))}
    </ul>
  );
};

// we must use `getInitialProps()` to enable SSR correctly
IndexPage.getInitialProps = async ({ req, query }) => {
  const isServer = !!req;

  // and we have to check a process is a server or not
  let articles;
  if (isServer) {
    // if the server side, we can receive data from the server directly
    articles = query.articles;
  } else {
    // if the client side, we must fetch data from the API server
    articles = await http.get('api/articles');
  }

  // finally, we can use data in the `IndexPage` component like above
  return {
    articles,
  };
};
Enter fullscreen mode Exit fullscreen mode

您是否曾想过这样的实现方式?

// server.js

const express = require('express');

const app = express();

app.get('/', (req, res) => {
  const message = 'Hello World!';
  res.render('index', { message });
});

app.listen(3000, () => {
  console.log('> Ready on http://localhost:3000');
});
Enter fullscreen mode Exit fullscreen mode
// views/index.jsx

export default function IndexPage{ message }) {
  return <p>{message}</p>;
}
Enter fullscreen mode Exit fullscreen mode

如果我们可以通过 SSR 看到“Hello World”呢?

让我们想象一下!

// server.js

const posts = [
  { id: 1, body: 'This is a first post.' },
  { id: 2, body: 'This is a second post.' },
  { id: 3, body: 'This is a last post.' },
];

app.get('/', (req, res) => {
  res.render('index', { posts });
});

app.get('/posts/:postId', (req, res) => {
  const { postId } = req.params;
  const post = findById(postId);
  res.render('post', { post });
});
Enter fullscreen mode Exit fullscreen mode
// views/index.jsx

import React from 'react';

const IndexPage = ({ posts }) => {
  return (
    <React.Fragment>
      {posts.map((post, index) => {
        return (
          <p key={index}>
            <a href={'/posts/' + post.id}>{post.body}</a>
          </p>
        );
      })}
    </React.Fragment>
  );
};

export default IndexPage;
Enter fullscreen mode Exit fullscreen mode
// views/post.jsx

import React from 'react';

const PostPage = ({ post }) => {
  return (
    <React.Fragment>
      <p>{post.body}</p>
    </React.Fragment>
  );
};

export default PostPage;
Enter fullscreen mode Exit fullscreen mode

这够简单了吧?

我们可以将 React 当作视图模板引擎来使用!

关于react-ssr

GitHub 徽标 saltyshiomix / react-ssr

React SSR 作为视图模板引擎

概述

  • SSR(服务器端渲染)作为视图模板引擎
  • 动态的props
    • 将服务器数据传递给 React 客户端props
    • 适合
      • 管理面板
      • 博客
  • 开发者体验
    • webpack 和 babel 零配置
    • HMR(热模块替换)脚本和样式process.env.NODE_ENV !== 'production'
    • 内置 Sass(SCSS)支持

优点和缺点

优点

因为它只是一个视图模板引擎:

  • 它不需要任何 API,我们所要做的就是将服务器数据传递给客户端
  • 它支持多种引擎,如.hbs.ejs和 React.(ts|js)x
  • 我们可以像往常一样使用护照认证

缺点

  • 它的性能不太好,因为它在每次请求时都会组装整个 HTML
  • 不支持客户端路由

用法

使用 @react-ssr/express

安装:

$ npm install --save @react-ssr/core @react-ssr/express express react react-dom
Enter fullscreen mode Exit fullscreen mode

并将脚本添加到你的 package.json 中,如下所示:

Enter fullscreen mode Exit fullscreen mode

概述

  • 将服务器数据传递给 React 客户端props
    • 因此它的反应就像是一个视图模板引擎
    • 当然,它通过使用服务器端渲染针对搜索引擎进行了优化
  • 开发者体验
    • 它使用起来非常简单,几乎不需要学习如何使用
    • HMR(热模块更换)process.env !== 'production'

如何使用react-ssr

Express 应用程序有三个 npm 包:

@react-ssr/express在 JavaScript 中的使用

安装:

$ npm install --save @react-ssr/core @react-ssr/express express react react-dom
Enter fullscreen mode Exit fullscreen mode

package.json

{
  "scripts": {
    "start": "node server.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

并在您的项目中填充以下文件:

.babelrc

{
  "presets": [
    "@react-ssr/express/babel"
  ]
}
Enter fullscreen mode Exit fullscreen mode

server.js

const express = require('express');
const register = require('@react-ssr/express/register');

const app = express();

(async () => {
  // register `.jsx` as a view template engine
  await register(app);

  app.get('/', (req, res) => {
    const message = 'Hello World!';
    res.render('index', { message });
  });

  app.listen(3000, () => {
    console.log('> Ready on http://localhost:3000');
  });
})();
Enter fullscreen mode Exit fullscreen mode

视图/index.jsx

export default function IndexPage({ message }) {
  return <p>{message}</p>;
}
Enter fullscreen mode Exit fullscreen mode

就是这样!

然后只需运行npm start并前往http://localhost:3000,您就会看到Hello World!

@react-ssr/expressTypeScript 中的用法

要启用 TypeScript 引擎(.tsx),只需将其tsconfig.json放入项目根目录即可。

TypeScript 的代码如下:

package.json

{
  "scripts": {
    "start": "ts-node server.ts"
  }
}
Enter fullscreen mode Exit fullscreen mode

server.ts

import express, { Request, Response } from 'express';
import register from '@react-ssr/express/register';

const app = express();

(async () => {
  // register `.tsx` as a view template engine
  await register(app);

  app.get('/', (req: Request, res: Response) => {
    const message = 'Hello World!';
    res.render('index', { message });
  });

  app.listen(3000, () => {
    console.log('> Ready on http://localhost:3000');
  });
})();
Enter fullscreen mode Exit fullscreen mode

views/index.tsx

interface IndexPageProps {
  message: string;
}

export default function IndexPage({ message }: IndexPageProps) {
  return <p>{message}</p>;
}
Enter fullscreen mode Exit fullscreen mode

用法@react-ssr/nestjs-express

安装:

# install NestJS dependencies
$ npm install --save @nestjs/core @nestjs/common @nestjs/platform-express

# install @react-ssr/nestjs-express
$ npm install --save @react-ssr/core @react-ssr/nestjs-express react react-dom
Enter fullscreen mode Exit fullscreen mode

package.json

{
  "scripts": {
    "start": "ts-node --project tsconfig.server.json server/main.ts"
  }
}
Enter fullscreen mode Exit fullscreen mode

然后,在您的项目中填充以下文件:

.babelrc

{
  "presets": [
    "@react-ssr/nestjs-express/babel"
  ]
}
Enter fullscreen mode Exit fullscreen mode

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "preserve",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "strict": true,
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true
  },
  "exclude": [
    "node_modules",
    "ssr.config.js",
    ".ssr"
  ]
}
Enter fullscreen mode Exit fullscreen mode

tsconfig.server.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs"
  },
  "include": [
    "server"
  ]
}
Enter fullscreen mode Exit fullscreen mode

server/main.ts

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import register from '@react-ssr/nestjs-express/register';
import { AppModule } from './app.module';

(async () => {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // register `.tsx` as a view template engine
  await register(app);

  app.listen(3000, async () => {
    console.log(`> Ready on http://localhost:3000`);
  });
})();
Enter fullscreen mode Exit fullscreen mode

server/app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';

@Module({
  controllers: [
    AppController,
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

server/app.controller.ts

import {
  Controller,
  Get,
  Render,
} from '@nestjs/common';

@Controller()
export class AppController {
  @Get()
  @Render('index') // this will render `views/index.tsx`
  public showHome() {
    const user = { name: 'NestJS' };
    return { user };
  }
}
Enter fullscreen mode Exit fullscreen mode

最后,views/index.tsx

interface IndexPageProps {
  user: any;
}

const IndexPage = ({ user }: IndexPageProps) => {
  return <p>Hello {user.name}!</p>;
};

export default IndexPage;
Enter fullscreen mode Exit fullscreen mode

然后,只需运行npm start并转到http://localhost:3000
,您就会看到Hello NestJS!

有很多例子

examples/with-jsx-antd

示例/with-jsx-antd

examples/with-jsx-emotion

示例/with-jsx-emotion

examples/with-jsx-material-ui

示例/with-jsx-material-ui

examples/with-jsx-semantic-ui

示例/with-jsx-semantic-ui

examples/with-jsx-styled-components

示例/带有 jsx 样式的组件

结论

请尝试react-ssr并向我们发送反馈!

最好的,

鏂囩珷鏉ユ簮锛�https://dev.to/saltyshiomix/introducing-an-alternative-to-next-js-12ph
PREV
“Nextron”:Electron + Next.js 之梦
NEXT
使用 JavaScript 创建图像模式!