incorporate Sirv, and add a sapper.start() function

This commit is contained in:
Rich Harris
2019-05-09 21:32:13 -04:00
parent 5c07080207
commit bedbcb834b
14 changed files with 82 additions and 35 deletions

View File

@@ -336,7 +336,7 @@ export async function hydrate_target(target: Target): Promise<{
}
function load_css(chunk: string) {
const href = `client/${chunk}`;
const href = `sapper/${chunk}`;
if (document.querySelector(`link[href="${href}"]`)) return;
return new Promise((fulfil, reject) => {

View File

@@ -1 +1,14 @@
export { default as middleware } from './middleware/index';
import * as http from 'http';
import middleware from './middleware/index';
import { StartOptions, MiddlewareOptions, Handler } from './types';
export { middleware };
export function start(opts: StartOptions = {}) {
const handler = middleware(opts) as Handler;
const server = http.createServer(handler as http.ServerOptions);
server.listen(opts.port || process.env.PORT);
return server;
}

View File

@@ -5,7 +5,7 @@ import cookie from 'cookie';
import devalue from 'devalue';
import fetch from 'node-fetch';
import URL from 'url';
import { Manifest, Page, Req, Res } from './types';
import { Manifest, Page, Req, Res } from '../types';
import { build_dir, dev, src_dir } from '@sapper/internal/manifest-server';
import App from '@sapper/internal/App.svelte';
@@ -21,9 +21,8 @@ export function get_page_handler(
? () => read_template(src_dir)
: (str => () => str)(read_template(build_dir));
const has_service_worker = fs.existsSync(path.join(build_dir, 'service-worker.js'));
const has_service_worker = fs.existsSync(path.join(build_dir, 'service-worker/service-worker.js'));
const { server_routes, pages } = manifest;
const error_route = manifest.error;
function handle_error(req: Req, res: Res, statusCode: number, error: Error | string) {
@@ -63,7 +62,7 @@ export function get_page_handler(
// TODO add dependencies and CSS
const link = preloaded_chunks
.filter(file => file && !file.match(/\.map$/))
.map(file => `<${req.baseUrl}/client/${file}>;rel="modulepreload"`)
.map(file => `<${req.baseUrl}/sapper/${file}>;rel="modulepreload"`)
.join(', ');
res.setHeader('Link', link);
@@ -72,7 +71,7 @@ export function get_page_handler(
.filter(file => file && !file.match(/\.map$/))
.map((file) => {
const as = /\.css$/.test(file) ? 'style' : 'script';
return `<${req.baseUrl}/client/${file}>;rel="preload";as="${as}"`;
return `<${req.baseUrl}/sapper/${file}>;rel="preload";as="${as}"`;
})
.join(', ');
@@ -263,14 +262,14 @@ export function get_page_handler(
}
const file = [].concat(build_info.assets.main).filter(file => file && /\.js$/.test(file))[0];
const main = `${req.baseUrl}/client/${file}`;
const main = `${req.baseUrl}/sapper/${file}`;
if (build_info.bundler === 'rollup') {
if (build_info.legacy_assets) {
const legacy_main = `${req.baseUrl}/client/legacy/${build_info.legacy_assets.main}`;
script += `(function(){try{eval("async function x(){}");var main="${main}"}catch(e){main="${legacy_main}"};var s=document.createElement("script");try{new Function("if(0)import('')")();s.src=main;s.type="module";s.crossOrigin="use-credentials";}catch(e){s.src="${req.baseUrl}/client/shimport@${build_info.shimport}.js";s.setAttribute("data-main",main);}document.head.appendChild(s);}());`;
const legacy_main = `${req.baseUrl}/sapper/legacy/${build_info.legacy_assets.main}`;
script += `(function(){try{eval("async function x(){}");var main="${main}"}catch(e){main="${legacy_main}"};var s=document.createElement("script");try{new Function("if(0)import('')")();s.src=main;s.type="module";s.crossOrigin="use-credentials";}catch(e){s.src="${req.baseUrl}/sapper/shimport@${build_info.shimport}.js";s.setAttribute("data-main",main);}document.head.appendChild(s);}());`;
} else {
script += `var s=document.createElement("script");try{new Function("if(0)import('')")();s.src="${main}";s.type="module";s.crossOrigin="use-credentials";}catch(e){s.src="${req.baseUrl}/client/shimport@${build_info.shimport}.js";s.setAttribute("data-main","${main}")}document.head.appendChild(s)`;
script += `var s=document.createElement("script");try{new Function("if(0)import('')")();s.src="${main}";s.type="module";s.crossOrigin="use-credentials";}catch(e){s.src="${req.baseUrl}/sapper/shimport@${build_info.shimport}.js";s.setAttribute("data-main","${main}")}document.head.appendChild(s)`;
}
} else {
script += `</script><script src="${main}">`;
@@ -295,7 +294,7 @@ export function get_page_handler(
});
styles = Array.from(css_chunks)
.map(href => `<link rel="stylesheet" href="client/${href}">`)
.map(href => `<link rel="stylesheet" href="sapper/${href}">`)
.join('')
} else {
styles = (css && css.code ? `<style>${css.code}</style>` : '');
@@ -327,12 +326,12 @@ export function get_page_handler(
return function find_route(req: Req, res: Res, next: () => void) {
if (req.path === '/service-worker-index.html') {
const homePage = pages.find(page => page.pattern.test('/'));
const homePage = manifest.pages.find(page => page.pattern.test('/'));
handle_page(homePage, req, res);
return;
}
for (const page of pages) {
for (const page of manifest.pages) {
if (page.pattern.test(req.path)) {
handle_page(page, req, res);
return;

View File

@@ -1,4 +1,4 @@
import { Req, Res, ServerRoute } from './types';
import { Req, Res, ServerRoute } from '../types';
export function get_server_route_handler(routes: ServerRoute[]) {
async function handle_route(route: ServerRoute, req: Req, res: Res, next: () => void) {

View File

@@ -1,23 +1,41 @@
import fs from 'fs';
import path from 'path';
import sirv from 'sirv';
import { build_dir, dev, manifest } from '@sapper/internal/manifest-server';
import { Handler, Req, Res } from './types';
import { Handler, Req, Res, MiddlewareOptions } from '../types';
import { get_server_route_handler } from './get_server_route_handler';
import { get_page_handler } from './get_page_handler';
import { lookup } from './mime';
import { stringify } from 'querystring';
export default function middleware(opts: {
session?: (req: Req, res: Res) => any,
ignore?: any
} = {}) {
export default function middleware(opts: MiddlewareOptions = {}) {
const { session, ignore } = opts;
let emitted_basepath = false;
return compose_handlers(ignore, [
sirv('static', {
dev,
setHeaders: opts.static && opts.static.headers && ((res: Response, pathname: string, stats: fs.Stats) => {
const headers = opts.static.headers(pathname, stats);
for (const k in headers) res.setHeader(k, headers[k]);
})
}),
sirv(`${build_dir}/client`, {
dev,
maxAge: 31536000,
immutable: true
}),
sirv(`${build_dir}/service-worker`, {
dev,
maxAge: 300
}),
(req: Req, res: Res, next: () => void) => {
if (req.baseUrl === undefined) {
let { originalUrl } = req;
let originalUrl = req.originalUrl || req.url;
if (req.url === '/' && originalUrl[originalUrl.length - 1] !== '/') {
originalUrl += '/';
}

View File

@@ -1,3 +1,4 @@
import { Stats } from 'fs';
import { ClientRequest, ServerResponse } from 'http';
export type ServerRoute = {
@@ -37,6 +38,18 @@ export type Props = {
[key: string]: any;
};
export interface MiddlewareOptions {
static?: {
headers?: (pathname: string, stats: Stats) => Record<string, string>
},
session?: (req: Req, res: Res) => any,
ignore?: any
}
export interface StartOptions extends MiddlewareOptions {
port?: number;
}
export interface Req extends ClientRequest {
url: string;
baseUrl: string;