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

@@ -24,8 +24,9 @@ function template(kind, external) {
external,
plugins: [
resolve({
extensions: ['.mjs', '.js', '.ts']
extensions: ['.mjs', '.js', '.json', '.ts']
}),
json(),
commonjs(),
string({
include: '**/*.md'

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;

View File

@@ -122,7 +122,7 @@ export async function build({
const client_files = client_result.chunks
.filter(chunk => !chunk.file.endsWith('.map')) // SW does not need to cache sourcemap files
.map(chunk => `client/${chunk.file}`);
.map(chunk => `sapper/${chunk.file}`);
create_serviceworker_manifest({
manifest_data,

View File

@@ -333,7 +333,7 @@ class Watcher extends EventEmitter {
JSON.stringify(result.to_json(manifest_data, this.dirs), null, ' ')
);
const client_files = result.chunks.map(chunk => `client/${chunk.file}`);
const client_files = result.chunks.map(chunk => `sapper/${chunk.file}`);
create_serviceworker_manifest({
manifest_data,

View File

@@ -60,9 +60,8 @@ async function _export({
rimraf(export_dir);
copy(static_files, export_dir);
copy(path.join(build_dir, 'client'), path.join(export_dir, 'client'));
copy(path.join(build_dir, 'service-worker.js'), path.join(export_dir, 'service-worker.js'));
copy(path.join(build_dir, 'service-worker.js.map'), path.join(export_dir, 'service-worker.js.map'));
copy(path.join(build_dir, 'client'), export_dir);
copy(path.join(build_dir, 'service-worker'), export_dir);
const defaultPort = process.env.PORT ? parseInt(process.env.PORT) : 3000;
const port = await ports.find(defaultPort);

View File

@@ -1,9 +1,13 @@
import * as fs from 'fs';
import { mkdirp } from './fs_utils';
export function copy_shimport(dest: string) {
mkdirp(`${dest}/client/sapper`);
const shimport_version = require('shimport/package.json').version;
fs.writeFileSync(
`${dest}/client/shimport@${shimport_version}.js`,
`${dest}/client/sapper/shimport@${shimport_version}.js`,
fs.readFileSync(require.resolve('shimport/index.js'))
);
}

View File

@@ -9,7 +9,7 @@ export default {
},
output: () => {
let dir = `${dest}/client`;
let dir = `${dest}/client/sapper`;
if (process.env.SAPPER_LEGACY_BUILD) dir += `/legacy`;
return {
@@ -45,7 +45,7 @@ export default {
output: () => {
return {
file: `${dest}/service-worker.js`,
file: `${dest}/service-worker/service-worker.js`,
format: 'iife'
}
}

View File

@@ -12,10 +12,10 @@ export default {
output: () => {
return {
path: `${dest}/client`,
path: `${dest}/client/sapper`,
filename: '[hash]/[name].js',
chunkFilename: '[hash]/[name].[id].js',
publicPath: `client/`
publicPath: `sapper/`
};
}
},
@@ -46,7 +46,7 @@ export default {
output: () => {
return {
path: dest,
path: `${dest}/service-worker`,
filename: '[name].js',
chunkFilename: '[name].[id].[hash].js'
}

View File

@@ -116,7 +116,7 @@ export default function extract_css(client_result: CompileResult, components: Pa
if (!client_result.css_files) return; // Rollup-only for now
let asset_dir = `${dirs.dest}/client`;
let asset_dir = `${dirs.dest}/client/sapper`;
if (process.env.SAPPER_LEGACY_BUILD) asset_dir += '/legacy';
const unclaimed = new Set(client_result.css_files.map(x => x.id));
@@ -238,7 +238,7 @@ export default function extract_css(client_result: CompileResult, components: Pa
map.file = output_file_name;
map.sources = map.sources.map(source => path.relative(asset_dir, source));
fs.writeFileSync(`${asset_dir}/${output_file_name}`, `${code}\n/* sourceMappingURL=client/${output_file_name}.map */`);
fs.writeFileSync(`${asset_dir}/${output_file_name}`, `${code}\n/* sourceMappingURL=sapper/${output_file_name}.map */`);
fs.writeFileSync(`${asset_dir}/${output_file_name}.map`, JSON.stringify(map, null, ' '));
result.main = output_file_name;