从 S3 加载数据时,我应该如何构建 Sapper/Svelte 路由?

jco*_*lum 1 amazon-s3 svelte sapper

假设我有一堆数据文档,它们是 S3 中的 JSON 文档,每年一个。我通过 dir 结构在 Sapper 中定义了一条路线:

??? routes
?   ??? _error.svelte
?   ??? _layout.svelte
?   ??? about.svelte
?   ??? data
?   ?   ??? [year].svelte
Run Code Online (Sandbox Code Playgroud)

我的script块中的代码:

  let yearData;
  onMount(async () => {
    const f = await fetch(yearDataUrl(year), {
      headers: { 'Access-Control-Allow-Origin': '*' }
    });
    const jsonResults = await f.json();
    yearData = jsonResults;
  });
Run Code Online (Sandbox Code Playgroud)

每个数据集在 S3 中作为[s3 url]/[year here].json。导航栏中有一组链接显示每个数据集。我可以onMount很好地加载数据,但随后单击导航栏链接不会加载新数据。所以onMount很可能是错误的选择。

我应该如何构建它?还值得注意的是,我想将这些页面呈现为静态文件(数据很少更改,尤其是前几年)。

Ric*_*ris 5

有两种选择。第一个也是最惯用的 - 在你的情况下也是正确的,因为听起来你想使用服务器端渲染 - 是使用preload

<script context="module">
  export async function preload(page) {
    const f = await this.fetch(yearDataUrl(page.params.year), {
      headers: { 'Access-Control-Allow-Origin': '*' }
    });

    return {
      yearData: await f.json()
    };
  }
</script>

<script>
  export let yearData;
</script>

<!-- use yearData here -->
Run Code Online (Sandbox Code Playgroud)

preload 函数将在组件创建之前运行,并为其提供yearDataprop。每当page.params发生变化时,preload都会再次运行,设置一个新的道具。

因为这既适用于服务器也适用于客户端(因此使用了this.fetch而不是fetch,它在两种环境中都适用)您将获得服务器呈现的页面,而不是一onMount运行就闪烁到页面中的加载消息。

为了完整起见,包含的第二个选项是使用页面存储

<script>
  import { stores } from '@sapper/app';

  const { page } = stores();

  let yearData;

  $: if (process.browser) {
      fetch(yearDataUrl($page.params.year))
        .then(f => f.json())
        .then(data => {
          yearData = data;
        });
  }
</script>
Run Code Online (Sandbox Code Playgroud)

在这种情况下yearData 不会被服务器渲染。(为了完整起见,您还需要处理竞争条件和错误,这不是preload.)