前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >54. 精读《在浏览器运行 serverRender》

54. 精读《在浏览器运行 serverRender》

作者头像
黄子毅
发布2022-03-14 16:14:18
3880
发布2022-03-14 16:14:18
举报
文章被收录于专栏:前端精读评论

本周精读内容是 《在浏览器运行 serverRender》。

这里是效果页,先睹为快:client-ssr。

1 引言

在服务端 ssr 成为常识的今天,前端 ssr 是我最近的新尝试,效果可以点击上面链接查看。说说前端 ssr 有哪些好处:

  1. 不消耗服务器资源。对,不消耗服务器资源,完美的分布式运行!对于百万 UV 甚至更高的页面,服务器成本减少了几十万或者上百万。
  2. 前后端分离,首先 ssr 不需要部署服务器,其次前端代码也不需要担心质量问题导致的内存泄露了,同时可以不必时刻注意使用同构的三方库,只需要考虑前端可运行!
  3. 不需要后端缓存服务,对于千人千面的复杂页面,对后端 ssr 来说缓存规模庞大的无法计算。
  4. 相比后端 ssr,在前端可以绕过复杂的权限系统,同时 http 请求的权限问题也无需关心。
  5. 因为第一点,对于不支持后端服务的 github pages 也能做到 ssr。

相对的,缺点是:

  1. 需要客户端支持 serviceWorker。
  2. 第二次首屏才会生效。后端 ssr 可以做到访问前预缓存 ssr 结果。
  3. 可能破坏前端页面状态,因为在同一个环境偷偷执行了一些页面逻辑。不过这个缺点可以通过 web worker 执行 ssr 解决,还在调研中。
  4. service worker 拦截入口 html 风险很高,一旦代码有故障可能导致严重后果,需要提前考虑完备的回滚方案。

像缓存清空时机等问题,前后端 ssr 都会遇到,所以不列在优缺点中。

2 精读

本篇精读分享的是前端 ssr 方案具体实现步骤。

我们先了解整体流程:

service worker 拦截首页

service worker 可以在浏览器尝试请求首屏 html 之前的时机拦截,此时如果 caches 命中,直接将 response 扔给浏览器,那么服务端将完全不会收到请求,完成了最高效的缓存命中。

当然第一次没有缓存,所以在没有命中缓存时,会同步的做两件事:

  1. 发送请求,拿到后端返回的 response,扔给浏览器。这是最普通的请求逻辑。
  2. 当前端代码 ready 后,postMessage 给浏览器,索要 ssr 内容。

附上代码片段:

代码语言:javascript
复制
self.addEventListener("fetch", event => {
  if (
    event.request.mode === "navigate" &&
    event.request.method === "GET" &&
    event.request.headers.get("accept").includes("text/html")
  ) {
    event.respondWith(
      caches.open(SSR_BUNDLE_VERSION).then(cache => {
        return cache.match(event.request).then(response => {
          // 命中缓存,直接返回结果。
          if (response) {
            return response;
          }
          return fetch(event.request).then(response => {
            const newResponse = response.clone();
            return newResponse
              .text()
              .then(text => {
                // 通知浏览器,执行 ssr 并且返回内容。
                self.clients.matchAll().then(clients => {
                  if (!clients || !clients.length) {
                    return;
                  }
                  clients.forEach(client => {
                    client.postMessage({
                      type: "getServerRenderContent",
                      pathname: new URL(event.request.url, location).pathname
                    });
                  });
                });

                return response;
              })
              .catch(err => response);
          });
        });
      })
    );
  }
});

当然还需要一个监听,用来拿浏览器的 ssr 内容,并缓存到 caches 中,比较简单就省略了。

浏览器执行 ssr

监听就不说了,主要是如何利用 react-routerreact-loadable 完成前端 ssr。

首先根据 service worker 告诉我们的 pathname,拿到对应 loadable 的实例,并通过 loadable.preload() 预先加载 chunk,当 chunk 加载完毕时,资源已经准备好了。

我们利用给 StaticRouter 传递当前的 pathname,让 react-router 模拟出需要 ssr 的页面内容,通过 renderToString 拿到 ssr 的结果。

附上代码片段:

代码语言:javascript
复制
if (navigator.serviceWorker) {
  navigator.serviceWorker.addEventListener("message", event => {
    if (event.data.type === "getServerRenderContent") {
      const baseHrefRegex = new RegExp(
        escapeRegExp("${projectConfig.baseHref}"),
        "g"
      );
      const matchRouterPath = event.data.pathname.replace(baseHrefRegex, "");
      const loadableMap = pageLoadableMap.get(
        matchRouterPath === "/" ? "/" : trimEnd(matchRouterPath, "/")
      );
      if (loadableMap) {
        loadableMap.preload().then(() => {
          const ssrResult = renderToString(
            <StaticRouter location={event.data.pathname} context={{}}>
              <App />
            </StaticRouter>
          );

          if (navigator.serviceWorker.controller) {
            navigator.serviceWorker.controller.postMessage({
              type: "serverRenderContent",
              pathname: event.data.pathname,
              content: ssrResult
            });
          }
        });
      }
    }
  });
}

这里需要优化,利用 web worker 执行 ssr 才可以用于生产环境。

最后,等待用户的下一次刷新,service worker 会帮我们把 ssr 内容作为首屏给用户一个惊喜的。

3 总结

同样这次只是抛砖引玉,希望大家能提出建议一起帮助我们完善这个方案。

此方案正式用在生产环境后,会再写一篇文章介绍实践过程。

4 更多讨论

讨论地址是:精读《在浏览器运行 serverRender》 · Issue #80 · dt-fe/weekly

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端精读评论 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 引言
  • 2 精读
    • service worker 拦截首页
      • 浏览器执行 ssr
      • 3 总结
      • 4 更多讨论
      相关产品与服务
      云服务器
      云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档