update manifest generation

This commit is contained in:
Rich Harris
2018-07-16 11:21:24 -04:00
parent 624f17364c
commit 969430716f
3 changed files with 98 additions and 65 deletions

View File

@@ -3,10 +3,10 @@ import * as path from 'path';
import * as glob from 'glob'; import * as glob from 'glob';
import { posixify, write_if_changed } from './utils'; import { posixify, write_if_changed } from './utils';
import { dev, locations } from '../config'; import { dev, locations } from '../config';
import { Route } from '../interfaces'; import { Page, PageComponent, ServerRoute } from '../interfaces';
export function create_main_manifests({ routes, dev_port }: { export function create_main_manifests({ routes, dev_port }: {
routes: Route[]; routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] };
dev_port?: number; dev_port?: number;
}) { }) {
const path_to_routes = path.relative(`${locations.app()}/manifest`, locations.routes()); const path_to_routes = path.relative(`${locations.app()}/manifest`, locations.routes());
@@ -19,7 +19,7 @@ export function create_main_manifests({ routes, dev_port }: {
} }
export function create_serviceworker_manifest({ routes, client_files }: { export function create_serviceworker_manifest({ routes, client_files }: {
routes: Route[]; routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] };
client_files: string[]; client_files: string[];
}) { }) {
const assets = glob.sync('**', { cwd: 'assets', nodir: true }); const assets = glob.sync('**', { cwd: 'assets', nodir: true });
@@ -32,37 +32,61 @@ export function create_serviceworker_manifest({ routes, client_files }: {
export const shell = [\n\t${client_files.map((x: string) => `"${x}"`).join(',\n\t')}\n]; export const shell = [\n\t${client_files.map((x: string) => `"${x}"`).join(',\n\t')}\n];
export const routes = [\n\t${routes.pages.filter(r => r.id !== '_error').map((r: Route) => `{ pattern: ${r.pattern} }`).join(',\n\t')}\n]; export const routes = [\n\t${routes.pages.map((r: Page) => `{ pattern: ${r.pattern} }`).join(',\n\t')}\n];
`.replace(/^\t\t/gm, '').trim(); `.replace(/^\t\t/gm, '').trim();
write_if_changed(`${locations.app()}/manifest/service-worker.js`, code); write_if_changed(`${locations.app()}/manifest/service-worker.js`, code);
} }
function generate_client(routes: Route[], path_to_routes: string, dev_port?: number) { function right_pad(str: string, len: number) {
const page_ids = new Set(routes.pages.map(page => page.id)); while (str.length < len) str += ' ';
const server_routes_to_ignore = routes.server_routes.filter(route => !page_ids.has(route.id)); return str;
}
const pages = routes.pages.filter(page => page.id !== '_error'); function generate_client(
const error_route = routes.pages.find(page => page.id === '_error'); routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] },
path_to_routes: string,
dev_port?: number
) {
const page_ids = new Set(routes.pages.map(page =>
page.pattern.toString()));
const server_routes_to_ignore = routes.server_routes.filter(route =>
!page_ids.has(route.pattern.toString()));
const len = Math.max(...routes.components.map(c => c.name.length));
let code = ` let code = `
// This file is generated by Sapper — do not edit it! // This file is generated by Sapper — do not edit it!
import root from '${posixify(`${path_to_routes}/index.html`)}';
${routes.components.map(component =>
`const ${right_pad(component.name, len)} = () => import('${posixify(`${path_to_routes}/${component.file}`)}');`)
.join('\n')}
export const routes = { export const routes = {
ignore: [${server_routes_to_ignore.map(route => route.pattern).join(', ')}], ignore: [${server_routes_to_ignore.map(route => route.pattern).join(', ')}],
root,
pages: [ pages: [
${pages.map(page => { ${routes.pages.map(page => `{
const file = posixify(`${path_to_routes}/${page.file}`); // ${page.parts[page.parts.length - 1].component.file}
pattern: ${page.pattern},
parts: [
${page.parts.map(part => {
if (part.params.length > 0) {
const props = part.params.map((param, i) => `${param}: match[${i + 1}]`);
return `{ component: ${part.component.name}, params: match => ({ ${props.join(', ')} }) }`;
}
const params = page.params.length === 0 return `{ component: ${part.component.name} }`;
? '{}' }).join(',\n\t\t\t\t\t\t')}
: `{ ${page.params.map((part, i) => `${part}: match[${i + 1}]`).join(', ')} }`; ]
}`).join(',\n\n\t\t\t\t')}
return `{ pattern: ${page.pattern}, params: ${page.params.length > 0 ? `match` : `()`} => (${params}), load: () => import(/* webpackChunkName: "${page.id}" */ '${file}') }`;
}).join(',\n\t\t\t\t')}
], ],
error: () => import(/* webpackChunkName: '_error' */ '${posixify(`${path_to_routes}/${error_route.file}`)}') error: () => import(/* webpackChunkName: '_error' */ '${posixify(`${path_to_routes}/_error.html`)}')
};`.replace(/^\t\t/gm, '').trim(); };`.replace(/^\t\t/gm, '').trim();
if (dev()) { if (dev()) {
@@ -82,16 +106,17 @@ function generate_client(routes: Route[], path_to_routes: string, dev_port?: num
return code; return code;
} }
function generate_server(routes: Route[], path_to_routes: string) { function generate_server(
const pages = routes.pages.filter(page => page.id !== '_error'); routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] },
const error_route = routes.pages.find(page => page.id === '_error'); path_to_routes: string
) {
const imports = [].concat( const imports = [].concat(
routes.server_routes.map(route => routes.server_routes.map(route =>
`import * as route_${route.id} from '${posixify(`${path_to_routes}/${route.file}`)}';`), `import * as ${route.name} from '${posixify(`${path_to_routes}/${route.file}`)}';`),
pages.map(page => routes.components.map(component =>
`import page_${page.id} from '${posixify(`${path_to_routes}/${page.file}`)}';`), `import ${component.name} from '${posixify(`${path_to_routes}/${component.file}`)}';`),
`import error from '${posixify(`${path_to_routes}/${error_route.file}`)}';` `import root from '${posixify(`${path_to_routes}/index.html`)}';`,
`import error from '${posixify(`${path_to_routes}/_error.html`)}';`
); );
let code = ` let code = `
@@ -100,29 +125,36 @@ function generate_server(routes: Route[], path_to_routes: string) {
export const routes = { export const routes = {
server_routes: [ server_routes: [
${routes.server_routes.map(route => { ${routes.server_routes.map(route => `{
const params = route.params.length === 0 // ${route.file}
? '{}' pattern: ${route.pattern},
: `{ ${route.params.map((part, i) => `${part}: match[${i + 1}]`).join(', ')} }`; handlers: ${route.name},
params: ${route.params.length > 0
return `{ id: '${route.id}', pattern: ${route.pattern}, params: ${route.params.length > 0 ? `match` : `()`} => (${params}), handlers: route_${route.id} }`; ? `match => ({ ${route.params.map((param, i) => `${param}: match[${i + 1}]`).join(', ')} })`
}).join(',\n\t\t\t\t')} : `() => ({})`}
}`).join(',\n\n\t\t\t\t')}
], ],
pages: [ pages: [
${pages.map(page => { ${routes.pages.map(page => `{
const params = page.params.length === 0 // ${page.parts[page.parts.length - 1].component.file}
? '{}' pattern: ${page.pattern},
: `{ ${page.params.map((part, i) => `${part}: match[${i + 1}]`).join(', ')} }`; parts: [
${page.parts.map(part => {
if (part.params.length > 0) {
const props = part.params.map((param, i) => `${param}: match[${i + 1}]`);
return `{ component: ${part.component.name}, params: match => ({ ${props.join(', ')} }) }`;
}
return `{ id: '${page.id}', pattern: ${page.pattern}, params: ${page.params.length > 0 ? `match` : `()`} => (${params}), handler: page_${page.id} }`; return `{ component: ${part.component.name} }`;
}).join(',\n\t\t\t\t')} }).join(',\n\t\t\t\t\t\t')}
]
}`).join(',\n\n\t\t\t\t')}
], ],
error: { root,
error: true,
handler: error error
}
};`.replace(/^\t\t/gm, '').trim(); };`.replace(/^\t\t/gm, '').trim();
return code; return code;

View File

@@ -1,29 +1,10 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { locations } from '../config'; import { locations } from '../config';
import { Page, PageComponent, ServerRoute } from '../interfaces';
type Component = {
name: string;
file: string;
};
type Page = {
pattern: RegExp;
parts: Array<{
component: Component;
params: string[];
}>
};
type ServerRoute = {
name: string;
pattern: RegExp;
file: string;
params: string[];
};
export default function create_routes(cwd = locations.routes()) { export default function create_routes(cwd = locations.routes()) {
const components: Component[] = []; const components: PageComponent[] = [];
const pages: Page[] = []; const pages: Page[] = [];
const server_routes: ServerRoute[] = []; const server_routes: ServerRoute[] = [];
@@ -32,7 +13,7 @@ export default function create_routes(cwd = locations.routes()) {
parent_segments: Part[][], parent_segments: Part[][],
parent_params: string[], parent_params: string[],
stack: Array<{ stack: Array<{
component: Component, component: PageComponent,
params: string[] params: string[]
}> }>
) { ) {

View File

@@ -18,4 +18,24 @@ export type Template = {
export type Store = { export type Store = {
get: () => any; get: () => any;
};
export type PageComponent = {
name: string;
file: string;
};
export type Page = {
pattern: RegExp;
parts: Array<{
component: PageComponent;
params: string[];
}>
};
export type ServerRoute = {
name: string;
pattern: RegExp;
file: string;
params: string[];
}; };