卷起来,前端建站SSG,SSR,ISR,Hydration, Island...一网打尽

React, Vue, Angular 三足鼎立之后,前端界又开始“卷起来了”,不过战火已经单页渲染蔓延到了服务端渲染建站。

NextJs成名已久,功能全面,astro Island 独步天下,qwik No hydration 异军突起。remix 守正出奇,无招胜有招。

今天我们来一块说道说道。

让建站酷起来

SSR

SSR (server-side rendering)相对比较好理解,它算是是SPA大行其道之前主流的方式,简单来说就是服务端,拉取数据组装页面,返回前端HTML。

这种方式优点在于简单直接,每次访问都能够拿到最新数据。但缺点是有点费网,如果流量大,用户分布广就需要费不少功夫优化,这里不再展开。

SSG

SSG(static site generation)顾名思义,就是提前生成静态的网站。优点是性能好,HTML推送到CDN,成本体验也是最佳。这里的问题是适用场景有限,一般用作内容不太变化的场景。

ISR

ISR(Incremental Static Regeneration)渐进式的静态内容生成。应该是NextJS的首创,从一定程度上优化了SSG了的问题。简单来说就是提供一种机制能够在server中自动的执行SSG,这点优点也很明显,一是能够让内容尽量保持新鲜,而是从访问行为上仍然保持静态访问。

照搬next的思路,有两种方式:

轮训式刷新

简单来说就是类似js setInterval的方式按照一定是时间段刷新server端的构建。

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most once every 10 seconds
    revalidate: 10, // In seconds
  }
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// the path has not been generated.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: blocking } will server-render pages
  // on-demand if the path doesn't exist.
  return { paths, fallback: 'blocking' }
}

export default Blog

按需刷新

而按需的方式是算是NextJS对上述方式的优化。机制server 对外提供http的API。内容变动调用这个API就好。

// pages/api/revalidate.js

export default async function handler(req, res) {
  // Check for secret to confirm this is a valid request
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Invalid token' })
  }

  try {
    // this should be the actual path not a rewritten path
    // e.g. for "/blog/[slug]" this should be "/blog/post-1"
    await res.revalidate('/path-to-revalidate')
    return res.json({ revalidated: true })
  } catch (err) {
    // If there was an error, Next.js will continue
    // to show the last successfully generated page
    return res.status(500).send('Error revalidating')
  }
}

当然ISR仍然是SSG的范畴,复杂场景仍然无法应对。

Edge Rendering

这个严格来说是站点的部署形态,算是新时代边缘计算的一种应用场景。类似以前静态的资源推送到CDN,让用户能够就近享受最佳的体验。现在动态网站也能够在边缘渲染,让用户享受到更佳的体验。

这里的问题仍在在于数据,除非是经过特意的改造,一般网站的数据仍需要请求到一个中心化的源服务中。

image.png

一方面用户体验仍然不佳,另一方面源服务压力仍然巨大,成本不低。

上面NextJs的ISR或多或少也是为了解决这个问题。当然另一个更彻底的思路,在边缘的节点上也能有数据持久化的能力,例如cloudflare,或者使用一些分布式的数据库,这里不再展开。

酷的“代价”

这些更现代的建站方式确实很炫酷,但是也不是没有缺点。一点就是页面数据会变大(移动站点不太友好),另一方面首次可交互时间也会延后。

这里实际上就涉及Hydration注水的概念。

Hydration

Hydration注水,大家可能较少听到,但是它却是现代前端spa,mpa同构框架的关键。

同一份代码,先server端跑生成一份一定状态计算后的HTML,然后需要在前端“活过来”的过程大概就称之为注水了。

这里不同的框架实现的细节不同,但是通用的问题是,事件在注水之后才能交互。页面越复杂这段时间越长,越影响体验,这点也是各大框架大显身手的地方。

Selective Hydration

渐进可选式的注水,这里的代表就是大名鼎鼎的React,借助于fiber架构,React能够打断传统递归式的注水,让应用能够优先处理交互事件,这里框架层面比较复杂,具体效果怎么样也有待观察。

Islands Architecture

Islands Architecture隔离交互组件。astro框架首打的特性。

image.png

这里理解也比较简单,让静态页面保持静态,只让页面上需要复杂交互的才去走注水的那一套,保持交互性。

无交互场景

---
// Example: Use a static React component on the page, without JavaScript.
import MyReactComponent from '../components/MyReactComponent.jsx';
---
<!-- 100% HTML, Zero JavaScript loaded on the page! -->
<MyReactComponent />

有交互的场景。

---
// Example: Use a dynamic React component on the page.
import MyReactComponent from '../components/MyReactComponent.jsx';
---
<!-- This component is now interactive on the page! 
     The rest of your website remains static and zero JS. -->
<MyReactComponent client:load />

No hydration

最快的注水,就是无注水?。这就是qwik 框架的主要卖点。

const Counter = component$(() => {
  const store = useStore({
    htmlCount: 0,
    cmpCount: 0,
  });

  return (
    <div>
      <button onClick$={() => store.htmlCount++}>{store.htmlCount}</button>
      <CmpButton onClick$={() => store.cmpCount++}>{store.cmpCount}</CmpButton>
    </div>
  );
});

语法和react类似,区别于$的标注,框架依赖这些标注,在构建的时候会将这些组件或者逻辑代码独立成单个js。

<div>
  <button q:obj="1" on:click="./chunk-a.js#Counter_button_onClick[0]">0</button>
  <div>...</div>
</div>

事件在点击之后或者prefetch,才会懒加载对应的js。以此来实现无注水。

没噱头的remix

remix 是react-router团队的新作。

Focused on web standards and modern web app UX, you’re simply going to build better websites

从介绍上来看似乎没什么噱头,但似乎这就是它们最大的卖点。坚持标准的语法,只使用经典有效的手段。从remix-vs-next的文章来看效果确实不错,守正出奇。

上面只是蜻蜓点水介绍了现代框架中比较新潮点。每个地方深挖下去都有不错的收获。花拳百出,核心都是为了提高开发体验,增强用户体验。


参考

本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
卷起来,前端建站SSG,SSR,ISR,Hydration, Island...一网打尽
React, Vue, Angular 三足鼎立之后,前端界又开始“卷起来了”,不过战火已经单页渲染蔓延到了服务端渲染建站。
<<上一篇
下一篇>>