implement session/preload on client

This commit is contained in:
Richard Harris
2019-02-02 16:13:07 -05:00
parent 91ea0335ae
commit c964500118

View File

@@ -3,6 +3,7 @@ import { stores } from '@sapper/internal';
import Root from '__ROOT__';
import { preload as root_preload } from '__ROOT_PRELOAD__';
import ErrorComponent from '__ERROR__';
import { writable } from 'svelte/store.mjs';
import {
Target,
ScrollPosition,
@@ -18,6 +19,8 @@ import goto from './goto';
// injected at build time
declare const __IGNORE__, __COMPONENTS__, __PAGES__, __SAPPER__;
export const initial_data = typeof __SAPPER__ !== 'undefined' && __SAPPER__;
const ignore = __IGNORE__;
export const components: ComponentLoader[] = __COMPONENTS__;
export const routes: Route[] = __PAGES__;
@@ -28,6 +31,26 @@ let current_token: {};
let root_preloaded: Promise<any>;
let current_branch = [];
const session = writable(initial_data && initial_data.session);
let $session;
let session_dirty: boolean;
session.subscribe(async value => {
$session = value;
if (!ready) return;
session_dirty = true;
const target = select_target(new URL(location.href));
const token = current_token = {};
const { redirect, props, branch } = await hydrate_target(target);
if (token !== current_token) return; // a secondary navigation happened while we were loading
await render(redirect, branch, props, target.page);
});
export let prefetching: {
href: string;
promise: Promise<{ redirect?: Redirect, data?: any }>;
@@ -56,8 +79,6 @@ export function set_cid(n) {
cid = n;
}
export const initial_data = typeof __SAPPER__ !== 'undefined' && __SAPPER__;
const _history = typeof history !== 'undefined' ? history : {
pushState: (state: any, title: string, href: string) => {},
replaceState: (state: any, title: string, href: string) => {},
@@ -137,13 +158,32 @@ export async function navigate(target: Target, id: number, noscroll?: boolean, h
const { redirect, props, branch } = await loaded;
if (token !== current_token) return; // a secondary navigation happened while we were loading
if (redirect) return goto(redirect.location, { replaceState: true });
await render(branch, props, target.page, scroll_history[id], noscroll, hash);
await render(redirect, branch, props, target.page);
if (document.activeElement) document.activeElement.blur();
if (!noscroll) {
let scroll = scroll_history[id];
if (hash) {
// scroll is an element id (from a hash), we need to compute y.
const deep_linked = document.querySelector(hash);
if (deep_linked) {
scroll = {
x: 0,
y: deep_linked.getBoundingClientRect().top
};
}
}
scroll_history[cid] = scroll;
if (scroll) scrollTo(scroll.x, scroll.y);
}
}
async function render(branch: any[], props: any, page: Page, scroll: ScrollPosition, noscroll: boolean, hash: string) {
async function render(redirect: Redirect, branch: any[], props: any, page: Page) {
if (redirect) return goto(redirect.location, { replaceState: true });
stores.page.set(page);
stores.preloading.set(false);
@@ -165,31 +205,15 @@ async function render(branch: any[], props: any, page: Page, scroll: ScrollPosit
props: {
Root,
props,
session: __SAPPER__.session
session
},
hydrate: true
});
}
if (!noscroll) {
if (hash) {
// scroll is an element id (from a hash), we need to compute y.
const deep_linked = document.querySelector(hash);
if (deep_linked) {
scroll = {
x: 0,
y: deep_linked.getBoundingClientRect().top
};
}
}
scroll_history[cid] = scroll;
if (scroll) scrollTo(scroll.x, scroll.y);
}
current_branch = branch;
ready = true;
session_dirty = false;
}
export async function hydrate_target(target: Target): Promise<{
@@ -221,7 +245,7 @@ export async function hydrate_target(target: Target): Promise<{
path: page.path,
query: page.query,
params: {}
});
}, $session);
}
let branch;
@@ -231,7 +255,7 @@ export async function hydrate_target(target: Target): Promise<{
if (!part) return null;
const segment = segments[i];
if (current_branch[i] && current_branch[i].segment === segment) return current_branch[i];
if (!session_dirty && current_branch[i] && current_branch[i].segment === segment) return current_branch[i];
const { default: Component, preload } = await load_component(components[part.i]);
@@ -242,7 +266,7 @@ export async function hydrate_target(target: Target): Promise<{
path: page.path,
query: page.query,
params: part.params ? part.params(target.match) : {}
})
}, $session)
: {};
} else {
preloaded = initial_data.preloaded[i + 1];