Skip to content

Commit

Permalink
Merge branch 'master' of github.com:sveltejs/kit
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Nov 8, 2020
2 parents 964a8d2 + 694239a commit 819ea58
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 152 deletions.
7 changes: 7 additions & 0 deletions packages/app-utils/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export {
EndpointManifest,
PageManifest,
PageComponentManifest,
SetupModule,
SSRComponentModule
} from './src/types';
14 changes: 8 additions & 6 deletions packages/app-utils/src/renderer/manifest/index.spec.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ const examplePageComponentManifest: PageComponentManifest = {
default: true,
type: 'foo',
name: 'bar',
file: 'baz'
}
file: 'baz',
url: 'boo'
};

const examplePageManifest: PageManifest = {
pattern: /a/,
Expand All @@ -14,19 +15,20 @@ const examplePageManifest: PageManifest = {
component: examplePageComponentManifest,
params: [ 'quux', 'corge' ]
} ]
}
};

const exampleEndpointManifest: EndpointManifest = {
name: 'grault',
pattern: /b/,
file: 'garply',
file: 'garply',
url: 'bla',
params: [ 'waldo', 'fred' ]
}
};

export const exampleRouteManifest: RouteManifest = {
layout: examplePageComponentManifest,
error: examplePageComponentManifest,
components: [ examplePageComponentManifest, examplePageComponentManifest ],
pages: [ examplePageManifest, examplePageManifest ],
endpoints: [ exampleEndpointManifest, exampleEndpointManifest ]
}
};
65 changes: 17 additions & 48 deletions packages/app-utils/src/renderer/render/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ type FetchOpts = {
export default async function render_page(
request: IncomingRequest,
context: any,
options: RenderOptions
options: RenderOptions,
status: number = 200,
error: Error | null = null
): Promise<{
status: number,
body: string,
Expand Down Expand Up @@ -192,14 +194,15 @@ export default async function render_page(
});

const props: Record<string, any> = {
status: 200,
error: null,
status,
error,
stores: {
page: readable({
host: request.host,
path: request.path,
query: request.query,
params
params,
error
}, noop),
preloading: readable(null, noop),
session: writable(session)
Expand Down Expand Up @@ -266,8 +269,8 @@ export default async function render_page(
<script>
__SVELTE__ = {
baseUrl: "${baseUrl}",
status: 200,
error: null,
status: ${status},
error: ${serialize_error(error)},
preloaded: ${serialized_preloads},
session: ${serialized_session}
};
Expand All @@ -283,52 +286,18 @@ export default async function render_page(
body: html,
dependencies
};
} catch (error) {
console.error(error.stack);

const status = error.status || 500;

try {
const rendered = options.root.default.render({ status, error });

const head = `${rendered.head}
<script type="module">
import { start } from '/_app/${options.client.entry}';
} catch (thrown) {
console.error(thrown.stack);

start({
target: document.body
});
</script>`.replace(/^\t\t\t/gm, '');

const body = `${rendered.html}
<script>
__SVELTE__ = {
baseUrl: "${baseUrl}",
status: ${status},
error: ${serialize_error(error)},
preloaded: null,
session: ${serialized_session}
};
</script>`.replace(/^\t\t\t/gm, '');

const html = options.template
.replace('%svelte.head%', head)
.replace('%svelte.body%', body);

return {
status,
headers: {
'content-type': 'text/html'
},
body: html,
dependencies: {}
};
} catch (error) {
if (!error) {
const status = thrown.status || 500;
return render_page(request, context, options, status, thrown);
} else {
// oh lawd now you've done it
return {
status: 500,
headers: {},
body: error.stack, // TODO probably not in prod?
body: thrown.stack, // TODO probably not in prod?
dependencies: {}
};
}
Expand All @@ -345,7 +314,7 @@ function try_serialize(data: any, fail?: (err: Error) => void) {
}

// Ensure we return something truthy so the client will not re-render the page over the error
function serialize_error(error: Error) {
function serialize_error(error?: Error) {
if (!error) return null;
let serialized = try_serialize(error);
if (!serialized) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,77 +4,91 @@ export type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS';

export type Headers = Record<string, string>;

export type IncomingRequest = {
export interface IncomingRequest {
host: string | null; // TODO is this actually necessary?
method: Method;
headers: Headers;
body: any; // TODO
path: string;
query: URLSearchParams;
};
}

export type EndpointResponse = {
export interface EndpointResponse {
status: number;
headers: Headers;
body: any; // TODO what types can body be?
};
}

export type PageResponse = EndpointResponse & {
export interface PageResponse extends EndpointResponse {
dependencies: Record<string, EndpointResponse>;
};
}

type SetupModule = {
export interface SetupModule {
prepare?: (headers: Headers) => Promise<{ context: any, headers: Headers }>;
getSession?: (context: any) => Promise<any>;
setSession?: (context: any, session: any) => Promise<any>;
};
}

export type RenderOptions = {
export interface SSRComponentModule {
default: SSRComponent;
}

export interface SSRComponent {
render(props: unknown): {
html: string
head: string
css: { code: string, map: unknown };
}
}

export interface RenderOptions {
only_prerender: boolean; // TODO this shouldn't really be part of the public API
static_dir: string;
template: string;
manifest: RouteManifest;
client: ClientManifest;
root: any; // TODO
root: SSRComponentModule;
setup: SetupModule;
load: (route: PageComponentManifest | EndpointManifest) => Promise<any>; // TODO
dev: boolean; // TODO this is awkward
};
}

export type PageComponentManifest = {
export interface PageComponentManifest {
default?: boolean;
type?: string;
url: string;
name: string;
file: string;
};
}

export type PageManifest = {
export interface PageManifest {
pattern: RegExp;
path: string;
parts: Array<{
component: PageComponentManifest;
params: string[];
}>;
};
}

export type EndpointManifest = {
export interface EndpointManifest {
name: string;
pattern: RegExp;
file: string;
url: string;
params: string[];
};
}

export type RouteManifest = {
export interface RouteManifest {
error: PageComponentManifest;
layout: PageComponentManifest;
components: PageComponentManifest[];
pages: PageManifest[];
endpoints: EndpointManifest[];
};
}

export type ClientManifest = {
export interface ClientManifest {
entry: string;
deps: Record<string, { js: string[], css: string[] }>
};
}

export type Loader = (item: PageComponentManifest | EndpointManifest) => Promise<any>; // TODO types for modules
37 changes: 24 additions & 13 deletions packages/create-svelte/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import path from 'path';
import prompts from 'prompts/lib/index';
import glob from 'tiny-glob/sync';
import gitignore_contents from '../template/.gitignore';
import add_css from './modifications/add_css';
import add_typescript from './modifications/add_typescript';
import versions from './versions';

Expand Down Expand Up @@ -84,19 +85,7 @@ async function main(): Promise<void> {

console.log(bold(green(`✔ Copied project files`)));

// modifications
const modifications = [['Use TypeScript in components?', false, add_typescript]] as const;

for (const [message, initial, fn] of modifications) {
const response = await prompts({
type: 'confirm',
name: 'value',
message,
initial
});

await fn(target, response.value);
}
await prompt_modifications(target);

console.log(`\nNext steps:`);
let i = 1;
Expand All @@ -113,4 +102,26 @@ async function main(): Promise<void> {
console.log('\nStuck? Visit us at https://svelte.dev/chat\n');
}

async function prompt_modifications(target: string) {
const ts_response = await prompts({
type: 'confirm',
name: 'value',
message: 'Use TypeScript in components?',
initial: false
});
await add_typescript(target, ts_response.value);

const css_response = await prompts({
type: 'select',
name: 'value',
message: 'What do you want to use for writing Styles in Svelte components?',
choices: [
{ title: 'CSS', value: 'css' },
{ title: 'Less', value: 'less' },
{ title: 'SCSS', value: 'scss' }
]
});
await add_css(target, css_response.value);
}

main();
42 changes: 42 additions & 0 deletions packages/create-svelte/cli/modifications/add_css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { bold, green } from 'kleur/colors';
import { add_svelte_prepocess_to_config, update_component, update_package_json } from './utils';

export default async function add_css(cwd: string, which: 'css' | 'less' | 'scss'): Promise<void> {
if (which === 'css') {
console.log(`You can add support for CSS preprocessors like SCSS/Less/PostCSS later.`);
} else if (which === 'less') {
update_package_json(cwd, {
less: '^3.0.0',
'svelte-preprocess': '^4.0.0'
});
update_component(cwd, 'src/components/Counter.svelte', [['<style>', '<style lang="less">']]);
update_component(cwd, 'src/routes/index.svelte', [['<style>', '<style lang="less">']]);
add_svelte_prepocess_to_config(cwd);
console.log(
bold(
green(
`✔ Added Less support. ` +
`To use it inside Svelte components, add lang="less" to the attributes of a style tag.`
)
)
);
} else if (which === 'scss') {
update_package_json(cwd, {
sass: '^1.0.0',
'svelte-preprocess': '^4.0.0'
});
update_component(cwd, 'src/components/Counter.svelte', [['<style>', '<style lang="scss">']]);
update_component(cwd, 'src/routes/index.svelte', [['<style>', '<style lang="scss">']]);
add_svelte_prepocess_to_config(cwd);
console.log(
bold(
green(
`✔ Added SCSS support. ` +
`To use it inside Svelte components, add lang="scss" to the attributes of a style tag.`
)
)
);
} else {
console.error(`Unknown CSS option "${which}"`);
}
}
5 changes: 3 additions & 2 deletions packages/kit/src/api/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { copy_assets } from '../utils';
import { create_app } from '../../core/create_app';
import { SvelteAppConfig } from '../../interfaces';
import { css_injection } from './css_injection';
import { EndpointManifest } from '@sveltejs/app-utils';

const exec = promisify(child_process.exec);

Expand Down Expand Up @@ -67,9 +68,9 @@ export async function build(config: SvelteAppConfig) {
fs.writeFileSync(setup_file, '');
}

await exec(`${snowpack_bin} build --out=${unoptimized}/server --ssr`);
await exec(`node ${snowpack_bin} build --out=${unoptimized}/server --ssr`);
log.success('server');
await exec(`${snowpack_bin} build --out=${unoptimized}/client`);
await exec(`node ${snowpack_bin} build --out=${unoptimized}/client`);
log.success('client');
}

Expand Down
Loading

0 comments on commit 819ea58

Please sign in to comment.