我想使用Sapper.js构建一个可脱机工作但还具有服务器端渲染功能的Web应用程序。为此,我需要两种数据存储实现:一种在浏览器中工作,另一种在服务器上工作。
我认为在client.js
和server.js
中,我可能可以导入商店的相应实现,然后将其作为道具传递给我的页面组件,类似于:
// server.js
// [some more imports here]
import DataStore from "./my/backend/datastore"
polka()
.use(
sapper.middleware({
pageProps: {DataStore}
})
)
.listen(PORT, err => {/* other stuff */});
// client.js
import * as sapper from '@sapper/app';
import DataStore from "./my/frontend/datastore"
sapper.start({
target: document.querySelector('#sapper'),
pageProps: {DataStore}
})
<!-- page.svelte -->
<script>
export let DataStore;
let item;
if (!item) {
DataStore.getItem().then(i => item = i);
}
</script>
<p>{item}</p>
但是,似乎没有办法将道具从两个入口点传递到页面中。
尽管使用全局变量而不是props,但https://stackoverflow.com/a/49085459/9236140上问题#3的答案也允许做同样的事情。但是,由于我还没有设法从组件内部访问window
和global
,所以它似乎不再起作用。
// routes/server/route/exposing/get_item.js
import DataStore from "./my/backend/datastore"
export async function get(req, res, next) {
res.end(await DataStore.getItem());
}
<!-- page.svelte -->
<script context="module">
export async function preload(page, session) {
const response = await this.fetch(`/server/route/exposing/get_item`);
return {
item: await response.text()
}
}
</script>
<script>
import {onMount} from 'svelte';
export let item;
let DataStore;
onMount(async () => {
// Dynamically import DataStore so I can use it later, e.g. in on click handlers.
const module = await import("./my/frontend/datastore");
DataStore = module.default;
}
</script>
<p>{item}</p>
preload
中的page.svelte
函数。非常感谢您的阅读。所有指针表示赞赏。 :)
摆弄一些东西之后,我发现了一种方法,可以在preload
函数中区分服务器和客户端,并至少在前端上导航时防止AJAX调用,但是它感觉很hacky,并增加了一些样板:
// server.js
// [imports here]
polka()
.use(
sapper.middleware({
session: (req, res) => ({environment: "server"})
})
)
.listen(PORT, err => {/* other stuff */});
<!-- page.svelte -->
<script context="module">
export async function preload(page, session) {
if (session.environment === "server") {
session.environment = "client"
const response = await this.fetch(`/server/route/exposing/get_item`);
return {
item: await response.text()
}
} else {
const module = await import("./my/frontend/datastore");
return {
item: await module.default.getItem()
};
}
}
</script>