diff --git a/packages/app-utils/src/prerender/index.ts b/packages/app-utils/src/prerender/index.ts index da5b4bbc39f3..45624165aa35 100644 --- a/packages/app-utils/src/prerender/index.ts +++ b/packages/app-utils/src/prerender/index.ts @@ -3,9 +3,9 @@ import { dirname, resolve as resolve_path } from 'path'; import { parse, resolve, URLSearchParams } from 'url'; import { mkdirp } from '../files'; import { render } from '../render'; -import { RouteManifest } from '../types'; +import { PageResponse, RouteManifest } from '../types'; -function clean_html(html) { +function clean_html(html: string) { return html .replace(//gm, '') .replace(/()[\s\S]*?<\/script>/gm, '$1') @@ -13,17 +13,17 @@ function clean_html(html) { .replace(//gm, ''); } -function get_href(attrs) { +function get_href(attrs: string) { const match = /href\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs); return match && (match[1] || match[2] || match[3]); } -function get_src(attrs) { +function get_src(attrs: string) { const match = /src\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs); return match && (match[1] || match[2] || match[3]); } -function get_srcset_urls(attrs) { +function get_srcset_urls(attrs: string) { const results = []; // Note that the srcset allows any ASCII whitespace, including newlines. const match = /srcset\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/s.exec(attrs); @@ -130,9 +130,11 @@ export async function prerender({ log.error(`${rendered.status} ${path}`); } - if (rendered.dependencies) { - for (const path in rendered.dependencies) { - const result = rendered.dependencies[path]; + const dependencies = (rendered as PageResponse).dependencies; + + if (dependencies) { + for (const path in dependencies) { + const result = dependencies[path]; const response_type = Math.floor(result.status / 100); const is_html = result.headers['content-type'] === 'text/html'; diff --git a/packages/app-utils/src/render/index.ts b/packages/app-utils/src/render/index.ts index bfdcb645e126..29d5e365c1a5 100644 --- a/packages/app-utils/src/render/index.ts +++ b/packages/app-utils/src/render/index.ts @@ -3,7 +3,7 @@ import render_page from './page'; import render_route from './route'; import { EndpointResponse, IncomingRequest, PageResponse, RenderOptions } from '../types'; -function md5(body) { +function md5(body: string) { return createHash('md5').update(body).digest('hex'); } diff --git a/packages/app-utils/src/render/page.ts b/packages/app-utils/src/render/page.ts index 50c94cc2efdf..4312b9c5bc8f 100644 --- a/packages/app-utils/src/render/page.ts +++ b/packages/app-utils/src/render/page.ts @@ -6,13 +6,13 @@ import devalue from 'devalue'; import fetch, { Response } from 'node-fetch'; import * as mime from 'mime'; import { render } from './index'; -import { IncomingRequest, RenderOptions, PageManifest } from '../types'; +import { IncomingRequest, RenderOptions, PageManifest, EndpointResponse, PageResponse, Headers } from '../types'; const noop = () => {}; type FetchOpts = { method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS'; - headers?: Record; + headers?: Headers; body?: any; }; @@ -20,8 +20,13 @@ export default async function render_page( request: IncomingRequest, context: any, options: RenderOptions -) { - let redirected; +): Promise<{ + status: number, + body?: string, + headers?: Headers, + dependencies?: Record< string, EndpointResponse | PageResponse> +}> { + let redirected: { status: number; location?: string; headers: Headers }; let preload_error; const page: PageManifest = options.manifest.pages.find(page => page.pattern.test(request.path)); @@ -53,10 +58,10 @@ export default async function render_page( l++; }); - const dependencies = {}; + const dependencies: Record = {}; const preload_context = { - redirect: (status, location) => { + redirect: (status: number, location: string) => { if (redirected && (redirected.status !== status || redirected.location !== location)) { throw new Error(`Conflicting redirects`); } diff --git a/packages/app-utils/src/render/route.ts b/packages/app-utils/src/render/route.ts index 2ef2d524e369..994b7bb1dbc8 100644 --- a/packages/app-utils/src/render/route.ts +++ b/packages/app-utils/src/render/route.ts @@ -1,10 +1,14 @@ -import { IncomingRequest, RenderOptions, EndpointManifest } from '../types'; +import { IncomingRequest, RenderOptions, EndpointManifest, Headers } from '../types'; export default function render_route( request: IncomingRequest, context: any, options: RenderOptions -) { +): Promise<{ + status: number, + body: string, + headers?: Headers +}> { const route: EndpointManifest = options.manifest.endpoints.find(route => route.pattern.test(request.path)); if (!route) return; @@ -53,7 +57,7 @@ export default function render_route( }); } -function lowercase_keys(obj) { +function lowercase_keys(obj: Record) { const clone = {}; for (const key in obj) { clone[key.toLowerCase()] = obj[key]; diff --git a/packages/kit/.gitignore b/packages/kit/.gitignore index a42891b7aa81..fc683b4725d6 100644 --- a/packages/kit/.gitignore +++ b/packages/kit/.gitignore @@ -1,4 +1,5 @@ .DS_Store /node_modules /dist -/assets/client.* \ No newline at end of file +/assets/client.* +/client/**/*.d.ts diff --git a/packages/kit/client/tsconfig.json b/packages/kit/client/tsconfig.json new file mode 100644 index 000000000000..83f2c88c0e76 --- /dev/null +++ b/packages/kit/client/tsconfig.json @@ -0,0 +1,15 @@ +{ + /* Generates the typings for client code */ + "compilerOptions": { + "resolveJsonModule": true, + "module": "esnext", + "moduleResolution": "node", + "target": "ES6", + "esModuleInterop": true, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "." + }, + "include": ["../src/client/**/*", "../src/ambient.d.ts"], + "lib": ["ES2020", "dom", "node"] +} diff --git a/packages/kit/package.json b/packages/kit/package.json index f4f7373098b5..1bdf25195561 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -33,12 +33,13 @@ }, "files": [ "assets", - "dist" + "dist", + "client" ], "scripts": { "dev": "rollup -cw", "build": "rollup -c", - "prepare": "npm run build", + "prepare": "npm run build && cd client && tsc", "prepublishOnly": "npm run build" } } diff --git a/packages/kit/src/ambient.d.ts b/packages/kit/src/ambient.d.ts new file mode 100644 index 000000000000..ed02887ddc9b --- /dev/null +++ b/packages/kit/src/ambient.d.ts @@ -0,0 +1,11 @@ +declare module "MANIFEST" { + export const components: any[]; + export const routes: any[]; + export const Layout: any; + export const ErrorComponent: any; +} + +declare module "ROOT" { + const root: any; + export default root; +} diff --git a/packages/kit/src/api/dev/loader.ts b/packages/kit/src/api/dev/loader.ts index cedbbf529278..5444d8cff66a 100644 --- a/packages/kit/src/api/dev/loader.ts +++ b/packages/kit/src/api/dev/loader.ts @@ -35,7 +35,7 @@ export default function loader(snowpack: SnowpackDevServer): Loader { let data: string; try { - const result = await snowpack.loadUrl(url, {isSSR: true, encoding: 'utf-8'}); + const result = await snowpack.loadUrl(url, {isSSR: true, encoding: 'utf8'}); data = result.contents; } catch (err) { throw new Error(`Failed to load ${url}: ${err.message}`); diff --git a/packages/kit/src/api/dev/sourcemap_stacktrace.ts b/packages/kit/src/api/dev/sourcemap_stacktrace.ts index f845cc61d0e1..c1b6ff1fe391 100644 --- a/packages/kit/src/api/dev/sourcemap_stacktrace.ts +++ b/packages/kit/src/api/dev/sourcemap_stacktrace.ts @@ -70,7 +70,9 @@ export function sourcemap_stacktrace(stack: string) { return input; } - const consumer = new SourceMapConsumer(raw_sourcemap); + // TODO: according to typings, this code cannot work; + // the constructor returns a promise that needs to be awaited + const consumer = new (SourceMapConsumer as any)(raw_sourcemap); const pos = consumer.originalPositionFor({ line: Number(line), column: Number(column), diff --git a/packages/kit/src/cli.ts b/packages/kit/src/cli.ts index 2bf7c9f27d17..3f8b3fe9f6bb 100644 --- a/packages/kit/src/cli.ts +++ b/packages/kit/src/cli.ts @@ -2,9 +2,9 @@ import relative from 'require-relative'; import sade from 'sade'; import colors from 'kleur'; import * as pkg from '../package.json'; -import { ReadyEvent } from './interfaces'; +import { ReadyEvent, SvelteAppConfig } from './interfaces'; -let config; +let config: SvelteAppConfig; try { config = relative('./svelte.config.js', process.cwd()); diff --git a/packages/kit/tsconfig.json b/packages/kit/tsconfig.json new file mode 100644 index 000000000000..29d4d3b9c173 --- /dev/null +++ b/packages/kit/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "module": "esnext", + "moduleResolution": "node", + "target": "ES6", + "esModuleInterop": true, + "noEmit": true + }, + "include": ["src/**/*"], + "lib": ["ES2020", "dom", "node"] +} diff --git a/packages/snowpack-config/snowpack.config.js b/packages/snowpack-config/snowpack.config.js index 5600915b924c..521186b3abc8 100644 --- a/packages/snowpack-config/snowpack.config.js +++ b/packages/snowpack-config/snowpack.config.js @@ -25,6 +25,7 @@ module.exports = { 'src/setup': '/_app/setup' }, alias: { + '@sveltejs/kit': '/_app/main', $components: './src/components' } }; \ No newline at end of file