UmiJS 学习笔记 - 服务器端渲染(SSR)


prtyaa
prtyaa 2023-12-26 17:33:00 63387
分类专栏: 资讯

UmiJS 作为一个企业级前端应用框架,不满足于只做于客户端渲染,它也支持服务器端渲染和预渲染。

首先介绍一下三者的区别:

  • 客户端渲染:浏览器在收到服务器发来的 HTML, JS, CSS 等文件后,内置的 JS 引擎解析 JS 文件内容生成 DOM 结构并最终渲染给用户。
  • 服务器端渲染:服务器在接收到客户端的网络请求后,读取所需的数据然后完成页面的 HTML 字符串拼接,并发给送浏览器。
  • 预渲染:使用 Umi 提供的工具在构建时把渲染后的 HTML 生成静态 HTML 文件,可以理解为静态 HTML 文件生成。

如何启用服务器端渲染?

此功能默认关闭,需要通过配置开启,可以修改项目根目录中的 .umirc.ts 增加 ssr 配置项:

export default {
  ssr: {},
}

执行 umi dev 访问的页面即是服务器端渲染后的。可以查看网页源代码,如果 <div id="root"> DOM 里的元素不为空,则是 SSR。

此时是借助于 devServer 实现的服务器端渲染,如果配合后端开发框架一起使用时,可以配置关闭 umi dev 下的服务器端渲染行为:

export default {
  ssr: {
    // 默认为 true
    devServerRender: false,
  },
}

如何配合其他服务器端框架使用?

在上个步骤我们了解了如何关闭默认的服务器端渲染行为,如果我们想借助于其他框架实现服务器端渲染呢?

Umi 服务器端的渲染不耦合某个服务器端框架,你可以使用熟悉的框架来实现这个过程,例如 Express, Koa 等。

以 Koa 为例

app.use(async (ctx) => {
  const { request: req, response: res } = ctx;
  // 或者从 CDN 上下载到 server 端
  // const serverPath = await downloadServerBundle('http://cdn.com/bar/umi.server.js');
  const render = require('./dist/umi.server');
  res.set('Content-Type', 'text/html');

  const context = {};
  const { html, error, rootContainer } = await render({
    // 有需要可带上 query
    path: req.url,
    context,

    // 可自定义 html 模板
    // htmlTemplate: defaultHtml,

    // 启用流式渲染
    // mode: 'stream',

    // html 片段静态标记(适用于静态站点生成)
    // staticMarkup: false,

    // 扩展 getInitialProps 在服务端渲染中的参数
    // getInitialPropsCtx: {},

    // manifest,正常情况下不需要
  });

  ctx.body = html
});

在上述的代码中,Umi 的渲染功能会返回一个拼接完成后的 HTML 字符串(没有报错的理想情况下),然后交由 Koa 提供给浏览器端。

小提示:配合其他开发框架使用时,如果在浏览器中渲染时遇到 js 等静态资源文件加载失败时,请检查资源所在端口或域名是否正确,可以指定 publicPath 配置项。

如何在服务器端获取数据?

既然是服务器端渲染,那么获取数据是必不可少的一个步骤。例如我们想从一个 API 服务器查询获取数据,然后展示在页面中。

在 Umi 中有两种方式:

  • 页面级别数据获取
  • 在 Node.js 中查询 API 获取数据(可以在开发框架中来执行)

假设我们的 API 地址是 `jsonplaceholder.typicode.com`,它的内容如下:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

首先来看第一种方式,Umi 支持页面级数据预获取,这点非常方便。

每个页面可能有单独的数据预获取逻辑,它会获取页面组件上的 getInitialProps 静态方法,执行后将结果注入到该页面组件的 props 中,例如:

function IndexPage(props) {
  const {
    todoData: {
      title = ''
    }
  } = props;
  return (
    <div>
      <h1 className={styles.title}>{title}</h1>
    </div>
  );
}

IndexPage.getInitialProps = async (ctx) => {
    // 发起 API 请求查询
    const result = await fetch(`https://jsonplaceholder.typicode.com/todos/1`).then(res => res.json());
    return {
      todoData: result
    }
};

export default IndexPage;

接下来我们看看第二种方式,继续以 Koa 为例,修改上述代码:

app.use(async (ctx) => {
  const { request: req, response: res } = ctx;
  // 或者从 CDN 上下载到 server 端
  // const serverPath = await downloadServerBundle('http://cdn.com/bar/umi.server.js');
  const render = require('./dist/umi.server');
  res.set('Content-Type', 'text/html');

  const context = {};
  // 发起 API 请求查询
  const result = await fetch(`https://jsonplaceholder.typicode.com/todos/1`).then(res => res.json());
  const { html, error, rootContainer } = await render({
    // 有需要可带上 query
    path: req.url,
    context,

    // 可自定义 html 模板
    // htmlTemplate: defaultHtml,

    // 启用流式渲染
    // mode: 'stream',

    // html 片段静态标记(适用于静态站点生成)
    // staticMarkup: false,

    // 扩展 getInitialProps 在服务端渲染中的参数
    getInitialPropsCtx: {
      todoData: result
    },

    // manifest,正常情况下不需要
  });

  ctx.body = html
});

上述代码首先发起查询,获得数据后使用 getInitialPropsCtx 把查询到的数据扩展到 ctx 中。

在使用的时候,在页面组件的 getInitialProps 中即可使用这个参数了,注意只有在服务器端执行时才有此函数:

function IndexPage(props) {
  const {
    todoData: {
      title = ''
    }
  } = props;
  return (
    <div>
      <h1 className={styles.title}>{title}</h1>
    </div>
  );
}

IndexPage.getInitialProps = async (ctx) => {
  const { isServer, todoData } = ctx;
  if (isServer) {
    return {
      todoData
    }
  }
  return {};
};

这两种方式各有其使用场景,对于多个页面公共的数据可以采用第二种方式;对于各个页面单独的数据通过第一种方式更灵活。

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=30931
赞同 0
评论 0 条
prtyaaL0
粉丝 1 发表 2554 + 关注 私信
上周热门
银河麒麟添加网络打印机时,出现“client-error-not-possible”错误提示  1448
银河麒麟打印带有图像的文档时出错  1365
银河麒麟添加打印机时,出现“server-error-internal-error”  1151
统信桌面专业版【如何查询系统安装时间】  1073
统信操作系统各版本介绍  1070
统信桌面专业版【全盘安装UOS系统】介绍  1028
麒麟系统也能完整体验微信啦!  984
统信【启动盘制作工具】使用介绍  627
统信桌面专业版【一个U盘做多个系统启动盘】的方法  575
信刻全自动档案蓝光光盘检测一体机  484
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

添加我为好友,拉您入交流群!

请使用微信扫一扫!