跳转到内容
understanding astro

第三章

🚀 Understanding Astro 了解Astro

By Ohans Emmanuel 作者:Ohans Emmanuel

Chapter 3: Build Your Own Component Island
第3章构建自己的组件岛

“What I cannot create, I do not understand” — Richard Feynman
“我不能创造的东西,我不理解”—理查德·费曼

Astro’s fast narrative relies on component islands, which allow using other framework components like React, Vue, or Svelte in our Astro applications. This chapter will guide us in creating our own component island from the ground up.
Astro的快速叙述依赖于组件岛,这允许在我们的Astro应用程序中使用其他框架组件,如React,Vue或Svelte。本章将指导我们从头开始创建我们自己的组件岛。

What you’ll learn 您将学到的内容

  • An overview of different web application rendering techniques.
    不同Web应用程序渲染技术的概述。
  • Build your own component islands implementation from scratch.
    从头开始构建您自己的组件岛实现。
  • Comprehend the island architecture.
    了解岛上的建筑。

A brief history of how we got here
我们如何走到这一步的简史

To ensure the coming technical implementation is built on a solid understanding, let’s peep into the past and explore the several application rendering techniques we may employ on a frontend application.
为了确保即将到来的技术实现建立在坚实的理解之上,让我们看看过去,并探索我们可能在前端应用程序上使用的几种应用程序渲染技术。

It is essential to note that this isn’t an exhaustive guide to front-end application rendering. However, we’ll learn enough to understand and appreciate the component islands architecture.
需要注意的是,这并不是一个关于前端应用程序呈现的详尽指南。然而,我们将学到足够的知识来理解和欣赏组件岛的架构。

Where it all begins

一切开始的地方

In simple terms, there are two main actors in serving an application to a user:
简单地说,在向用户提供应用程序时有两个主要参与者:

  1. The user client, e.g., a web browser
    用户客户端,例如,网页浏览器
  2. The application server 应用服务器

To display a website, a user requests a resource from an application server.
为了显示网站,用户从应用服务器请求资源。

The web browser requesting article.html from an application server.

The web browser requesting article.html from an application server.
Web浏览器从应用服务器请求article.html。

With these two actors at play, a significant architectural decision you’ll make when building any decent frontend application is whether to render an application on the client or server1.
有了这两个参与者,在构建任何像样的前端应用程序时,您将做出的一个重要的架构决策是在客户端还是服务器上呈现应用程序 1

Let’s briefly explore both options.
让我们简要地探讨这两种选择。


Client-side rendering (CSR)

客户端渲染(CSR)

Choosing client side rendering.

Choosing client side rendering.
选择客户端渲染。

By definition, a client-side rendered application renders pages directly in the browser using Javascript. All logic, data-fetching, templating and routing are handled on the client (the user’s browser).
根据定义,客户端呈现的应用程序使用JavaScript直接在浏览器中呈现页面。所有逻辑、数据获取、模板和路由都在客户端(用户的浏览器)上处理。

An overview of a client-side rendered application.

An overview of a client-side rendered application.
客户端呈现的应用程序的概述。

The past years saw the rise of client-side rendering, particularly among single-page applications. You’ve likely seen this in action if you’ve worked with libraries like React or Vue.
在过去的几年里,客户端呈现的兴起,特别是在单页面应用程序中。如果您使用过React或Vue等库,您可能已经看到了这一点。

For a practical overview, consider the webpage for a blog article with a like count and a comment section below the initial viewport.
对于一个实用的概述,考虑一个博客文章的网页,该博客文章具有点赞计数和在初始视口下方的评论部分。

A blog article with a dynamic sidebar and a comment section below the article.

A blog article with a dynamic sidebar and a comment section below the article.
一个博客文章,带有动态侧边栏和文章下方的评论部分。

If this application was entirely client-side rendered, the simplified rendering flow would look like this:
如果这个应用程序完全是在客户端渲染的,那么简化的渲染流程将如下所示:

  1. The user visits your website.
    用户访问您的网站。
  2. Your static server returns a near-empty HTML page to the browser.
    静态服务器会向浏览器返回一个几乎空的 HTML 页面。
  3. The browser fetches the linked script file in the HTML page.
    浏览器在 HTML 页面中获取链接的脚本文件。
  4. The Javascript is loaded and parsed.
    加载并解析JavaScript。
  5. The data for the article, number of comments and comments are fetched.
    获取文章的数据、评论和评论的数量。
  6. A fully interactive page is shown to the user.
    向用户显示完全交互的页面。

Visualising the rendering process from a user's perspective.

Visualising the rendering process from a user’s perspective.
从用户的角度可视化渲染过程。

The pros of client-side rendering (CSR)

客户端渲染(CSR)的优点

  • The user gets back the resource from the server quickly. In our case, a near-empty HTML page, but on the bright side, the user receives that quickly! In technical terms, client-side rendering yields a high time to first byte (TTFB)2
    用户可以快速地从服务器取回资源。在我们的例子中,一个几乎空的 HTML 页面,但从好的方面来看,用户很快就收到了!在技术术语中,客户端渲染产生了一个高的第一字节时间(TTFB) 2
  • Arguably accessible to reason about. All logic, data-fetching, templating and routing are handled in one place - the client.
    可论证的可论证的所有逻辑、数据获取、模板和路由都在一个地方处理-客户端。

The cons of client-side rendering

客户端渲染的缺点

  • It potentially takes the user a long time to see anything tangible on our page, i.e., they’re initially met with an empty screen. Even if we change the initial HTML page sent to the browser to be an empty application shell, it still potentially takes time for the user to see eventual data, i.e., after the Javascript is parsed and the data fetched from the server.
    用户可能要花很长时间才能看到我们页面上的任何有形内容,即,他们一开始看到的是一个空白的屏幕。即使我们将发送到浏览器的初始 HTML 页面更改为空的应用程序外壳,用户仍然可能需要时间来查看最终数据,即在解析JavaScript并从服务器获取数据之后。

  • As the application grows, the amount of Javascript parsed and executed before displaying data increases. This can impact mobile performance negatively.
    随着应用程序的增长,在显示数据之前解析和执行的JavaScript数量也会增加。这可能会对移动的性能产生负面影响。

  • The page’s time to interactivity (TTI)3 suffers, e.g., it takes long before our users can interact with the comments. All Javascript must be parsed, and all associated data must be fetched first.
    页面的交互时间(TTI) 3 遭受例如我们的用户需要很长时间才能与评论互动。所有的JavaScript都必须被解析,并且所有相关的数据必须首先被提取。

  • Detrimental SEO if not implemented correctly.
    有害的SEO,如果没有正确实施。


Server-side rendering 服务器端渲染

Choosing server-side rendering.

Choosing server-side rendering.
选择服务器端渲染。

Let’s assume we’re unhappy with client-side rendering and decide to do the opposite.
让我们假设我们对客户端渲染不满意,并决定做相反的事情。

On the opposing end of the rendering pole lies server-side rendering.
在渲染极的另一端是服务器端渲染。

In a server-side rendered application, a user navigates to our site, and the server generates the full HTML for the page and sends it back to the user.
在服务器端呈现的应用程序中,用户导航到我们的网站,服务器为页面生成完整的 HTML 并将其发送回用户。

In our example, here’s what a simplified flow would look like:
在我们的示例中,简化的流程如下所示:

  1. The user visits our website.
    用户访问我们的网站。
  2. The data for the article, user profile and comments are fetched on the server.
    文章、用户配置文件和评论的数据在服务器上获取。
  3. The server renders the HTML page with the article, the number of comments and other required assets.
    服务器呈现具有文章、评论数量和其他所需资产的 HTML 页面。
  4. The server sends the client a fully formed HTML page.
    服务器向客户端发送完整格式的 HTML 页面。

Visualising the rendering process from a user's perspective.

Visualising the rendering process from a user’s perspective.
从用户的角度可视化渲染过程。

NB: it is assumed that the server sends a mostly static HTML page with minimal Javascript needed for interactivity.
注意:假设服务器发送一个大部分静态的 HTML 页面,具有交互性所需的最小JavaScript。

The pros of server-side rendering

服务器端渲染的优点

  • As soon as the user browser receives our fully formed HTML page, they can almost immediately interact with it, e.g., the rendered comments. There’s no need to wait for more Javascript to be loaded and parsed. In performance lingo, the time to interactivity (TTI) equals the first contentful paint (FCP).4
    一旦用户浏览器接收到我们完全形成的 HTML 页面,他们几乎可以立即与它交互,例如,的评论。没有必要等待更多的JavaScript被加载和解析。在性能术语中,交互时间(TTI)等于第一内容绘制(FCP)。 4
  • Great SEO benefits as search engines can index your pages and crawl them just fine.
    搜索引擎优化的好处,因为搜索引擎可以索引你的网页,并抓取它们就好了。

The cons of server-side rendering

服务器端渲染的缺点

  • Generating pages on the server takes time. In our case, we must wait for all the relevant data to be fetched on the server. As such, the time to first byte(TTFB)5 is slow.
    在服务器上生成页面需要时间。在我们的例子中,我们必须等待服务器上获取所有相关数据。因此,到第一字节(TTFB) 5 的时间慢。
  • Resource intensive: the server takes on the burden of rendering content for users and bots. As a result, associated server costs increase as rendering needs to be done on the server.
    资源密集型:服务器承担了为用户和机器人呈现内容的负担。因此,随着渲染需要在服务器上完成,相关的服务器成本增加。
  • Full page reloads for every requested server resource.
    为每个请求的服务器资源重新加载完整页。

Server-side rendering with client-side hydration

服务器端渲染和客户端合成

We’ve explored rendering on both sides of the application rendering pole. However, what if there was a way to use server and client-side rendering? Some strategy right in the middle of the hypothetic rendering pole?
我们已经在应用程序渲染极的两侧探索了渲染。但是,如果有一种方法可以使用服务器端和客户端渲染呢?在假设的渲染极中间的一些策略?

Choosing SSR with client-side hydration.

Choosing SSR with client-side hydration.
选择SSR与客户端水合。

If we were building an interactive application and working with a framework like React or Vue, a widely common approach is to render on the server and hydrate on the client.
如果我们正在构建一个交互式应用程序,并使用像React或Vue这样的框架,一个广泛使用的方法是在服务器上渲染并在客户端上进行水合。

Hydration, in layperson’s terms, means re-rendering the entire application again on the client to attach event handlers to the DOM and support interactivity.
用外行人的话说,水合意味着在客户机上再次重新呈现整个应用程序,以将事件处理程序附加到DOM上并支持交互性。

In theory, this is supposed to give us the wins of server-side rendering plus the interactivity we get with rich client-side rendered applications.
从理论上讲,这应该给予我们带来服务器端渲染的好处,加上丰富的客户端渲染应用程序的交互性。

In our example, here’s what a simplified flow would look like:
在我们的示例中,简化的流程如下所示:

  1. The user visits our website.
    用户访问我们的网站。
  2. The data for the article, user profile and comments are fetched on the server.
    文章、用户配置文件和评论的数据在服务器上获取。
  3. The server renders the HTML page with the article, the number of comments and other required assets.
    服务器呈现具有文章、评论数量和其他所需资产的 HTML 页面。
  4. The server sends the client a fully formed HTML page alongside the Javascript client runtime.
    服务器向客户端发送一个完整的 HTML 页面以及JavaScript客户端运行时。
  5. The client then “boots up” Javascript to make the page interactive.
    然后客户端“启动”JavaScript以使页面具有交互性。

Making an otherwise static page interactive (e.g., attaching event listeners) is called hydration.
使原本静态的页面成为交互式的(例如,附加事件监听器)被称为水合。

Visualising the rendering process from a user's perspective.

Visualising the rendering process from a user’s perspective.
从用户的角度可视化渲染过程。

The pros of server-side rendering with client-side hydration

服务器端渲染与客户端水合的优点

  • Benefits of SSR, e.g., quick FP and FMP
    SSR的好处,例如,快速FP和FMP
  • Can power highly interactive applications.
    可以支持高度交互的应用程序。
  • Supported rendering style in most frontend frameworks such as React and Vue.
    大多数前端框架支持渲染风格,如React和Vue。

The cons of server-side rendering with client-side hydration

服务器端渲染与客户端水合的缺点

  • Slow time to first byte — similar to standard SSR.
    第一个字节的时间慢-类似于标准SSR。
  • It can delay time to Interactivity (TTI) by making the user interface look ready before completing client-side processing. The period where the UI looks ready but is unresponsive (not hydrated) is what’s been — quite hilariously — dubbed the uncanny valley.
    它可以通过在完成客户端处理之前使用户界面看起来准备就绪来延迟交互时间(TTI)。UI看起来准备就绪但反应迟钝(没有水分)的时期被称为“神秘谷”。

NB: this assumes certain parts of our application, such as the likes and comments, can be interacted with, e.g., clicked to perform further action.
NB:这假设我们的应用程序的某些部分,例如喜欢和评论,可以与之交互,例如,单击以执行进一步操作。


Partial hydration for the win

部分水合作用

Combining server-side rendering with client-side hydration has the potential to offer the best of both worlds. However, it is not without its demerits.
将服务器端渲染与客户端水化相结合,有可能实现两全其美。然而,它并非没有缺点。

One way to tackle the heavy delay in time to interactivity (TTI) seems obvious. Instead of hydrating the entire application, why not hydrate only the interactive bits?
解决交互时间(TTI)严重延迟的一种方法似乎显而易见。与其对整个应用程序进行补水,为什么不只对交互位进行补水呢?

Partial hydration vs full-page hydration.

Partial hydration vs full-page hydration.
部分水合vs全页水合。

As opposed to hydrating the entire application client side, partial hydration refers to hydrating specific parts of an application while leaving the rest static.
与对整个应用程序客户端进行水化相反,部分水化指的是对应用程序的特定部分进行水化,同时使其余部分保持静止。

For example, in our application, we’d leave the rest of the page static while hydrating just the like button and comment section.
例如,在我们的应用程序中,我们将保持页面的其余部分静态,而只对喜欢按钮和注释部分进行补水。

We may also take partial hydration further and implement what’s known as lazy hydration. For example, our application has a comment section below the initial viewport.
我们还可以进一步进行部分水合,并实施所谓的惰性水合。例如,我们的应用程序在初始视口下面有一个注释部分。

In this case, we may hydrate the like button when the page is loaded and hydrate the comment section only when the user scrolls below the initial viewport.
在这种情况下,我们可以在页面加载时使用“like”按钮,并且仅在用户滚动到初始视口下方时使用“注释”部分。

Hydrate the comment section at a later time.

Hydrate the comment section at a later time.
稍后再添加评论部分。

Talk about flexibility! 谈论灵活性!

The pros of partial hydration

部分补水的好处

  • The same benefits of server-side rendering with client-side hydration.
    服务器端渲染与客户端水化的好处相同。
  • Faster time to interactivity as the entire application isn’t hydrated.
    更快的交互时间,因为整个应用程序没有水合。

The cons of partial hydration

部分水合的缺点

  • If most of the parts of the application are interactive and have a high priority, the advantage of partial hydration could be arguably minimal, i.e., the entire application would take just as long to be hydrated.
    如果应用程序的大多数部分是交互式的并且具有高优先级,则部分水合的优点可以论证为最小,即,整个应用将花费同样长的时间来水合。

Where does the island architecture come from?

岛屿建筑从何而来?

The island architecture is built upon the foundation of partial hydration. Essentially, the islands architecture refers to having “islands of interactivity” on an otherwise static HTML page.
岛屿建筑是建立在部分水化的基础上的。本质上,岛架构指的是在其他静态的 HTML 页面上具有“交互岛”。

Islands of interactivity on an otherwise static webpage.

Islands of interactivity on an otherwise static webpage.
静态网页上的互动孤岛。

To make sense of this, think of these islands as partially hydrated components. So our entire page isn’t hydrated, but rather these islands.
为了理解这一点,我们可以把这些岛看作是部分水合的成分。所以我们的整个页面并没有被水合,而是这些岛屿。


A partial hydration islands architecture implementation
部分水合岛架构实现

It’s game time, mate.
游戏时间到了伙计

This section might seem challenging, but I suggest taking your time and coding along if possible. But, of course, you’ll probably be fine if you’re a more experienced engineer!
这一部分可能看起来很有挑战性,但我建议你花点时间编写代码,如果可能的话。但是,当然,如果你是一个更有经验的工程师,你可能会很好!

We will begin building our own island architecture implementation from the ground up. In more technical terms, we will implement a framework-independent partial hydration islands architecture implementation.
我们将从头开始构建我们自己的岛屿架构。在更多的技术术语中,我们将实现独立于框架的部分水合岛架构实现。

Phew! That’s a mouth full.
呼!这是一个嘴满。

Let’s break that down.
我们来分析一下。

Objectives 目的

The goal of this exercise is not to build a full-blown library or to create an exact clone of the Astro Island implementation. No!
本练习的目标不是构建一个完整的库或创建Astro Island实现的精确克隆。不!

Our objective is to peel back the perceived layer of complexity and strip down component islands to a fundamental digestible unit.
我们的目标是剥离感知的复杂性层和剥离组件岛到一个基本的可消化的单位。

Here are the functional requirements for our island implementation:
以下是我们岛实施的功能要求:

  1. Framework-independent: our solution must work across multiple frameworks, e.g., Preact, Vue, Petite-Vue and React.
    独立于框架:我们的解决方案必须跨多个框架工作,例如, PreactVuePetite-VueReact
  2. A partial hydration islands architecture implementation: we will strip away Javascript by default and only hydrate on an as-needed basis.
    部分水化岛体系结构实现:我们将默认删除JavaScript,只在需要时添加水合物。
  3. No frontend build step: for simplicity, our implementation will disregard a frontend build step, e.g., using babel.
    无前端构建步骤:为了简单起见,我们的实现将忽略前端构建步骤,例如,使用 babel.
  4. Support lazy hydration: this is a form of partial hydration where we can trigger hydration later and not immediately after loading the site. e.g., if an island is off-screen (not in the viewport), we will not load the Javascript for the island. We will only do so when the island is in view.
    支持懒惰补水:这是部分水合的一种形式,其中我们可以稍后而不是在装载部位之后立即触发水合。例如,如果一个岛在屏幕外(不在视口中),我们不会加载该岛的JavaScript。我们只有在看到岛屿的时候才会这样做。

Installation 安装方式

Let’s call our island module mini-island.
让我们把岛模块命名为 mini-island

To install mini-island, a developer will import our soon-to-be-built module as shown below:
要安装 mini-island ,开发人员将导入我们即将构建的模块,如下所示: