如何避免 Spartacus 重复发送 CMS page 请求

发布时间 2023-11-17 19:00:39作者: JerryWang_汪子熙

如下图所示,启用了 SSR 之后,Spartacus 在 CSR 模式下 re-hydration 时,会重复发送一次 CMS page 请求:

可以参考这个 StackOverflow 的讨论,通过下面的代码来阻止 CSR 模式下重复发送 page 请求:

provideConfig(<RoutingConfig>{      routing: { loadStrategy: RouteLoadStrategy.ONCE },    }),

The configured transfer state should work OOTB for some parts of the data, but not for everything. See the source code of cms-store.module.ts, product-store.module.ts and site-context-store.module.ts.

  • cms-store.module.ts
  • product-store.module.ts
  • site-context-store.module.ts

Spartacus服务器端渲染和状态传输

Spartacus是一种用于构建电子商务Web应用程序的Angular框架。服务器端渲染是一种将应用程序的初始渲染推移到服务器端的技术,有助于提高性能和搜索引擎优化。状态传输是服务器端渲染的一个关键方面,它确保客户端在加载时能够获取到与服务器渲染内容一致的应用程序状态。

状态传输在Spartacus中通常涉及到两个方面:页面初始化和数据预取。

页面初始化

页面初始化涉及到将页面的初始状态从服务器传递到客户端,以便客户端能够正确渲染页面。在Spartacus中,这通常包括以下步骤:

  1. 服务器端渲染: 当用户请求页面时,服务器会执行Angular应用程序,并将应用程序的初始状态一起渲染为HTML。

  2. 状态序列化: 服务器会将应用程序的状态序列化为一种数据格式,通常是JSON或类似的格式。

  3. 页面响应: 服务器将HTML响应发送给客户端,同时包含了序列化后的状态数据。状态数据通常嵌入在HTML中,可以在脚本中轻松提取。

  4. 客户端解析: 客户端接收到响应后,可以从HTML中提取状态数据并将其反序列化为客户端应用程序的状态。

下面是一个通用的示例,展示了状态传输的过程:

<!DOCTYPE html>
<html>
<head>
    <!-- 页面的一般标记 -->
</head>
<body>
    <!-- 页面内容 -->
</body>
<script>
    // 客户端脚本
    // 从HTML中提取状态数据
    const serializedState = `<!-- 序列化后的状态数据 -->`;
    const initialState = JSON.parse(serializedState);

    // 使用状态数据初始化客户端应用程序
    initializeApp(initialState);
</script>
</html>

数据预取

数据预取是确保在页面加载时获取所需数据的过程。这有助于减少初始渲染后的数据请求,提高性能。在Spartacus中,数据预取通常包括以下步骤:

  1. 路由匹配: 客户端应用程序根据页面的路由信息来确定需要哪些数据。

  2. 数据获取: 客户端应用程序使用路由信息来发出数据请求,这些请求可能是API请求或其他形式的数据获取。

  3. 数据预取: 客户端应用程序在初始渲染之前获取到数据,并将其存储在应用程序状态中。

下面是一个通用的示例,展示了数据预取的过程:

// 客户端应用程序代码

import { ActivatedRoute } from '@angular/router';
import { DataService } from './data.service';

// 在组件中获取路由参数并预取数据
class MyComponent {
    constructor(private route: ActivatedRoute, private dataService: DataService) {
        this.route.params.subscribe(params => {
            const productId = params.productId;
            this.dataService.getProductData(productId).subscribe(data => {
                // 将数据存储在应用程序状态中
                storeProductData(data);
            });
        });
    }
}

// 数据服务
class DataService {
    getProductData(productId: string) {
        // 发出API请求获取产品数据
        return apiService.getProduct(productId);
    }
}