Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.

TypeScript support: preload detection at runtime #1344

Merged
merged 2 commits into from
Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion runtime/src/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { writable } from 'svelte/store';
import App from '@sapper/internal/App.svelte';
import { root_preload, ErrorComponent, ignore, components, routes } from '@sapper/internal/manifest-client';
import { root_comp, ErrorComponent, ignore, components, routes } from '@sapper/internal/manifest-client';
import {
Target,
ScrollPosition,
Expand Down Expand Up @@ -297,6 +297,7 @@ export async function hydrate_target(target: Target): Promise<{
};

if (!root_preloaded) {
const root_preload = root_comp.preload || (() => {});
root_preloaded = initial_data.preloaded[0] || root_preload.call(preload_context, {
host: page.host,
path: page.path,
Expand Down
13 changes: 6 additions & 7 deletions runtime/src/server/middleware/get_page_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,13 @@ export function get_page_handler(
let params;

try {
const root_preloaded = manifest.root_preload
? manifest.root_preload.call(preload_context, {
const root_preload = manifest.root_comp.preload || (() => {});
const root_preloaded = root_preload.call(preload_context, {
host: req.headers.host,
path: req.path,
query: req.query,
params: {}
}, session)
: {};
}, session);

match = error ? null : page.pattern.exec(req.path);

Expand All @@ -174,8 +173,8 @@ export function get_page_handler(
// the deepest level is used below, to initialise the store
params = part.params ? part.params(match) : {};

return part.preload
? part.preload.call(preload_context, {
return part.component.preload
? part.component.preload.call(preload_context, {
host: req.headers.host,
path: req.path,
query: req.query,
Expand Down Expand Up @@ -257,7 +256,7 @@ export function get_page_handler(
if (!part) continue;

props[`level${l++}`] = {
component: part.component,
component: part.component.default,
props: preloaded[i + 1] || {},
segment: segments[i]
};
Expand Down
9 changes: 5 additions & 4 deletions runtime/src/server/middleware/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ export type Page = {
pattern: RegExp;
parts: Array<{
name: string;
component: Component;
component: {
default: Component;
preload?: (data: any) => any | Promise<any>;
},
params?: (match: RegExpMatchArray) => Record<string, string>;
preload?: (data: any) => any | Promise<any>;
}>
};

export type Manifest = {
server_routes: ServerRoute[];
pages: Page[];
root: Component;
root_preload?: (data: any) => any | Promise<any>;
root_comp: Component;
error: Component;
}

Expand Down
15 changes: 7 additions & 8 deletions src/core/create_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ function generate_client_manifest(

return `
// This file is generated by Sapper — do not edit it!
export { default as Root } from '${stringify(get_file(path_to_routes, manifest_data.root), false)}';
export { preload as root_preload } from '${manifest_data.root.has_preload ? stringify(get_file(path_to_routes, manifest_data.root), false) : './shared'}';
// webpack does not support export * as root_comp yet so do a two line import/export
import * as root_comp from '${stringify(get_file(path_to_routes, manifest_data.root), false)}';
export { root_comp };
export { default as ErrorComponent } from '${stringify(get_file(path_to_routes, manifest_data.error), false)}';

export const ignore = [${server_routes_to_ignore.map(route => route.pattern).join(', ')}];
Expand Down Expand Up @@ -166,8 +167,8 @@ function generate_server_manifest(
manifest_data.server_routes.map((route, i) =>
`import * as route_${i} from ${stringify(posixify(`${path_to_routes}/${route.file}`))};`),
manifest_data.components.map((component, i) =>
`import component_${i}${component.has_preload ? `, { preload as preload_${i} }` : ''} from ${stringify(get_file(path_to_routes, component))};`),
`import root${manifest_data.root.has_preload ? `, { preload as root_preload }` : ''} from ${stringify(get_file(path_to_routes, manifest_data.root))};`,
`import * as component_${i} from ${stringify(get_file(path_to_routes, component))};`),
`import * as root_comp from ${stringify(get_file(path_to_routes, manifest_data.root))};`,
`import error from ${stringify(get_file(path_to_routes, manifest_data.error))};`
);

Expand Down Expand Up @@ -211,8 +212,7 @@ function generate_server_manifest(
const props = [
`name: "${part.component.name}"`,
`file: ${stringify(part.component.file)}`,
`component: component_${component_lookup[part.component.name]}`,
part.component.has_preload && `preload: preload_${component_lookup[part.component.name]}`
`component: component_${component_lookup[part.component.name]}`
].filter(Boolean);

if (part.params.length > 0) {
Expand All @@ -226,8 +226,7 @@ function generate_server_manifest(
}`).join(',\n\n\t\t\t\t')}
],

root,
root_preload${manifest_data.root.has_preload ? '' : `: () => {}`},
root_comp,
error
};

Expand Down
26 changes: 4 additions & 22 deletions src/core/create_manifest_data.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as fs from 'fs';
import * as path from 'path';
import svelte from 'svelte/compiler';
import { Page, PageComponent, ServerRoute, ManifestData } from '../interfaces';
import { posixify, reserved_words } from '../utils';

Expand All @@ -13,28 +12,14 @@ export default function create_manifest_data(cwd: string, extensions: string = '
throw new Error(`As of Sapper 0.21, the routes/ directory should become src/routes/`);
}

function has_preload(file: string) {
const source = fs.readFileSync(path.join(cwd, file), 'utf-8');

if (/preload/.test(source)) {
try {
const { vars } = svelte.compile(source.replace(/<style\b[^>]*>[^]*?<\/style>/g, ''), { generate: false });
return vars.some((variable: any) => variable.module && variable.export_name === 'preload');
} catch (err) {}
}

return false;
}

function find_layout(file_name: string, component_name: string, dir: string = '') {
const ext = component_extensions.find((ext) => fs.existsSync(path.join(cwd, dir, `${file_name}${ext}`)));
const file = posixify(path.join(dir, `${file_name}${ext}`))

return ext
? {
name: component_name,
file: file,
has_preload: has_preload(file)
file: file
}
: null;
}
Expand All @@ -47,16 +32,14 @@ export default function create_manifest_data(cwd: string, extensions: string = '
default: true,
type: 'layout',
name: '_default_layout',
file: null,
has_preload: false
file: null
};

const default_error: PageComponent = {
default: true,
type: 'error',
name: '_default_error',
file: null,
has_preload: false
file: null
};

function walk(
Expand Down Expand Up @@ -161,8 +144,7 @@ export default function create_manifest_data(cwd: string, extensions: string = '
else if (item.is_page) {
const component = {
name: get_slug(item.file),
file: item.file,
has_preload: has_preload(item.file)
file: item.file
};

components.push(component);
Expand Down
1 change: 0 additions & 1 deletion src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export type PageComponent = {
type?: string;
name: string;
file: string;
has_preload: boolean;
};

export type Page = {
Expand Down
18 changes: 9 additions & 9 deletions test/unit/create_manifest_data/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ describe('manifest_data', () => {
it('creates routes', () => {
const { components, pages, server_routes } = create_manifest_data(path.join(__dirname, 'samples/basic'));

const index = { name: 'index', file: 'index.html', has_preload: false };
const about = { name: 'about', file: 'about.html', has_preload: false };
const blog = { name: 'blog', file: 'blog/index.html', has_preload: false };
const blog_$slug = { name: 'blog_$slug', file: 'blog/[slug].html', has_preload: false };
const index = { name: 'index', file: 'index.html' };
const about = { name: 'about', file: 'about.html' };
const blog = { name: 'blog', file: 'blog/index.html' };
const blog_$slug = { name: 'blog_$slug', file: 'blog/[slug].html' };

assert.deepEqual(components, [
index,
Expand Down Expand Up @@ -79,7 +79,7 @@ describe('manifest_data', () => {
// had to remove ? and " because windows

// const quote = { name: '$34', file: '".html' };
const hash = { name: '$35', has_preload: false, file: '#.html' };
const hash = { name: '$35', file: '#.html' };
// const question_mark = { name: '$63', file: '?.html' };

assert.deepEqual(components, [
Expand Down Expand Up @@ -206,10 +206,10 @@ describe('manifest_data', () => {
it('works with custom extensions' , () => {
const { components, pages, server_routes } = create_manifest_data(path.join(__dirname, 'samples/custom-extension'), '.jazz .beebop .funk .html');

const index = { name: 'index', file: 'index.funk', has_preload: false };
const about = { name: 'about', file: 'about.jazz', has_preload: false };
const blog = { name: 'blog', file: 'blog/index.html', has_preload: false };
const blog_$slug = { name: 'blog_$slug', file: 'blog/[slug].beebop', has_preload: false };
const index = { name: 'index', file: 'index.funk' };
const about = { name: 'about', file: 'about.jazz' };
const blog = { name: 'blog', file: 'blog/index.html' };
const blog_$slug = { name: 'blog_$slug', file: 'blog/[slug].beebop' };

assert.deepEqual(components, [
index,
Expand Down