mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-11 19:04:30 +00:00
Slot-based routing (#573)
This commit is contained in:
@@ -1 +1,7 @@
|
|||||||
<svelte:component this={child.component} {...child.props}/>
|
<h1>{status}</h1>
|
||||||
|
|
||||||
|
<p>{error.message}</p>
|
||||||
|
|
||||||
|
{#if process.env.NODE_ENV === 'development'}
|
||||||
|
<pre>{error.stack}</pre>
|
||||||
|
{/if}
|
||||||
@@ -1 +1 @@
|
|||||||
<svelte:component this={child.component} {...child.props}/>
|
<slot></slot>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { writable } from 'svelte/store.mjs';
|
import { writable } from 'svelte/store.mjs';
|
||||||
import Sapper from '@sapper/internal/Sapper.svelte';
|
import App from '@sapper/internal/App.svelte';
|
||||||
import { stores } from '@sapper/internal/shared';
|
import { stores } from '@sapper/internal/shared';
|
||||||
import { Root, root_preload, ErrorComponent, ignore, components, routes } from '@sapper/internal/manifest-client';
|
import { Root, root_preload, ErrorComponent, ignore, components, routes } from '@sapper/internal/manifest-client';
|
||||||
import {
|
import {
|
||||||
@@ -180,8 +180,13 @@ async function render(redirect: Redirect, branch: any[], props: any, page: Page)
|
|||||||
stores.preloading.set(false);
|
stores.preloading.set(false);
|
||||||
|
|
||||||
if (root_component) {
|
if (root_component) {
|
||||||
root_component.props = props;
|
root_component.$set(props);
|
||||||
} else {
|
} else {
|
||||||
|
props.session = session;
|
||||||
|
props.level0 = {
|
||||||
|
props: await root_preloaded
|
||||||
|
};
|
||||||
|
|
||||||
// first load — remove SSR'd <head> contents
|
// first load — remove SSR'd <head> contents
|
||||||
const start = document.querySelector('#sapper-head-start');
|
const start = document.querySelector('#sapper-head-start');
|
||||||
const end = document.querySelector('#sapper-head-end');
|
const end = document.querySelector('#sapper-head-end');
|
||||||
@@ -192,13 +197,9 @@ async function render(redirect: Redirect, branch: any[], props: any, page: Page)
|
|||||||
detach(end);
|
detach(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
root_component = new Sapper({
|
root_component = new App({
|
||||||
target,
|
target,
|
||||||
props: {
|
|
||||||
Root,
|
|
||||||
props,
|
props,
|
||||||
session
|
|
||||||
},
|
|
||||||
hydrate: true
|
hydrate: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -211,13 +212,14 @@ async function render(redirect: Redirect, branch: any[], props: any, page: Page)
|
|||||||
export async function hydrate_target(target: Target): Promise<{
|
export async function hydrate_target(target: Target): Promise<{
|
||||||
redirect?: Redirect;
|
redirect?: Redirect;
|
||||||
props?: any;
|
props?: any;
|
||||||
branch?: Array<{ Component: ComponentConstructor, preload: (page) => Promise<any>, segment: string }>
|
branch?: Array<{ Component: ComponentConstructor, preload: (page) => Promise<any>, segment: string }>;
|
||||||
}> {
|
}> {
|
||||||
const { route, page } = target;
|
const { route, page } = target;
|
||||||
const segments = page.path.split('/').filter(Boolean);
|
const segments = page.path.split('/').filter(Boolean);
|
||||||
|
|
||||||
let redirect: Redirect = null;
|
let redirect: Redirect = null;
|
||||||
let error: { statusCode: number, message: Error | string } = null;
|
|
||||||
|
const props = { error: null, status: 200, segments: [segments[0]] };
|
||||||
|
|
||||||
const preload_context = {
|
const preload_context = {
|
||||||
fetch: (url: string, opts?: any) => fetch(url, opts),
|
fetch: (url: string, opts?: any) => fetch(url, opts),
|
||||||
@@ -227,8 +229,9 @@ export async function hydrate_target(target: Target): Promise<{
|
|||||||
}
|
}
|
||||||
redirect = { statusCode, location };
|
redirect = { statusCode, location };
|
||||||
},
|
},
|
||||||
error: (statusCode: number, message: Error | string) => {
|
error: (status: number, error: Error | string) => {
|
||||||
error = { statusCode, message };
|
props.error = typeof error === 'string' ? new Error(error) : error;
|
||||||
|
props.status = status;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -241,15 +244,19 @@ export async function hydrate_target(target: Target): Promise<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
let branch;
|
let branch;
|
||||||
|
let l = 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
branch = await Promise.all(route.parts.map(async (part, i) => {
|
branch = await Promise.all(route.parts.map(async (part, i) => {
|
||||||
|
props.segments[l] = segments[i + 1]; // TODO make this less confusing
|
||||||
if (!part) return null;
|
if (!part) return null;
|
||||||
|
|
||||||
|
const j = l++;
|
||||||
|
|
||||||
const segment = segments[i];
|
const segment = segments[i];
|
||||||
if (!session_dirty && 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]);
|
const { default: component, preload } = await load_component(components[part.i]);
|
||||||
|
|
||||||
let preloaded;
|
let preloaded;
|
||||||
if (ready || !initial_data.preloaded[i + 1]) {
|
if (ready || !initial_data.preloaded[i + 1]) {
|
||||||
@@ -264,49 +271,15 @@ export async function hydrate_target(target: Target): Promise<{
|
|||||||
preloaded = initial_data.preloaded[i + 1];
|
preloaded = initial_data.preloaded[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return { Component, preloaded, segment };
|
return (props[`level${j}`] = { component, props: preloaded, segment });
|
||||||
}));
|
}));
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
error = { statusCode: 500, message: e };
|
props.error = error;
|
||||||
|
props.status = 500;
|
||||||
branch = [];
|
branch = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redirect) return { redirect };
|
return { redirect, props, branch };
|
||||||
|
|
||||||
if (error) {
|
|
||||||
// TODO be nice if this was less of a special case
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
child: {
|
|
||||||
component: ErrorComponent,
|
|
||||||
props: {
|
|
||||||
error: typeof error.message === 'string' ? new Error(error.message) : error.message,
|
|
||||||
status: error.statusCode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
branch
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = Object.assign({}, await root_preloaded, {
|
|
||||||
child: { segment: segments[0] }
|
|
||||||
});
|
|
||||||
|
|
||||||
let level = props.child;
|
|
||||||
|
|
||||||
branch.forEach((node, i) => {
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
level.component = node.Component;
|
|
||||||
level.props = Object.assign({}, node.preloaded, {
|
|
||||||
child: { segment: segments[i + 1] }
|
|
||||||
});
|
|
||||||
|
|
||||||
level = level.props.child;
|
|
||||||
});
|
|
||||||
|
|
||||||
return { props, branch };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function load_css(chunk: string) {
|
function load_css(chunk: string) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { IGNORE } from '../constants';
|
|||||||
import { Manifest, Page, Props, Req, Res } from './types';
|
import { Manifest, Page, Props, Req, Res } from './types';
|
||||||
import { build_dir, dev, src_dir } from '@sapper/internal/manifest-server';
|
import { build_dir, dev, src_dir } from '@sapper/internal/manifest-server';
|
||||||
import { stores } from '@sapper/internal/shared';
|
import { stores } from '@sapper/internal/shared';
|
||||||
import Sapper from '@sapper/internal/Sapper.svelte';
|
import App from '@sapper/internal/App.svelte';
|
||||||
|
|
||||||
export function get_page_handler(
|
export function get_page_handler(
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
@@ -38,7 +38,7 @@ export function get_page_handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handle_page(page: Page, req: Req, res: Res, status = 200, error: Error | string = null) {
|
async function handle_page(page: Page, req: Req, res: Res, status = 200, error: Error | string = null) {
|
||||||
const isSWIndexHtml = req.path === '/service-worker-index.html';
|
const is_service_worker_index = req.path === '/service-worker-index.html';
|
||||||
const build_info: {
|
const build_info: {
|
||||||
bundler: 'rollup' | 'webpack',
|
bundler: 'rollup' | 'webpack',
|
||||||
shimport: string | null,
|
shimport: string | null,
|
||||||
@@ -52,7 +52,7 @@ export function get_page_handler(
|
|||||||
// preload main.js and current route
|
// preload main.js and current route
|
||||||
// TODO detect other stuff we can preload? images, CSS, fonts?
|
// TODO detect other stuff we can preload? images, CSS, fonts?
|
||||||
let preloaded_chunks = Array.isArray(build_info.assets.main) ? build_info.assets.main : [build_info.assets.main];
|
let preloaded_chunks = Array.isArray(build_info.assets.main) ? build_info.assets.main : [build_info.assets.main];
|
||||||
if (!error && !isSWIndexHtml) {
|
if (!error && !is_service_worker_index) {
|
||||||
page.parts.forEach(part => {
|
page.parts.forEach(part => {
|
||||||
if (!part) return;
|
if (!part) return;
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ export function get_page_handler(
|
|||||||
|
|
||||||
|
|
||||||
let toPreload = [root_preloaded];
|
let toPreload = [root_preloaded];
|
||||||
if (!isSWIndexHtml) {
|
if (!is_service_worker_index) {
|
||||||
toPreload = toPreload.concat(page.parts.map(part => {
|
toPreload = toPreload.concat(page.parts.map(part => {
|
||||||
if (!part) return null;
|
if (!part) return null;
|
||||||
|
|
||||||
@@ -193,48 +193,51 @@ export function get_page_handler(
|
|||||||
|
|
||||||
const segments = req.path.split('/').filter(Boolean);
|
const segments = req.path.split('/').filter(Boolean);
|
||||||
|
|
||||||
const props = Object.assign({}, preloaded[0], {
|
// TODO make this less confusing
|
||||||
child: {
|
const layout_segments = [segments[0]];
|
||||||
|
let l = 1;
|
||||||
|
|
||||||
|
page.parts.forEach((part, i) => {
|
||||||
|
layout_segments[l] = segments[i + 1];
|
||||||
|
if (!part) return null;
|
||||||
|
l++;
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
segments: layout_segments,
|
||||||
|
status: error ? status : 200,
|
||||||
|
error: error ? error instanceof Error ? error : { message: error } : null,
|
||||||
|
session: writable(session),
|
||||||
|
level0: {
|
||||||
|
props: preloaded[0]
|
||||||
|
},
|
||||||
|
level1: {
|
||||||
segment: segments[0],
|
segment: segments[0],
|
||||||
props: {}
|
props: {}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
let level = props.child;
|
if (!is_service_worker_index) {
|
||||||
if (!isSWIndexHtml) {
|
let l = 1;
|
||||||
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;
|
||||||
|
|
||||||
Object.assign(level, {
|
props[`level${l++}`] = {
|
||||||
component: part.component,
|
component: part.component,
|
||||||
props: Object.assign({}, preloaded[i + 1])
|
props: preloaded[i + 1],
|
||||||
});
|
segment: segments[i]
|
||||||
|
|
||||||
level.props.child = <Props["child"]>{
|
|
||||||
segment: segments[i + 1],
|
|
||||||
props: {}
|
|
||||||
};
|
};
|
||||||
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: params
|
params: params
|
||||||
});
|
});
|
||||||
|
|
||||||
const { html, head, css } = Sapper.render({
|
const { html, head, css } = App.render(props);
|
||||||
Root: manifest.root,
|
|
||||||
props: props,
|
|
||||||
session: writable(session)
|
|
||||||
});
|
|
||||||
|
|
||||||
const serialized = {
|
const serialized = {
|
||||||
preloaded: `[${preloaded.map(data => try_serialize(data)).join(',')}]`,
|
preloaded: `[${preloaded.map(data => try_serialize(data)).join(',')}]`,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import minify_html from './utils/minify_html';
|
import minify_html from './utils/minify_html';
|
||||||
import { create_compilers, create_main_manifests, create_manifest_data, create_serviceworker_manifest } from '../core';
|
import { create_compilers, create_app, create_manifest_data, create_serviceworker_manifest } from '../core';
|
||||||
import { copy_shimport } from './utils/copy_shimport';
|
import { copy_shimport } from './utils/copy_shimport';
|
||||||
import read_template from '../core/read_template';
|
import read_template from '../core/read_template';
|
||||||
import { CompileResult } from '../core/create_compilers/interfaces';
|
import { CompileResult } from '../core/create_compilers/interfaces';
|
||||||
@@ -71,7 +71,7 @@ export async function build({
|
|||||||
const manifest_data = create_manifest_data(routes);
|
const manifest_data = create_manifest_data(routes);
|
||||||
|
|
||||||
// create src/node_modules/@sapper/app.mjs and server.mjs
|
// create src/node_modules/@sapper/app.mjs and server.mjs
|
||||||
create_main_manifests({
|
create_app({
|
||||||
bundler,
|
bundler,
|
||||||
manifest_data,
|
manifest_data,
|
||||||
cwd,
|
cwd,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as http from 'http';
|
|||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
import * as ports from 'port-authority';
|
import * as ports from 'port-authority';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { create_manifest_data, create_main_manifests, create_compilers, create_serviceworker_manifest } from '../core';
|
import { create_manifest_data, create_app, create_compilers, create_serviceworker_manifest } from '../core';
|
||||||
import { Compiler, Compilers } from '../core/create_compilers';
|
import { Compiler, Compilers } from '../core/create_compilers';
|
||||||
import { CompileResult } from '../core/create_compilers/interfaces';
|
import { CompileResult } from '../core/create_compilers/interfaces';
|
||||||
import Deferred from './utils/Deferred';
|
import Deferred from './utils/Deferred';
|
||||||
@@ -162,7 +162,7 @@ class Watcher extends EventEmitter {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
manifest_data = create_manifest_data(routes);
|
manifest_data = create_manifest_data(routes);
|
||||||
create_main_manifests({
|
create_app({
|
||||||
bundler: this.bundler,
|
bundler: this.bundler,
|
||||||
manifest_data,
|
manifest_data,
|
||||||
dev: true,
|
dev: true,
|
||||||
@@ -190,7 +190,7 @@ class Watcher extends EventEmitter {
|
|||||||
() => {
|
() => {
|
||||||
try {
|
try {
|
||||||
const new_manifest_data = create_manifest_data(routes);
|
const new_manifest_data = create_manifest_data(routes);
|
||||||
create_main_manifests({
|
create_app({
|
||||||
bundler: this.bundler,
|
bundler: this.bundler,
|
||||||
manifest_data, // TODO is this right? not new_manifest_data?
|
manifest_data, // TODO is this right? not new_manifest_data?
|
||||||
dev: true,
|
dev: true,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const runtime = [
|
|||||||
'app.mjs',
|
'app.mjs',
|
||||||
'server.mjs',
|
'server.mjs',
|
||||||
'internal/shared.mjs',
|
'internal/shared.mjs',
|
||||||
'internal/Sapper.svelte',
|
|
||||||
'internal/layout.svelte',
|
'internal/layout.svelte',
|
||||||
'internal/error.svelte'
|
'internal/error.svelte'
|
||||||
].map(file => ({
|
].map(file => ({
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export * from './core/create_manifests';
|
export * from './core/create_app';
|
||||||
export { default as create_compilers } from './core/create_compilers/index';
|
export { default as create_compilers } from './core/create_compilers/index';
|
||||||
export { default as create_manifest_data } from './core/create_manifest_data';
|
export { default as create_manifest_data } from './core/create_manifest_data';
|
||||||
@@ -3,7 +3,7 @@ import * as path from 'path';
|
|||||||
import { posixify, stringify, walk, write_if_changed } from '../utils';
|
import { posixify, stringify, walk, write_if_changed } from '../utils';
|
||||||
import { Page, PageComponent, ManifestData } from '../interfaces';
|
import { Page, PageComponent, ManifestData } from '../interfaces';
|
||||||
|
|
||||||
export function create_main_manifests({
|
export function create_app({
|
||||||
bundler,
|
bundler,
|
||||||
manifest_data,
|
manifest_data,
|
||||||
dev_port,
|
dev_port,
|
||||||
@@ -31,8 +31,11 @@ export function create_main_manifests({
|
|||||||
const client_manifest = generate_client_manifest(manifest_data, path_to_routes, bundler, dev, dev_port);
|
const client_manifest = generate_client_manifest(manifest_data, path_to_routes, bundler, dev, dev_port);
|
||||||
const server_manifest = generate_server_manifest(manifest_data, path_to_routes, cwd, src, dest, dev);
|
const server_manifest = generate_server_manifest(manifest_data, path_to_routes, cwd, src, dest, dev);
|
||||||
|
|
||||||
|
const app = generate_app(manifest_data, path_to_routes);
|
||||||
|
|
||||||
write_if_changed(`${output}/internal/manifest-client.mjs`, client_manifest);
|
write_if_changed(`${output}/internal/manifest-client.mjs`, client_manifest);
|
||||||
write_if_changed(`${output}/internal/manifest-server.mjs`, server_manifest);
|
write_if_changed(`${output}/internal/manifest-server.mjs`, server_manifest);
|
||||||
|
write_if_changed(`${output}/internal/App.svelte`, app);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function create_serviceworker_manifest({ manifest_data, output, client_files, static_files }: {
|
export function create_serviceworker_manifest({ manifest_data, output, client_files, static_files }: {
|
||||||
@@ -230,6 +233,58 @@ function generate_server_manifest(
|
|||||||
`.replace(/^\t{2}/gm, '').trim();
|
`.replace(/^\t{2}/gm, '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generate_app(manifest_data: ManifestData, path_to_routes: string) {
|
||||||
|
// TODO remove default layout altogether
|
||||||
|
|
||||||
|
const max_depth = Math.max(...manifest_data.pages.map(page => page.parts.filter(Boolean).length));
|
||||||
|
|
||||||
|
const levels = [];
|
||||||
|
for (let i = 0; i < max_depth; i += 1) {
|
||||||
|
levels.push(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let l = max_depth;
|
||||||
|
|
||||||
|
let pyramid = `<svelte:component this={level${l}.component} {...level${l}.props}/>`;
|
||||||
|
|
||||||
|
while (l-- > 1) {
|
||||||
|
pyramid = `
|
||||||
|
<svelte:component this={level${l}.component} segment={segments[${l}]} {...level${l}.props}>
|
||||||
|
{#if level${l + 1}}
|
||||||
|
${pyramid.replace(/\n/g, '\n\t\t\t\t\t')}
|
||||||
|
{/if}
|
||||||
|
</svelte:component>
|
||||||
|
`.replace(/^\t\t\t/gm, '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<!-- This file is generated by Sapper — do not edit it! -->
|
||||||
|
<script>
|
||||||
|
import { setContext } from 'svelte';
|
||||||
|
import { CONTEXT_KEY } from './shared';
|
||||||
|
import Layout from '${get_file(path_to_routes, manifest_data.root)}';
|
||||||
|
import Error from '${get_file(path_to_routes, manifest_data.error)}';
|
||||||
|
|
||||||
|
export let session;
|
||||||
|
export let error;
|
||||||
|
export let status;
|
||||||
|
export let segments;
|
||||||
|
export let level0;
|
||||||
|
${levels.map(l => `export let level${l} = null;`).join('\n\t\t\t')}
|
||||||
|
|
||||||
|
setContext(CONTEXT_KEY, session);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Layout segment={segments[0]} {...level0.props}>
|
||||||
|
{#if error}
|
||||||
|
<Error {error} {status}/>
|
||||||
|
{:else}
|
||||||
|
${pyramid.replace(/\n/g, '\n\t\t\t\t')}
|
||||||
|
{/if}
|
||||||
|
</Layout>
|
||||||
|
`.replace(/^\t\t/gm, '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
function get_file(path_to_routes: string, component: PageComponent) {
|
function get_file(path_to_routes: string, component: PageComponent) {
|
||||||
if (component.default) return `./${component.type}.svelte`;
|
if (component.default) return `./${component.type}.svelte`;
|
||||||
return posixify(`${path_to_routes}/${component.file}`);
|
return posixify(`${path_to_routes}/${component.file}`);
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
import { page } from '@sapper/app';
|
import { page } from '@sapper/app';
|
||||||
|
|
||||||
export let count;
|
export let count;
|
||||||
export let child;
|
export let segment;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span>y: {$page.params.y} {count}</span>
|
<span>y: {$page.params.y} {count}</span>
|
||||||
<svelte:component this={child.component} {...child.props}/>
|
<slot></slot>
|
||||||
|
|
||||||
<span>child segment: {child.segment}</span>
|
<span>child segment: {segment}</span>
|
||||||
@@ -28,7 +28,7 @@ describe('layout', function() {
|
|||||||
await page.goto(`${base}/foo/bar/baz`);
|
await page.goto(`${base}/foo/bar/baz`);
|
||||||
|
|
||||||
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).map(str => str.trim()), [
|
assert.deepEqual(text1.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: baz 1',
|
'z: baz 1',
|
||||||
'click me',
|
'click me',
|
||||||
@@ -37,7 +37,7 @@ describe('layout', function() {
|
|||||||
|
|
||||||
await start();
|
await start();
|
||||||
const text2 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
const text2 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
||||||
assert.deepEqual(text2.split('\n').filter(Boolean).map(str => str.trim()), [
|
assert.deepEqual(text2.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: baz 1',
|
'z: baz 1',
|
||||||
'click me',
|
'click me',
|
||||||
@@ -48,7 +48,7 @@ describe('layout', function() {
|
|||||||
await wait(50);
|
await wait(50);
|
||||||
|
|
||||||
const text3 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
const text3 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
||||||
assert.deepEqual(text3.split('\n').filter(Boolean).map(str => str.trim()), [
|
assert.deepEqual(text3.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: qux 2',
|
'z: qux 2',
|
||||||
'click me',
|
'click me',
|
||||||
|
|||||||
@@ -8,13 +8,16 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { preloading } from '@sapper/app';
|
import { preloading } from '@sapper/app';
|
||||||
|
import { setContext } from 'svelte';
|
||||||
|
|
||||||
export let child;
|
export let child;
|
||||||
export let rootPreloadFunctionRan;
|
export let rootPreloadFunctionRan;
|
||||||
|
|
||||||
|
setContext('x', { rootPreloadFunctionRan });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $preloading}
|
{#if $preloading}
|
||||||
<progress class='preloading-progress' value=0.5/>
|
<progress class='preloading-progress' value=0.5/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<svelte:component this={child.component} {rootPreloadFunctionRan} {...child.props}/>
|
<slot></slot>
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svelte:component this={child.component} {...child.props}/>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<h1>root preload function ran: {rootPreloadFunctionRan}</h1>
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<script>
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
const { rootPreloadFunctionRan } = getContext('x');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>root preload function ran: {rootPreloadFunctionRan}</h1>
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svelte:component this={child.component} {...child.props}/>
|
|
||||||
Reference in New Issue
Block a user