svelte - 如何修复 sapper/svelte 中的 localStorage 错误

标签 svelte sapper

import { writable } from 'svelte/store';

/** Read the current token from LocalStorage on boot */
const token = writable(localStorage.getItem('token'));
/** Store the token in LocalStorage whenever it´s updated */
token.subscribe((val) => {
  if (!localStorage) return;

  if (!val) {
    return localStorage.removeItem('token');
  }

  localStorage.setItem('token', val);
});

export default token;

当我运行npm run dev时,我仍然收到 localStorage 在 sapper 中未定义的错误

最佳答案

在 Sapper 中,您的代码将在浏览器和 SSR 的 Node 中运行。真正的Node,甚至不是像jsdom之类的模拟浏览器环境。 (不一定是“将”,事实上,它是“可能”,因为只有浏览器请求的第一个页面才会在服务器端呈现,但您仍然需要确保所有代码都支持这两种页面)。

在 Node 中,许多浏览器 API(例如 localStorage)不可用。

在 JS 中,你不能像这样测试变量是否存在:

if (!localStorage) ...

如果该变量不存在,您将会遇到崩溃。测试变量是否存在的安全方法如下:

if (typeof localStorage === 'undefined') ...

因此,通过重写您的商店,使您的代码与浏览器 + Node 兼容:

const createBrowserTokenStore = () => {
  const store = writable(localStorage.getItem('token'))
  
  // Store the token in LocalStorage whenever it´s updated
  store.subscribe((val) => {
    if (!localStorage) return
    if (!val) return localStorage.removeItem('token')
    localStorage.setItem('token', val)
  })

  return store
}

// just enough to not crash in Node
const createNodeTokenStore = () => writable(null)

export const token = typeof localStorage === 'undefined'
  ? createNodeTokenStore()
  : createBrowserTokenStore()

请注意,即使在 SSR 上下文(即 Node)中,浏览器代码也会运行。页面SSR时的具体操作顺序如下:

  • 页面 HTML 在 Node 中呈现,组件使用 ssr: true 编译选项进行编译 - 即,仅在一次传递中呈现 HTML 字符串的组件

  • HTML 被发送到浏览器

  • 浏览器会按应有的样子显示您的页面

  • JS在后台加载并执行

  • 您的 Svelte 组件将使用 Hydratable 选项重新运行,这意味着它们将尝试回收现有的 DOM 元素,而不是无条件地创建它们

  • 您的页面现在是交互式的,但在获取 HTML 和加载 JS 之间的短暂(或不那么短)间隔内,它已经很漂亮了

我想说的是,即使页面是由 SSR 渲染的,您的 JS 也将在浏览器中运行,并且结果将替换 SSR 过程生成的结果。如果客户端 JS 组件生成与服务器完全不同的 DOM 元素,则 Svelte 将覆盖。

这意味着,在这种情况下,只要提供最小值以使代码不会在 Node 中崩溃就可以接受。如果您可以生成接近浏览器渲染结果的结果,那当然更好。 (另一种选择是调整您的代码,以便服务器在仅浏览器的情况下呈现类似“正在加载...”的内容)。

关于svelte - 如何修复 sapper/svelte 中的 localStorage 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65592525/

相关文章:

routing - 在 Sapper 中作为模态路由

javascript - slim 3 : array of children to parent communication via props

svelte - 是否可以在 svelte 中创建自定义指令?

javascript - Svelte 每个循环都不会更新,而对象是动态更改的

google-authentication - 将 Google Web Auth 添加到 Svelte/Sapper 的 "right"方法是什么?

markdown - 工兵/ slim : How do I add markdown files?

javascript - 如何将 Svelte 组件的状态绑定(bind)到 Sapper 中的查询字符串

adsense - 如何在 SPA(单页应用程序)的路由更改时调用 AdSense 自动广告?

svelte - <ComponentName>是在没有预期属性 'segment'的情况下创建的

css - 在 Sapper 中使用 rem 单位的相对大小