Svelte/Sapper.js - 如何使用localStorage数据初始化store?

20

我来自React背景,但是为了应对React巨大的捆绑大小,我将转而使用Svelte和Sapper开发我的下一个应用程序。然而,我在使用localStorage检索数据初始化Svelte存储时遇到了问题。

根据Sapper文档(https://sapper.svelte.dev/docs#Getting_started),我通过在命令行中运行npx degit "sveltejs/sapper-template#rollup" my-app创建了项目。然后,我安装了依赖项并删除了src文件夹中的演示代码。

接下来,我创建了两个文件:src/routes/index.sveltesrc/store/index.js

两个文件的代码:

src/store/index.js

    import {writable} from "svelte/store";
    
    export let userLang;
    
    if(typeof window !== "undefined") {
        userLang = writable(localStorage.getItem("lang") || "en");
    } else {
        userLang = writable(null);
    }

src/routes/index.svelte

    <script>
        import {userLang} from "../store";
    </script>
    
    <p>Your Preferred Language: {$userLang}</p>

当我运行应用程序并点击index路由时,我看到以下内容:

您的首选语言:null

然后几乎立即更新并更改为

您的首选语言:en

如果在localStorage中没有lang项,则更改为

您的首选语言:fr

在从开发人员控制台明确设置localStorage.setItem("lang", "fr")并刷新后。

我知道存储库首先在服务器上初始化,其中windowundefined,然后在客户端上重新添加。因此,这种行为是可以预料的。

那么我的问题是:如何完全跳过服务器初始化?是否可能仅在客户端上设置存储库(其中定义了localStorage),以便用户选择的语言立即可用?

我不能默认为用户更改首选语言后的所有内容都是英语或任何其他语言。我也不能在初始页面加载时通过navigator.language从浏览器获取用户语言,因为在服务器上navigator也是undefined

并且,在存储库重新添加之前出现空文本的闪烁会破坏我的应用程序的UX,特别是当userLang的值将在许多地方与翻译一起使用时。

因此,任何关于此的策略或技巧肯定会受到赞赏。

**** 更深层次的问题 ****

实际上,我更喜欢完全没有服务器端渲染此应用程序,但我确实需要Sapper提供的所有其他出色功能,如路由、预取和静态站点构建。

因此,根据文档,我尝试运行npx sapper export以生成完全静态的站点,以使服务器不再参与其中,但即使完全不使用服务器,仍然发生了完全相同的问题。

有人有关于如何配置Sapper并关闭SSR但保留其他功能的建议吗?

谢谢!

**** 更新 ****

根据Rich Harris的回答,使用{#if process.browser}将标记包装得很好。所以我已经像这样更新了src/routes/index.svelte文件:

    <script>
        import {userLang} from "../store";
    </script>

    {#if process.browser}
        <p>Your Preferred Language: {$userLang}</p>
    {/if}

同时,userLang变量立即被设置为来自localStorage的值或者默认值en,正如我在这个简单演示中的意图。现在没有更多的null闪烁了,所以它基本上表现得像是只有客户端,此时已经可以。

我将继续完善我的项目,并查看是否还遇到其他问题。在那之前,我认为这解决了我的问题。

1个回答

21

目前,SSR是必需的。有一个问题正在进行 SPA 模式 — https://github.com/sveltejs/sapper/issues/383 — 这将按照您所描述的行为运行,我们只需要解决它。

我们还计划在未来的版本中内置 i18n 支持:https://github.com/sveltejs/sapper/issues/576

同时,您可以通过将所有标记包装在 {#if process.browser} 内来模拟它 — 内部任何内容都不会被服务器呈现,但一旦 JavaScript 启动,它就会出现。


谢谢回复!我一定会关注这些问题,并尝试按你所说的将标记包含在 if 块中。同时,感谢 Svelte 的全面优越性。我知道随着时间的推移,该项目只会变得越来越好。 - another_one
我的令牌存储在localStorage中,我该如何在sapper中解决这个问题? - chovy
值得注意的是,检查 process.browser 似乎在常规的 JS 代码中也可以工作,而不仅仅是在模板中。谢谢! - Daniel Veihelmann
1
在我的构建环境中,process.browser可以工作。但是当我导出时它就无法工作了。 - Ilse Van Dommelen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接