mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-17 21:24:59 +00:00
move all page info to app-level stores
This commit is contained in:
@@ -5,7 +5,7 @@ import { Page, PageComponent, ManifestData } from '../interfaces';
|
|||||||
|
|
||||||
const app = fs.readFileSync(path.resolve(__dirname, '../templates/App.html'), 'utf-8');
|
const app = fs.readFileSync(path.resolve(__dirname, '../templates/App.html'), 'utf-8');
|
||||||
const internal = fs.readFileSync(path.resolve(__dirname, '../templates/internal.mjs'), 'utf-8');
|
const internal = fs.readFileSync(path.resolve(__dirname, '../templates/internal.mjs'), 'utf-8');
|
||||||
const layout = `<svelte:component this={child.component} {...child.props}/>`;
|
const layout = fs.readFileSync(path.resolve(__dirname, '../templates/layout.html'), 'utf-8');
|
||||||
|
|
||||||
export function create_main_manifests({
|
export function create_main_manifests({
|
||||||
bundler,
|
bundler,
|
||||||
|
|||||||
@@ -1 +1,8 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export const stores = {
|
||||||
|
preloading: writable(null),
|
||||||
|
page: writable(null)
|
||||||
|
};
|
||||||
|
|
||||||
export const CONTEXT_KEY = {};
|
export const CONTEXT_KEY = {};
|
||||||
1
templates/layout.html
Normal file
1
templates/layout.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svelte:component this={child.component} {...child.props}/>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import App from '@sapper/App.html';
|
import App from '@sapper/App.html';
|
||||||
import { preloading, page } from '../shared/stores';
|
import { stores } from '@sapper/internal';
|
||||||
import Root, * as RootStatic from '__ROOT__';
|
import Root, * as RootStatic from '__ROOT__';
|
||||||
import ErrorComponent from '__ERROR__';
|
import ErrorComponent from '__ERROR__';
|
||||||
import {
|
import {
|
||||||
@@ -10,7 +10,8 @@ import {
|
|||||||
ComponentLoader,
|
ComponentLoader,
|
||||||
ComponentConstructor,
|
ComponentConstructor,
|
||||||
RootProps,
|
RootProps,
|
||||||
Page
|
Page,
|
||||||
|
PageData
|
||||||
} from './types';
|
} from './types';
|
||||||
import goto from './goto';
|
import goto from './goto';
|
||||||
|
|
||||||
@@ -25,20 +26,9 @@ let current_token: {};
|
|||||||
let root_preload: Promise<any>;
|
let root_preload: Promise<any>;
|
||||||
let root_data: any;
|
let root_data: any;
|
||||||
|
|
||||||
const root_props: RootProps = {
|
|
||||||
path: null,
|
|
||||||
params: null,
|
|
||||||
query: null,
|
|
||||||
child: {
|
|
||||||
segment: null,
|
|
||||||
component: null,
|
|
||||||
props: {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export let prefetching: {
|
export let prefetching: {
|
||||||
href: string;
|
href: string;
|
||||||
promise: Promise<{ redirect?: Redirect, data?: any, nullable_depth?: number, new_segments?: any }>;
|
promise: Promise<{ redirect?: Redirect, data?: any, new_segments?: any }>;
|
||||||
} = null;
|
} = null;
|
||||||
export function set_prefetching(href, promise) {
|
export function set_prefetching(href, promise) {
|
||||||
prefetching = { href, promise };
|
prefetching = { href, promise };
|
||||||
@@ -111,7 +101,7 @@ export function scroll_state() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function navigate(target: Target, id: number, noscroll?: boolean, hash?: string): Promise<any> {
|
export async function navigate(target: Target, id: number, noscroll?: boolean, hash?: string): Promise<any> {
|
||||||
let scroll: ScrollPosition;
|
let scroll: ScrollPosition;
|
||||||
if (id) {
|
if (id) {
|
||||||
// popstate or initial navigation
|
// popstate or initial navigation
|
||||||
@@ -129,7 +119,7 @@ export function navigate(target: Target, id: number, noscroll?: boolean, hash?:
|
|||||||
cid = id;
|
cid = id;
|
||||||
|
|
||||||
if (root_component) {
|
if (root_component) {
|
||||||
preloading.set({
|
stores.preloading.set({
|
||||||
// TODO path, params, query
|
// TODO path, params, query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -141,38 +131,22 @@ export function navigate(target: Target, id: number, noscroll?: boolean, hash?:
|
|||||||
|
|
||||||
const token = current_token = {};
|
const token = current_token = {};
|
||||||
|
|
||||||
return loaded.then(({ redirect, data, nullable_depth, new_segments }) => {
|
const { redirect, page, data, new_segments, results } = await loaded;
|
||||||
if (redirect) {
|
|
||||||
return goto(redirect.location, { replaceState: true });
|
if (redirect) return goto(redirect.location, { replaceState: true });
|
||||||
}
|
if (new_segments) segments = new_segments;
|
||||||
if (new_segments) {
|
|
||||||
segments = new_segments;
|
await render(results, data, page, scroll_history[id], noscroll, hash, token);
|
||||||
}
|
if (document.activeElement) document.activeElement.blur();
|
||||||
render(data, nullable_depth, scroll_history[id], noscroll, hash, token);
|
|
||||||
if (document.activeElement) document.activeElement.blur();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function render(props: any, nullable_depth: number, scroll: ScrollPosition, noscroll: boolean, hash: string, token: {}) {
|
async function render(results: any[], props: any, page: PageData, scroll: ScrollPosition, noscroll: boolean, hash: string, token: {}) {
|
||||||
if (current_token !== token) return;
|
if (current_token !== token) return;
|
||||||
|
|
||||||
preloading.set(null);
|
stores.page.set(page);
|
||||||
|
stores.preloading.set(null);
|
||||||
|
|
||||||
if (root_component) {
|
if (root_component) {
|
||||||
// first, clear out highest-level root component
|
|
||||||
let level = props.child;
|
|
||||||
for (let i = 0; i < nullable_depth; i += 1) {
|
|
||||||
if (i === nullable_depth) break;
|
|
||||||
level = level.props.child;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { component } = level;
|
|
||||||
level.component = null;
|
|
||||||
root_component.props = props;
|
|
||||||
|
|
||||||
// then render new stuff
|
|
||||||
// TODO do we need to call `flush` before doing this?
|
|
||||||
level.component = component;
|
|
||||||
root_component.props = props;
|
root_component.props = props;
|
||||||
} else {
|
} else {
|
||||||
// first load — remove SSR'd <head> contents
|
// first load — remove SSR'd <head> contents
|
||||||
@@ -185,7 +159,7 @@ async function render(props: any, nullable_depth: number, scroll: ScrollPosition
|
|||||||
detach(end);
|
detach(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(props, root_data);
|
Object.assign(props, root_data); // TODO what is root_data, do we still need it?
|
||||||
|
|
||||||
root_component = new App({
|
root_component = new App({
|
||||||
target,
|
target,
|
||||||
@@ -215,14 +189,16 @@ async function render(props: any, nullable_depth: number, scroll: ScrollPosition
|
|||||||
if (scroll) scrollTo(scroll.x, scroll.y);
|
if (scroll) scrollTo(scroll.x, scroll.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(root_props, props);
|
previous_thingummy = results;
|
||||||
ready = true;
|
ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let previous_thingummy = [];
|
||||||
|
|
||||||
export function prepare_page(target: Target): Promise<{
|
export function prepare_page(target: Target): Promise<{
|
||||||
redirect?: Redirect;
|
redirect?: Redirect;
|
||||||
data?: any;
|
data?: any;
|
||||||
nullable_depth?: number;
|
page: PageData
|
||||||
}> {
|
}> {
|
||||||
const { page, path, query } = target;
|
const { page, path, query } = target;
|
||||||
const new_segments = path.split('/').filter(Boolean);
|
const new_segments = path.split('/').filter(Boolean);
|
||||||
@@ -240,9 +216,9 @@ export function prepare_page(target: Target): Promise<{
|
|||||||
|
|
||||||
let redirect: Redirect = null;
|
let redirect: Redirect = null;
|
||||||
let error: { statusCode: number, message: Error | string } = null;
|
let error: { statusCode: number, message: Error | string } = null;
|
||||||
|
let page_data: PageData;
|
||||||
|
|
||||||
const preload_context = {
|
const preload_context = {
|
||||||
store,
|
|
||||||
fetch: (url: string, opts?: any) => fetch(url, opts),
|
fetch: (url: string, opts?: any) => fetch(url, opts),
|
||||||
redirect: (statusCode: number, location: string) => {
|
redirect: (statusCode: number, location: string) => {
|
||||||
if (redirect && (redirect.statusCode !== statusCode || redirect.location !== location)) {
|
if (redirect && (redirect.statusCode !== statusCode || redirect.location !== location)) {
|
||||||
@@ -267,11 +243,13 @@ export function prepare_page(target: Target): Promise<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(page.parts.map((part, i) => {
|
return Promise.all(page.parts.map((part, i) => {
|
||||||
if (i < changed_from) return null;
|
const segment = new_segments[i];
|
||||||
|
|
||||||
|
if (i < changed_from || !part) return previous_thingummy[i];
|
||||||
if (!part) return null;
|
if (!part) return null;
|
||||||
|
|
||||||
return load_component(components[part.i]).then(({ default: Component, preload }) => {
|
return load_component(components[part.i]).then(({ default: Component, preload }) => {
|
||||||
const req = {
|
page_data = {
|
||||||
path,
|
path,
|
||||||
query,
|
query,
|
||||||
params: part.params ? part.params(target.match) : {}
|
params: part.params ? part.params(target.match) : {}
|
||||||
@@ -280,7 +258,7 @@ export function prepare_page(target: Target): Promise<{
|
|||||||
let preloaded;
|
let preloaded;
|
||||||
if (ready || !initial_data.preloaded[i + 1]) {
|
if (ready || !initial_data.preloaded[i + 1]) {
|
||||||
preloaded = preload
|
preloaded = preload
|
||||||
? preload.call(preload_context, req)
|
? preload.call(preload_context, page_data)
|
||||||
: {};
|
: {};
|
||||||
} else {
|
} else {
|
||||||
preloaded = initial_data.preloaded[i + 1];
|
preloaded = initial_data.preloaded[i + 1];
|
||||||
@@ -304,72 +282,55 @@ export function prepare_page(target: Target): Promise<{
|
|||||||
}
|
}
|
||||||
}).then(results => {
|
}).then(results => {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
return { redirect, new_segments };
|
return { redirect, new_segments, page: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
const get_params = page.parts[page.parts.length - 1].params || (() => ({}));
|
const deepest = page.parts[page.parts.length - 1];
|
||||||
const params = get_params(target.match);
|
|
||||||
|
const page_data = {
|
||||||
|
path,
|
||||||
|
query,
|
||||||
|
params: deepest.params ? deepest.params(target.match) : {}
|
||||||
|
};
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
const props = {
|
|
||||||
path,
|
|
||||||
query,
|
|
||||||
params,
|
|
||||||
error: typeof error.message === 'string' ? new Error(error.message) : error.message,
|
|
||||||
status: error.statusCode
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nullable_depth: 0,
|
|
||||||
new_segments,
|
new_segments,
|
||||||
data: Object.assign({}, props, {
|
page: page_data,
|
||||||
|
data: {
|
||||||
child: {
|
child: {
|
||||||
component: ErrorComponent,
|
component: ErrorComponent,
|
||||||
props
|
props: {
|
||||||
|
error: typeof error.message === 'string' ? new Error(error.message) : error.message,
|
||||||
|
status: error.statusCode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = { path, query, error: null, status: null };
|
const props = {
|
||||||
const data = {
|
child: {
|
||||||
path,
|
|
||||||
child: Object.assign({}, root_props.child, {
|
|
||||||
segment: new_segments[0]
|
segment: new_segments[0]
|
||||||
})
|
}
|
||||||
};
|
};
|
||||||
if (changed(query, root_props.query)) data.query = query;
|
|
||||||
if (changed(params, root_props.params)) data.params = params;
|
|
||||||
|
|
||||||
let level = data.child;
|
let level = props.child;
|
||||||
let nullable_depth = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < page.parts.length; i += 1) {
|
for (let i = 0; i < page.parts.length; i += 1) {
|
||||||
const part = page.parts[i];
|
const part = page.parts[i];
|
||||||
if (!part) continue;
|
if (!part) continue;
|
||||||
|
|
||||||
const get_params = part.params || (() => ({}));
|
level.component = results[i].Component;
|
||||||
|
level.props = Object.assign({}, results[i].preloaded, {
|
||||||
if (i < changed_from) {
|
child: {}
|
||||||
level.props.path = path;
|
});
|
||||||
level.props.query = query;
|
|
||||||
level.props.child = Object.assign({}, level.props.child);
|
|
||||||
|
|
||||||
nullable_depth += 1;
|
|
||||||
} else {
|
|
||||||
level.component = results[i].Component;
|
|
||||||
level.props = Object.assign({}, level.props, props, {
|
|
||||||
params: get_params(target.match),
|
|
||||||
}, results[i].preloaded);
|
|
||||||
|
|
||||||
level.props.child = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
level = level.props.child;
|
level = level.props.child;
|
||||||
level.segment = new_segments[i + 1];
|
level.segment = new_segments[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return { data, nullable_depth, new_segments };
|
return { data: props, new_segments, page: page_data, results };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,8 +363,4 @@ export function load_component(component: ComponentLoader): Promise<{
|
|||||||
|
|
||||||
function detach(node: Node) {
|
function detach(node: Node) {
|
||||||
node.parentNode.removeChild(node);
|
node.parentNode.removeChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changed(a: Record<string, string | true>, b: Record<string, string | true>) {
|
|
||||||
return JSON.stringify(a) !== JSON.stringify(b);
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { CONTEXT_KEY } from '@sapper/internal';
|
import { CONTEXT_KEY, stores } from '@sapper/internal';
|
||||||
import * as stores from '../shared/stores';
|
|
||||||
|
|
||||||
export const preloading = { subscribe: stores.preloading.subscribe };
|
export const preloading = { subscribe: stores.preloading.subscribe };
|
||||||
export const page = { subscribe: stores.page.subscribe };
|
export const page = { subscribe: stores.page.subscribe };
|
||||||
|
|||||||
@@ -65,4 +65,10 @@ export type Redirect = {
|
|||||||
|
|
||||||
export type Store = {
|
export type Store = {
|
||||||
get: () => any;
|
get: () => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PageData = {
|
||||||
|
path: string;
|
||||||
|
params: Record<string, string>;
|
||||||
|
query: Record<string, string | string[]>;
|
||||||
|
};
|
||||||
@@ -4,9 +4,9 @@ import cookie from 'cookie';
|
|||||||
import devalue from 'devalue';
|
import devalue from 'devalue';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import URL from 'url';
|
import URL from 'url';
|
||||||
import * as stores from '../../shared/stores';
|
|
||||||
import { build_dir, dev, src_dir, IGNORE } from '../placeholders';
|
import { build_dir, dev, src_dir, IGNORE } from '../placeholders';
|
||||||
import { Manifest, Page, Props, Req, Res } from './types';
|
import { Manifest, Page, Props, Req, Res } from './types';
|
||||||
|
import { stores } from '@sapper/internal';
|
||||||
import App from '@sapper/App.html';
|
import App from '@sapper/App.html';
|
||||||
|
|
||||||
export function get_page_handler(
|
export function get_page_handler(
|
||||||
@@ -135,6 +135,7 @@ export function get_page_handler(
|
|||||||
|
|
||||||
let preloaded;
|
let preloaded;
|
||||||
let match;
|
let match;
|
||||||
|
let params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const root_preloaded = manifest.root_preload
|
const root_preloaded = manifest.root_preload
|
||||||
@@ -147,16 +148,20 @@ export function get_page_handler(
|
|||||||
|
|
||||||
match = error ? null : page.pattern.exec(req.path);
|
match = error ? null : page.pattern.exec(req.path);
|
||||||
|
|
||||||
|
|
||||||
let toPreload = [root_preloaded];
|
let toPreload = [root_preloaded];
|
||||||
if (!isSWIndexHtml) {
|
if (!isSWIndexHtml) {
|
||||||
toPreload = toPreload.concat(page.parts.map(part => {
|
toPreload = toPreload.concat(page.parts.map(part => {
|
||||||
if (!part) return null;
|
if (!part) return null;
|
||||||
|
|
||||||
|
// the deepest level is used below, to initialise the store
|
||||||
|
params = part.params ? part.params(match) : {};
|
||||||
|
|
||||||
return part.preload
|
return part.preload
|
||||||
? part.preload.call(preload_context, {
|
? part.preload.call(preload_context, {
|
||||||
path: req.path,
|
path: req.path,
|
||||||
query: req.query,
|
query: req.query,
|
||||||
params: part.params ? part.params(match) : {}
|
params
|
||||||
})
|
})
|
||||||
: {};
|
: {};
|
||||||
}))
|
}))
|
||||||
@@ -186,60 +191,46 @@ export function get_page_handler(
|
|||||||
|
|
||||||
const segments = req.path.split('/').filter(Boolean);
|
const segments = req.path.split('/').filter(Boolean);
|
||||||
|
|
||||||
const props: Props = {
|
const props = Object.assign({}, preloaded[0], {
|
||||||
path: req.path,
|
|
||||||
query: req.query,
|
|
||||||
params: {},
|
|
||||||
child: null
|
|
||||||
};
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
props.error = error instanceof Error ? error : { message: error };
|
|
||||||
props.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = Object.assign({}, props, preloaded[0], {
|
|
||||||
params: {},
|
|
||||||
child: {
|
child: {
|
||||||
segment: segments[0]
|
segment: segments[0],
|
||||||
|
props: {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let level = data.child;
|
let level = props.child;
|
||||||
if (isSWIndexHtml) {
|
if (!isSWIndexHtml) {
|
||||||
level.props = Object.assign({}, props, {
|
|
||||||
params: {}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < page.parts.length; i += 1) {
|
for (let i = 0; i < page.parts.length; i += 1) {
|
||||||
const part = page.parts[i];
|
const part = page.parts[i];
|
||||||
if (!part) continue;
|
if (!part) continue;
|
||||||
|
|
||||||
const get_params = part.params || (() => ({}));
|
|
||||||
|
|
||||||
Object.assign(level, {
|
Object.assign(level, {
|
||||||
component: part.component,
|
component: part.component,
|
||||||
props: Object.assign({}, props, {
|
props: Object.assign({}, preloaded[i + 1])
|
||||||
params: get_params(match)
|
|
||||||
}, preloaded[i + 1])
|
|
||||||
});
|
});
|
||||||
|
|
||||||
level.props.child = <Props["child"]>{
|
level.props.child = <Props["child"]>{
|
||||||
segment: segments[i + 1]
|
segment: segments[i + 1],
|
||||||
|
props: {}
|
||||||
};
|
};
|
||||||
level = level.props.child;
|
level = level.props.child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
props.child.props.error = error instanceof Error ? error : { message: error };
|
||||||
|
props.child.props.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
stores.page.set({
|
stores.page.set({
|
||||||
path: req.path,
|
path: req.path,
|
||||||
query: req.query,
|
query: req.query,
|
||||||
params: req.params
|
params: params
|
||||||
});
|
});
|
||||||
|
|
||||||
const { html, head, css } = App.render({
|
const { html, head, css } = App.render({
|
||||||
Root: manifest.root,
|
Root: manifest.root,
|
||||||
props: data,
|
props: props,
|
||||||
session
|
session
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -313,6 +304,7 @@ export function get_page_handler(
|
|||||||
res.statusCode = status;
|
res.statusCode = status;
|
||||||
res.end(body);
|
res.end(body);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
console.log(err);
|
||||||
if (error) {
|
if (error) {
|
||||||
// we encountered an error while rendering the error page — oops
|
// we encountered an error while rendering the error page — oops
|
||||||
res.statusCode = 500;
|
res.statusCode = 500;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export type Page = {
|
|||||||
name: string;
|
name: string;
|
||||||
component: Component;
|
component: Component;
|
||||||
params?: (match: RegExpMatchArray) => Record<string, string>;
|
params?: (match: RegExpMatchArray) => Record<string, string>;
|
||||||
|
preload?: (data: any) => any | Promise<any>;
|
||||||
}>
|
}>
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ export type Manifest = {
|
|||||||
server_routes: ServerRoute[];
|
server_routes: ServerRoute[];
|
||||||
pages: Page[];
|
pages: Page[];
|
||||||
root: Component;
|
root: Component;
|
||||||
|
root_preload?: (data: any) => any | Promise<any>;
|
||||||
error: Component;
|
error: Component;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,9 +31,6 @@ export type Store = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
path: string;
|
|
||||||
query: Record<string, string>;
|
|
||||||
params: Record<string, string>;
|
|
||||||
error?: { message: string };
|
error?: { message: string };
|
||||||
status?: number;
|
status?: number;
|
||||||
child: {
|
child: {
|
||||||
@@ -64,6 +63,5 @@ interface Component {
|
|||||||
head: string;
|
head: string;
|
||||||
css: { code: string, map: any };
|
css: { code: string, map: any };
|
||||||
html: string
|
html: string
|
||||||
},
|
}
|
||||||
preload: (data: any) => any | Promise<any>
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { writable } from 'svelte/store';
|
|
||||||
|
|
||||||
export const preloading = writable(null);
|
|
||||||
export const page = writable(null);
|
|
||||||
@@ -1 +1,5 @@
|
|||||||
<h1>{params.slug.toUpperCase()}</h1>
|
<script>
|
||||||
|
import { page } from '@sapper/app';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>{$page.params.slug.toUpperCase()}</h1>
|
||||||
@@ -1 +1,5 @@
|
|||||||
<h1>{JSON.stringify(query)}</h1>
|
<script>
|
||||||
|
import { page } from '@sapper/app';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>{JSON.stringify($page.query)}</h1>
|
||||||
@@ -7,8 +7,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { page } from '@sapper/app';
|
||||||
export let slug;
|
export let slug;
|
||||||
export let query;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>{slug} {JSON.stringify(query)}</h1>
|
<h1>{slug} {JSON.stringify($page.query)}</h1>
|
||||||
@@ -2,6 +2,11 @@ import * as sapper from '@sapper/app';
|
|||||||
|
|
||||||
window.start = () => sapper.start({
|
window.start = () => sapper.start({
|
||||||
target: document.querySelector('#sapper')
|
target: document.querySelector('#sapper')
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(`OH NO! ${err.message}`);
|
||||||
|
throw err;
|
||||||
|
}).then(() => {
|
||||||
|
console.log(`STARTED`);
|
||||||
});
|
});
|
||||||
|
|
||||||
window.prefetchRoutes = () => sapper.prefetchRoutes();
|
window.prefetchRoutes = () => sapper.prefetchRoutes();
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export let params;
|
import { page } from '@sapper/app';
|
||||||
|
|
||||||
export let count;
|
export let count;
|
||||||
export let segment = params.z;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span>z: {segment} {count}</span>
|
<span>z: {$page.params.z} {count}</span>
|
||||||
<a href="foo/bar/qux">click me</a>
|
<a href="foo/bar/qux">click me</a>
|
||||||
@@ -9,13 +9,13 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export let params;
|
import { page } from '@sapper/app';
|
||||||
|
|
||||||
export let count;
|
export let count;
|
||||||
export let child;
|
export let child;
|
||||||
export let segment = params.y;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span>y: {segment} {count}</span>
|
<span>y: {$page.params.y} {count}</span>
|
||||||
<svelte:component this={child.component} {...child.props}/>
|
<svelte:component this={child.component} {...child.props}/>
|
||||||
|
|
||||||
<span>child segment: {child.segment}</span>
|
<span>child segment: {child.segment}</span>
|
||||||
@@ -26,10 +26,18 @@ describe('layout', function() {
|
|||||||
|
|
||||||
it('only recreates components when necessary', async () => {
|
it('only recreates components when necessary', async () => {
|
||||||
await page.goto(`${base}/foo/bar/baz`);
|
await page.goto(`${base}/foo/bar/baz`);
|
||||||
await start();
|
|
||||||
|
|
||||||
const text1 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
const text1 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
||||||
assert.deepEqual(text1.split('\n').filter(Boolean), [
|
assert.deepEqual(text1.split('\n').filter(Boolean).map(str => str.trim()), [
|
||||||
|
'y: bar 1',
|
||||||
|
'z: baz 1',
|
||||||
|
'click me',
|
||||||
|
'child segment: baz'
|
||||||
|
]);
|
||||||
|
|
||||||
|
await start();
|
||||||
|
const text2 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
||||||
|
assert.deepEqual(text2.split('\n').filter(Boolean).map(str => str.trim()), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: baz 1',
|
'z: baz 1',
|
||||||
'click me',
|
'click me',
|
||||||
@@ -39,8 +47,8 @@ describe('layout', function() {
|
|||||||
await page.click('[href="foo/bar/qux"]');
|
await page.click('[href="foo/bar/qux"]');
|
||||||
await wait(50);
|
await wait(50);
|
||||||
|
|
||||||
const text2 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
const text3 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
||||||
assert.deepEqual(text2.split('\n').filter(Boolean), [
|
assert.deepEqual(text3.split('\n').filter(Boolean).map(str => str.trim()), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: qux 2',
|
'z: qux 2',
|
||||||
'click me',
|
'click me',
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
<h1>{params.slug}</h1>
|
<script>
|
||||||
|
import { page } from '@sapper/app';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>{$page.params.slug}</h1>
|
||||||
|
|||||||
Reference in New Issue
Block a user