mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-13 19:45:26 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d13d6209ed | ||
|
|
05aef8de71 | ||
|
|
429f44e3a6 | ||
|
|
f8e853c02b | ||
|
|
bedbcb834b |
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,17 +1,5 @@
|
||||
# sapper changelog
|
||||
|
||||
## 0.27.1
|
||||
|
||||
* Prevent infinite loop if `preload` errors ([#677](https://github.com/sveltejs/sapper/pull/677))
|
||||
* Allow disabling of live reload ([#683](https://github.com/sveltejs/sapper/pull/683))
|
||||
* Let browser handle initial scroll ([#331](https://github.com/sveltejs/sapper/issues/331))
|
||||
* Allow custom route file extensions via `--ext` ([#632](https://github.com/sveltejs/sapper/pull/632))
|
||||
* Wait for server to restart before attaching debugger ([#694](https://github.com/sveltejs/sapper/pull/694))
|
||||
* Fix export queue ([#698](https://github.com/sveltejs/sapper/pull/698))
|
||||
* Rerun `preload` functions when query changes ([#701](https://github.com/sveltejs/sapper/issues/701))
|
||||
* Navigate when spread route changes ([#688](https://github.com/sveltejs/sapper/issues/688))
|
||||
|
||||
|
||||
## 0.27.0
|
||||
|
||||
* Change license from LIL to MIT ([#652](https://github.com/sveltejs/sapper/pull/652))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sapper",
|
||||
"version": "0.27.1",
|
||||
"version": "0.27.0",
|
||||
"description": "Military-grade apps, engineered by Svelte",
|
||||
"bin": {
|
||||
"sapper": "./sapper"
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -22,7 +22,6 @@ let root_component: Component;
|
||||
let current_token: {};
|
||||
let root_preloaded: Promise<any>;
|
||||
let current_branch = [];
|
||||
let current_query = '{}';
|
||||
|
||||
const stores = {
|
||||
page: writable({}),
|
||||
@@ -251,28 +250,10 @@ async function render(redirect: Redirect, branch: any[], props: any, page: Page)
|
||||
}
|
||||
|
||||
current_branch = branch;
|
||||
current_query = JSON.stringify(page.query);
|
||||
ready = true;
|
||||
session_dirty = false;
|
||||
}
|
||||
|
||||
function part_changed(i, segment, match, stringified_query) {
|
||||
// TODO only check query string changes for preload functions
|
||||
// that do in fact depend on it (using static analysis or
|
||||
// runtime instrumentation)
|
||||
if (stringified_query !== current_query) return true;
|
||||
|
||||
const previous = current_branch[i];
|
||||
|
||||
if (!previous) return false;
|
||||
if (segment !== previous.segment) return true;
|
||||
if (previous.match) {
|
||||
if (JSON.stringify(previous.match.slice(1, i + 2)) !== JSON.stringify(match.slice(1, i + 2))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function hydrate_target(target: Target): Promise<{
|
||||
redirect?: Redirect;
|
||||
props?: any;
|
||||
@@ -311,15 +292,11 @@ export async function hydrate_target(target: Target): Promise<{
|
||||
let l = 1;
|
||||
|
||||
try {
|
||||
const stringified_query = JSON.stringify(page.query);
|
||||
const match = route.pattern.exec(page.path);
|
||||
|
||||
let segment_dirty = false;
|
||||
|
||||
branch = await Promise.all(route.parts.map(async (part, i) => {
|
||||
const segment = segments[i];
|
||||
|
||||
if (part_changed(i, segment, match, stringified_query)) segment_dirty = true;
|
||||
if (current_branch[i] && current_branch[i].segment !== segment) segment_dirty = true;
|
||||
|
||||
props.segments[l] = segments[i + 1]; // TODO make this less confusing
|
||||
if (!part) return { segment };
|
||||
@@ -347,7 +324,7 @@ export async function hydrate_target(target: Target): Promise<{
|
||||
preloaded = initial_data.preloaded[i + 1];
|
||||
}
|
||||
|
||||
return (props[`level${j}`] = { component, props: preloaded, segment, match, part: part.i });
|
||||
return (props[`level${j}`] = { component, props: preloaded, segment, part: part.i });
|
||||
}));
|
||||
} catch (error) {
|
||||
props.error = error;
|
||||
@@ -359,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) => {
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function start(opts: {
|
||||
if (initial_data.error) return handle_error(url);
|
||||
|
||||
const target = select_target(url);
|
||||
if (target) return navigate(target, uid, true, hash);
|
||||
if (target) return navigate(target, uid, false, hash);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,17 @@
|
||||
export { default as middleware } from './middleware/index';
|
||||
import http from 'http';
|
||||
import middleware from './middleware/index';
|
||||
import { StartOptions, MiddlewareOptions, Handler } from './types';
|
||||
|
||||
export { middleware };
|
||||
|
||||
export function server(opts: MiddlewareOptions) {
|
||||
const handler = middleware(opts) as Handler;
|
||||
return http.createServer(handler as http.ServerOptions);
|
||||
}
|
||||
|
||||
export function start(opts: StartOptions = {}) {
|
||||
const s = server(opts);
|
||||
s.listen(opts.port || process.env.PORT);
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -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,20 +21,10 @@ 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 bail(req: Req, res: Res, err: Error) {
|
||||
console.error(err);
|
||||
|
||||
const message = dev ? escape_html(err.message) : 'Internal server error';
|
||||
|
||||
res.statusCode = 500;
|
||||
res.end(`<pre>${message}</pre>`);
|
||||
}
|
||||
|
||||
function handle_error(req: Req, res: Res, statusCode: number, error: Error | string) {
|
||||
handle_page({
|
||||
pattern: null,
|
||||
@@ -72,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);
|
||||
@@ -81,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(', ');
|
||||
|
||||
@@ -178,10 +168,6 @@ export function get_page_handler(
|
||||
|
||||
preloaded = await Promise.all(toPreload);
|
||||
} catch (err) {
|
||||
if (error) {
|
||||
return bail(req, res, err)
|
||||
}
|
||||
|
||||
preload_error = { statusCode: 500, message: err };
|
||||
preloaded = []; // appease TypeScript
|
||||
}
|
||||
@@ -276,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}">`;
|
||||
@@ -308,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,8 +313,11 @@ export function get_page_handler(
|
||||
res.statusCode = status;
|
||||
res.end(body);
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
if (error) {
|
||||
bail(req, res, err)
|
||||
// we encountered an error while rendering the error page — oops
|
||||
res.statusCode = 500;
|
||||
res.end(`<pre>${escape_html(err.message)}</pre>`);
|
||||
} else {
|
||||
handle_error(req, res, 500, err);
|
||||
}
|
||||
@@ -337,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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,23 +1,42 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import querystring from 'querystring';
|
||||
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';
|
||||
|
||||
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, [
|
||||
(req: Req, res: Res, next: () => void) => {
|
||||
fs.existsSync('static') && 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
|
||||
}),
|
||||
|
||||
function condition_request(req: Req, res: Res, next: () => void) {
|
||||
const qi = req.url.indexOf('?');
|
||||
req.query = ~qi ? querystring.parse(req.url.slice(qi + 1)) : {}
|
||||
|
||||
if (req.baseUrl === undefined) {
|
||||
let { originalUrl } = req;
|
||||
let originalUrl = req.originalUrl || req.url;
|
||||
if (req.url === '/' && originalUrl[originalUrl.length - 1] !== '/') {
|
||||
originalUrl += '/';
|
||||
}
|
||||
@@ -44,21 +63,6 @@ export default function middleware(opts: {
|
||||
next();
|
||||
},
|
||||
|
||||
fs.existsSync(path.join(build_dir, 'service-worker.js')) && serve({
|
||||
pathname: '/service-worker.js',
|
||||
cache_control: 'no-cache, no-store, must-revalidate'
|
||||
}),
|
||||
|
||||
fs.existsSync(path.join(build_dir, 'service-worker.js.map')) && serve({
|
||||
pathname: '/service-worker.js.map',
|
||||
cache_control: 'no-cache, no-store, must-revalidate'
|
||||
}),
|
||||
|
||||
serve({
|
||||
prefix: '/client/',
|
||||
cache_control: dev ? 'no-cache' : 'max-age=31536000, immutable'
|
||||
}),
|
||||
|
||||
get_server_route_handler(manifest.server_routes),
|
||||
|
||||
get_page_handler(manifest, session || noop)
|
||||
@@ -94,40 +98,4 @@ export function should_ignore(uri: string, val: any) {
|
||||
return uri.startsWith(val.charCodeAt(0) === 47 ? val : `/${val}`);
|
||||
}
|
||||
|
||||
export function serve({ prefix, pathname, cache_control }: {
|
||||
prefix?: string,
|
||||
pathname?: string,
|
||||
cache_control: string
|
||||
}) {
|
||||
const filter = pathname
|
||||
? (req: Req) => req.path === pathname
|
||||
: (req: Req) => req.path.startsWith(prefix);
|
||||
|
||||
const cache: Map<string, Buffer> = new Map();
|
||||
|
||||
const read = dev
|
||||
? (file: string) => fs.readFileSync(path.resolve(build_dir, file))
|
||||
: (file: string) => (cache.has(file) ? cache : cache.set(file, fs.readFileSync(path.resolve(build_dir, file)))).get(file)
|
||||
|
||||
return (req: Req, res: Res, next: () => void) => {
|
||||
if (filter(req)) {
|
||||
const type = lookup(req.path);
|
||||
|
||||
try {
|
||||
const file = decodeURIComponent(req.path.slice(1));
|
||||
const data = read(file);
|
||||
|
||||
res.setHeader('Content-Type', type);
|
||||
res.setHeader('Cache-Control', cache_control);
|
||||
res.end(data);
|
||||
} catch (err) {
|
||||
res.statusCode = 404;
|
||||
res.end('not found');
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function noop(){}
|
||||
|
||||
@@ -1,767 +0,0 @@
|
||||
application/andrew-inset ez
|
||||
application/applixware aw
|
||||
application/atom+xml atom
|
||||
application/atomcat+xml atomcat
|
||||
application/atomsvc+xml atomsvc
|
||||
application/ccxml+xml ccxml
|
||||
application/cdmi-capability cdmia
|
||||
application/cdmi-container cdmic
|
||||
application/cdmi-domain cdmid
|
||||
application/cdmi-object cdmio
|
||||
application/cdmi-queue cdmiq
|
||||
application/cu-seeme cu
|
||||
application/davmount+xml davmount
|
||||
application/docbook+xml dbk
|
||||
application/dssc+der dssc
|
||||
application/dssc+xml xdssc
|
||||
application/ecmascript ecma
|
||||
application/emma+xml emma
|
||||
application/epub+zip epub
|
||||
application/exi exi
|
||||
application/font-tdpfr pfr
|
||||
application/gml+xml gml
|
||||
application/gpx+xml gpx
|
||||
application/gxf gxf
|
||||
application/hyperstudio stk
|
||||
application/inkml+xml ink inkml
|
||||
application/ipfix ipfix
|
||||
application/java-archive jar
|
||||
application/java-serialized-object ser
|
||||
application/java-vm class
|
||||
application/javascript js
|
||||
application/json json map
|
||||
application/jsonml+json jsonml
|
||||
application/lost+xml lostxml
|
||||
application/mac-binhex40 hqx
|
||||
application/mac-compactpro cpt
|
||||
application/mads+xml mads
|
||||
application/marc mrc
|
||||
application/marcxml+xml mrcx
|
||||
application/mathematica ma nb mb
|
||||
application/mathml+xml mathml
|
||||
application/mbox mbox
|
||||
application/mediaservercontrol+xml mscml
|
||||
application/metalink+xml metalink
|
||||
application/metalink4+xml meta4
|
||||
application/mets+xml mets
|
||||
application/mods+xml mods
|
||||
application/mp21 m21 mp21
|
||||
application/mp4 mp4s
|
||||
application/msword doc dot
|
||||
application/mxf mxf
|
||||
application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy
|
||||
application/oda oda
|
||||
application/oebps-package+xml opf
|
||||
application/ogg ogx
|
||||
application/omdoc+xml omdoc
|
||||
application/onenote onetoc onetoc2 onetmp onepkg
|
||||
application/oxps oxps
|
||||
application/patch-ops-error+xml xer
|
||||
application/pdf pdf
|
||||
application/pgp-encrypted pgp
|
||||
application/pgp-signature asc sig
|
||||
application/pics-rules prf
|
||||
application/pkcs10 p10
|
||||
application/pkcs7-mime p7m p7c
|
||||
application/pkcs7-signature p7s
|
||||
application/pkcs8 p8
|
||||
application/pkix-attr-cert ac
|
||||
application/pkix-cert cer
|
||||
application/pkix-crl crl
|
||||
application/pkix-pkipath pkipath
|
||||
application/pkixcmp pki
|
||||
application/pls+xml pls
|
||||
application/postscript ai eps ps
|
||||
application/prs.cww cww
|
||||
application/pskc+xml pskcxml
|
||||
application/rdf+xml rdf
|
||||
application/reginfo+xml rif
|
||||
application/relax-ng-compact-syntax rnc
|
||||
application/resource-lists+xml rl
|
||||
application/resource-lists-diff+xml rld
|
||||
application/rls-services+xml rs
|
||||
application/rpki-ghostbusters gbr
|
||||
application/rpki-manifest mft
|
||||
application/rpki-roa roa
|
||||
application/rsd+xml rsd
|
||||
application/rss+xml rss
|
||||
application/rtf rtf
|
||||
application/sbml+xml sbml
|
||||
application/scvp-cv-request scq
|
||||
application/scvp-cv-response scs
|
||||
application/scvp-vp-request spq
|
||||
application/scvp-vp-response spp
|
||||
application/sdp sdp
|
||||
application/set-payment-initiation setpay
|
||||
application/set-registration-initiation setreg
|
||||
application/shf+xml shf
|
||||
application/smil+xml smi smil
|
||||
application/sparql-query rq
|
||||
application/sparql-results+xml srx
|
||||
application/srgs gram
|
||||
application/srgs+xml grxml
|
||||
application/sru+xml sru
|
||||
application/ssdl+xml ssdl
|
||||
application/ssml+xml ssml
|
||||
application/tei+xml tei teicorpus
|
||||
application/thraud+xml tfi
|
||||
application/timestamped-data tsd
|
||||
application/vnd.3gpp.pic-bw-large plb
|
||||
application/vnd.3gpp.pic-bw-small psb
|
||||
application/vnd.3gpp.pic-bw-var pvb
|
||||
application/vnd.3gpp2.tcap tcap
|
||||
application/vnd.3m.post-it-notes pwn
|
||||
application/vnd.accpac.simply.aso aso
|
||||
application/vnd.accpac.simply.imp imp
|
||||
application/vnd.acucobol acu
|
||||
application/vnd.acucorp atc acutc
|
||||
application/vnd.adobe.air-application-installer-package+zip air
|
||||
application/vnd.adobe.formscentral.fcdt fcdt
|
||||
application/vnd.adobe.fxp fxp fxpl
|
||||
application/vnd.adobe.xdp+xml xdp
|
||||
application/vnd.adobe.xfdf xfdf
|
||||
application/vnd.ahead.space ahead
|
||||
application/vnd.airzip.filesecure.azf azf
|
||||
application/vnd.airzip.filesecure.azs azs
|
||||
application/vnd.amazon.ebook azw
|
||||
application/vnd.americandynamics.acc acc
|
||||
application/vnd.amiga.ami ami
|
||||
application/vnd.android.package-archive apk
|
||||
application/vnd.anser-web-certificate-issue-initiation cii
|
||||
application/vnd.anser-web-funds-transfer-initiation fti
|
||||
application/vnd.antix.game-component atx
|
||||
application/vnd.apple.installer+xml mpkg
|
||||
application/vnd.apple.mpegurl m3u8
|
||||
application/vnd.aristanetworks.swi swi
|
||||
application/vnd.astraea-software.iota iota
|
||||
application/vnd.audiograph aep
|
||||
application/vnd.blueice.multipass mpm
|
||||
application/vnd.bmi bmi
|
||||
application/vnd.businessobjects rep
|
||||
application/vnd.chemdraw+xml cdxml
|
||||
application/vnd.chipnuts.karaoke-mmd mmd
|
||||
application/vnd.cinderella cdy
|
||||
application/vnd.claymore cla
|
||||
application/vnd.cloanto.rp9 rp9
|
||||
application/vnd.clonk.c4group c4g c4d c4f c4p c4u
|
||||
application/vnd.cluetrust.cartomobile-config c11amc
|
||||
application/vnd.cluetrust.cartomobile-config-pkg c11amz
|
||||
application/vnd.commonspace csp
|
||||
application/vnd.contact.cmsg cdbcmsg
|
||||
application/vnd.cosmocaller cmc
|
||||
application/vnd.crick.clicker clkx
|
||||
application/vnd.crick.clicker.keyboard clkk
|
||||
application/vnd.crick.clicker.palette clkp
|
||||
application/vnd.crick.clicker.template clkt
|
||||
application/vnd.crick.clicker.wordbank clkw
|
||||
application/vnd.criticaltools.wbs+xml wbs
|
||||
application/vnd.ctc-posml pml
|
||||
application/vnd.cups-ppd ppd
|
||||
application/vnd.curl.car car
|
||||
application/vnd.curl.pcurl pcurl
|
||||
application/vnd.dart dart
|
||||
application/vnd.data-vision.rdz rdz
|
||||
application/vnd.dece.data uvf uvvf uvd uvvd
|
||||
application/vnd.dece.ttml+xml uvt uvvt
|
||||
application/vnd.dece.unspecified uvx uvvx
|
||||
application/vnd.dece.zip uvz uvvz
|
||||
application/vnd.denovo.fcselayout-link fe_launch
|
||||
application/vnd.dna dna
|
||||
application/vnd.dolby.mlp mlp
|
||||
application/vnd.dpgraph dpg
|
||||
application/vnd.dreamfactory dfac
|
||||
application/vnd.ds-keypoint kpxx
|
||||
application/vnd.dvb.ait ait
|
||||
application/vnd.dvb.service svc
|
||||
application/vnd.dynageo geo
|
||||
application/vnd.ecowin.chart mag
|
||||
application/vnd.enliven nml
|
||||
application/vnd.epson.esf esf
|
||||
application/vnd.epson.msf msf
|
||||
application/vnd.epson.quickanime qam
|
||||
application/vnd.epson.salt slt
|
||||
application/vnd.epson.ssf ssf
|
||||
application/vnd.eszigno3+xml es3 et3
|
||||
application/vnd.ezpix-album ez2
|
||||
application/vnd.ezpix-package ez3
|
||||
application/vnd.fdf fdf
|
||||
application/vnd.fdsn.mseed mseed
|
||||
application/vnd.fdsn.seed seed dataless
|
||||
application/vnd.flographit gph
|
||||
application/vnd.fluxtime.clip ftc
|
||||
application/vnd.framemaker fm frame maker book
|
||||
application/vnd.frogans.fnc fnc
|
||||
application/vnd.frogans.ltf ltf
|
||||
application/vnd.fsc.weblaunch fsc
|
||||
application/vnd.fujitsu.oasys oas
|
||||
application/vnd.fujitsu.oasys2 oa2
|
||||
application/vnd.fujitsu.oasys3 oa3
|
||||
application/vnd.fujitsu.oasysgp fg5
|
||||
application/vnd.fujitsu.oasysprs bh2
|
||||
application/vnd.fujixerox.ddd ddd
|
||||
application/vnd.fujixerox.docuworks xdw
|
||||
application/vnd.fujixerox.docuworks.binder xbd
|
||||
application/vnd.fuzzysheet fzs
|
||||
application/vnd.genomatix.tuxedo txd
|
||||
application/vnd.geogebra.file ggb
|
||||
application/vnd.geogebra.tool ggt
|
||||
application/vnd.geometry-explorer gex gre
|
||||
application/vnd.geonext gxt
|
||||
application/vnd.geoplan g2w
|
||||
application/vnd.geospace g3w
|
||||
application/vnd.gmx gmx
|
||||
application/vnd.google-earth.kml+xml kml
|
||||
application/vnd.google-earth.kmz kmz
|
||||
application/vnd.grafeq gqf gqs
|
||||
application/vnd.groove-account gac
|
||||
application/vnd.groove-help ghf
|
||||
application/vnd.groove-identity-message gim
|
||||
application/vnd.groove-injector grv
|
||||
application/vnd.groove-tool-message gtm
|
||||
application/vnd.groove-tool-template tpl
|
||||
application/vnd.groove-vcard vcg
|
||||
application/vnd.hal+xml hal
|
||||
application/vnd.handheld-entertainment+xml zmm
|
||||
application/vnd.hbci hbci
|
||||
application/vnd.hhe.lesson-player les
|
||||
application/vnd.hp-hpgl hpgl
|
||||
application/vnd.hp-hpid hpid
|
||||
application/vnd.hp-hps hps
|
||||
application/vnd.hp-jlyt jlt
|
||||
application/vnd.hp-pcl pcl
|
||||
application/vnd.hp-pclxl pclxl
|
||||
application/vnd.hydrostatix.sof-data sfd-hdstx
|
||||
application/vnd.ibm.minipay mpy
|
||||
application/vnd.ibm.modcap afp listafp list3820
|
||||
application/vnd.ibm.rights-management irm
|
||||
application/vnd.ibm.secure-container sc
|
||||
application/vnd.iccprofile icc icm
|
||||
application/vnd.igloader igl
|
||||
application/vnd.immervision-ivp ivp
|
||||
application/vnd.immervision-ivu ivu
|
||||
application/vnd.insors.igm igm
|
||||
application/vnd.intercon.formnet xpw xpx
|
||||
application/vnd.intergeo i2g
|
||||
application/vnd.intu.qbo qbo
|
||||
application/vnd.intu.qfx qfx
|
||||
application/vnd.ipunplugged.rcprofile rcprofile
|
||||
application/vnd.irepository.package+xml irp
|
||||
application/vnd.is-xpr xpr
|
||||
application/vnd.isac.fcs fcs
|
||||
application/vnd.jam jam
|
||||
application/vnd.jcp.javame.midlet-rms rms
|
||||
application/vnd.jisp jisp
|
||||
application/vnd.joost.joda-archive joda
|
||||
application/vnd.kahootz ktz ktr
|
||||
application/vnd.kde.karbon karbon
|
||||
application/vnd.kde.kchart chrt
|
||||
application/vnd.kde.kformula kfo
|
||||
application/vnd.kde.kivio flw
|
||||
application/vnd.kde.kontour kon
|
||||
application/vnd.kde.kpresenter kpr kpt
|
||||
application/vnd.kde.kspread ksp
|
||||
application/vnd.kde.kword kwd kwt
|
||||
application/vnd.kenameaapp htke
|
||||
application/vnd.kidspiration kia
|
||||
application/vnd.kinar kne knp
|
||||
application/vnd.koan skp skd skt skm
|
||||
application/vnd.kodak-descriptor sse
|
||||
application/vnd.las.las+xml lasxml
|
||||
application/vnd.llamagraphics.life-balance.desktop lbd
|
||||
application/vnd.llamagraphics.life-balance.exchange+xml lbe
|
||||
application/vnd.lotus-1-2-3 123
|
||||
application/vnd.lotus-approach apr
|
||||
application/vnd.lotus-freelance pre
|
||||
application/vnd.lotus-notes nsf
|
||||
application/vnd.lotus-organizer org
|
||||
application/vnd.lotus-screencam scm
|
||||
application/vnd.lotus-wordpro lwp
|
||||
application/vnd.macports.portpkg portpkg
|
||||
application/vnd.mcd mcd
|
||||
application/vnd.medcalcdata mc1
|
||||
application/vnd.mediastation.cdkey cdkey
|
||||
application/vnd.mfer mwf
|
||||
application/vnd.mfmp mfm
|
||||
application/vnd.micrografx.flo flo
|
||||
application/vnd.micrografx.igx igx
|
||||
application/vnd.mif mif
|
||||
application/vnd.mobius.daf daf
|
||||
application/vnd.mobius.dis dis
|
||||
application/vnd.mobius.mbk mbk
|
||||
application/vnd.mobius.mqy mqy
|
||||
application/vnd.mobius.msl msl
|
||||
application/vnd.mobius.plc plc
|
||||
application/vnd.mobius.txf txf
|
||||
application/vnd.mophun.application mpn
|
||||
application/vnd.mophun.certificate mpc
|
||||
application/vnd.mozilla.xul+xml xul
|
||||
application/vnd.ms-artgalry cil
|
||||
application/vnd.ms-cab-compressed cab
|
||||
application/vnd.ms-excel xls xlm xla xlc xlt xlw
|
||||
application/vnd.ms-excel.addin.macroenabled.12 xlam
|
||||
application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb
|
||||
application/vnd.ms-excel.sheet.macroenabled.12 xlsm
|
||||
application/vnd.ms-excel.template.macroenabled.12 xltm
|
||||
application/vnd.ms-fontobject eot
|
||||
application/vnd.ms-htmlhelp chm
|
||||
application/vnd.ms-ims ims
|
||||
application/vnd.ms-lrm lrm
|
||||
application/vnd.ms-officetheme thmx
|
||||
application/vnd.ms-pki.seccat cat
|
||||
application/vnd.ms-pki.stl stl
|
||||
application/vnd.ms-powerpoint ppt pps pot
|
||||
application/vnd.ms-powerpoint.addin.macroenabled.12 ppam
|
||||
application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm
|
||||
application/vnd.ms-powerpoint.slide.macroenabled.12 sldm
|
||||
application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm
|
||||
application/vnd.ms-powerpoint.template.macroenabled.12 potm
|
||||
application/vnd.ms-project mpp mpt
|
||||
application/vnd.ms-word.document.macroenabled.12 docm
|
||||
application/vnd.ms-word.template.macroenabled.12 dotm
|
||||
application/vnd.ms-works wps wks wcm wdb
|
||||
application/vnd.ms-wpl wpl
|
||||
application/vnd.ms-xpsdocument xps
|
||||
application/vnd.mseq mseq
|
||||
application/vnd.musician mus
|
||||
application/vnd.muvee.style msty
|
||||
application/vnd.mynfc taglet
|
||||
application/vnd.neurolanguage.nlu nlu
|
||||
application/vnd.nitf ntf nitf
|
||||
application/vnd.noblenet-directory nnd
|
||||
application/vnd.noblenet-sealer nns
|
||||
application/vnd.noblenet-web nnw
|
||||
application/vnd.nokia.n-gage.data ngdat
|
||||
application/vnd.nokia.n-gage.symbian.install n-gage
|
||||
application/vnd.nokia.radio-preset rpst
|
||||
application/vnd.nokia.radio-presets rpss
|
||||
application/vnd.novadigm.edm edm
|
||||
application/vnd.novadigm.edx edx
|
||||
application/vnd.novadigm.ext ext
|
||||
application/vnd.oasis.opendocument.chart odc
|
||||
application/vnd.oasis.opendocument.chart-template otc
|
||||
application/vnd.oasis.opendocument.database odb
|
||||
application/vnd.oasis.opendocument.formula odf
|
||||
application/vnd.oasis.opendocument.formula-template odft
|
||||
application/vnd.oasis.opendocument.graphics odg
|
||||
application/vnd.oasis.opendocument.graphics-template otg
|
||||
application/vnd.oasis.opendocument.image odi
|
||||
application/vnd.oasis.opendocument.image-template oti
|
||||
application/vnd.oasis.opendocument.presentation odp
|
||||
application/vnd.oasis.opendocument.presentation-template otp
|
||||
application/vnd.oasis.opendocument.spreadsheet ods
|
||||
application/vnd.oasis.opendocument.spreadsheet-template ots
|
||||
application/vnd.oasis.opendocument.text odt
|
||||
application/vnd.oasis.opendocument.text-master odm
|
||||
application/vnd.oasis.opendocument.text-template ott
|
||||
application/vnd.oasis.opendocument.text-web oth
|
||||
application/vnd.olpc-sugar xo
|
||||
application/vnd.oma.dd2+xml dd2
|
||||
application/vnd.openofficeorg.extension oxt
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
|
||||
application/vnd.openxmlformats-officedocument.presentationml.slide sldx
|
||||
application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
|
||||
application/vnd.openxmlformats-officedocument.presentationml.template potx
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
|
||||
application/vnd.osgeo.mapguide.package mgp
|
||||
application/vnd.osgi.dp dp
|
||||
application/vnd.osgi.subsystem esa
|
||||
application/vnd.palm pdb pqa oprc
|
||||
application/vnd.pawaafile paw
|
||||
application/vnd.pg.format str
|
||||
application/vnd.pg.osasli ei6
|
||||
application/vnd.picsel efif
|
||||
application/vnd.pmi.widget wg
|
||||
application/vnd.pocketlearn plf
|
||||
application/vnd.powerbuilder6 pbd
|
||||
application/vnd.previewsystems.box box
|
||||
application/vnd.proteus.magazine mgz
|
||||
application/vnd.publishare-delta-tree qps
|
||||
application/vnd.pvi.ptid1 ptid
|
||||
application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
|
||||
application/vnd.realvnc.bed bed
|
||||
application/vnd.recordare.musicxml mxl
|
||||
application/vnd.recordare.musicxml+xml musicxml
|
||||
application/vnd.rig.cryptonote cryptonote
|
||||
application/vnd.rim.cod cod
|
||||
application/vnd.rn-realmedia rm
|
||||
application/vnd.rn-realmedia-vbr rmvb
|
||||
application/vnd.route66.link66+xml link66
|
||||
application/vnd.sailingtracker.track st
|
||||
application/vnd.seemail see
|
||||
application/vnd.sema sema
|
||||
application/vnd.semd semd
|
||||
application/vnd.semf semf
|
||||
application/vnd.shana.informed.formdata ifm
|
||||
application/vnd.shana.informed.formtemplate itp
|
||||
application/vnd.shana.informed.interchange iif
|
||||
application/vnd.shana.informed.package ipk
|
||||
application/vnd.simtech-mindmapper twd twds
|
||||
application/vnd.smaf mmf
|
||||
application/vnd.smart.teacher teacher
|
||||
application/vnd.solent.sdkm+xml sdkm sdkd
|
||||
application/vnd.spotfire.dxp dxp
|
||||
application/vnd.spotfire.sfs sfs
|
||||
application/vnd.stardivision.calc sdc
|
||||
application/vnd.stardivision.draw sda
|
||||
application/vnd.stardivision.impress sdd
|
||||
application/vnd.stardivision.math smf
|
||||
application/vnd.stardivision.writer sdw vor
|
||||
application/vnd.stardivision.writer-global sgl
|
||||
application/vnd.stepmania.package smzip
|
||||
application/vnd.stepmania.stepchart sm
|
||||
application/vnd.sun.xml.calc sxc
|
||||
application/vnd.sun.xml.calc.template stc
|
||||
application/vnd.sun.xml.draw sxd
|
||||
application/vnd.sun.xml.draw.template std
|
||||
application/vnd.sun.xml.impress sxi
|
||||
application/vnd.sun.xml.impress.template sti
|
||||
application/vnd.sun.xml.math sxm
|
||||
application/vnd.sun.xml.writer sxw
|
||||
application/vnd.sun.xml.writer.global sxg
|
||||
application/vnd.sun.xml.writer.template stw
|
||||
application/vnd.sus-calendar sus susp
|
||||
application/vnd.svd svd
|
||||
application/vnd.symbian.install sis sisx
|
||||
application/vnd.syncml+xml xsm
|
||||
application/vnd.syncml.dm+wbxml bdm
|
||||
application/vnd.syncml.dm+xml xdm
|
||||
application/vnd.tao.intent-module-archive tao
|
||||
application/vnd.tcpdump.pcap pcap cap dmp
|
||||
application/vnd.tmobile-livetv tmo
|
||||
application/vnd.trid.tpt tpt
|
||||
application/vnd.triscape.mxs mxs
|
||||
application/vnd.trueapp tra
|
||||
application/vnd.ufdl ufd ufdl
|
||||
application/vnd.uiq.theme utz
|
||||
application/vnd.umajin umj
|
||||
application/vnd.unity unityweb
|
||||
application/vnd.uoml+xml uoml
|
||||
application/vnd.vcx vcx
|
||||
application/vnd.visio vsd vst vss vsw
|
||||
application/vnd.visionary vis
|
||||
application/vnd.vsf vsf
|
||||
application/vnd.wap.wbxml wbxml
|
||||
application/vnd.wap.wmlc wmlc
|
||||
application/vnd.wap.wmlscriptc wmlsc
|
||||
application/vnd.webturbo wtb
|
||||
application/vnd.wolfram.player nbp
|
||||
application/vnd.wordperfect wpd
|
||||
application/vnd.wqd wqd
|
||||
application/vnd.wt.stf stf
|
||||
application/vnd.xara xar
|
||||
application/vnd.xfdl xfdl
|
||||
application/vnd.yamaha.hv-dic hvd
|
||||
application/vnd.yamaha.hv-script hvs
|
||||
application/vnd.yamaha.hv-voice hvp
|
||||
application/vnd.yamaha.openscoreformat osf
|
||||
application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg
|
||||
application/vnd.yamaha.smaf-audio saf
|
||||
application/vnd.yamaha.smaf-phrase spf
|
||||
application/vnd.yellowriver-custom-menu cmp
|
||||
application/vnd.zul zir zirz
|
||||
application/vnd.zzazz.deck+xml zaz
|
||||
application/voicexml+xml vxml
|
||||
application/widget wgt
|
||||
application/winhlp hlp
|
||||
application/wsdl+xml wsdl
|
||||
application/wspolicy+xml wspolicy
|
||||
application/x-7z-compressed 7z
|
||||
application/x-abiword abw
|
||||
application/x-ace-compressed ace
|
||||
application/x-apple-diskimage dmg
|
||||
application/x-authorware-bin aab x32 u32 vox
|
||||
application/x-authorware-map aam
|
||||
application/x-authorware-seg aas
|
||||
application/x-bcpio bcpio
|
||||
application/x-bittorrent torrent
|
||||
application/x-blorb blb blorb
|
||||
application/x-bzip bz
|
||||
application/x-bzip2 bz2 boz
|
||||
application/x-cbr cbr cba cbt cbz cb7
|
||||
application/x-cdlink vcd
|
||||
application/x-cfs-compressed cfs
|
||||
application/x-chat chat
|
||||
application/x-chess-pgn pgn
|
||||
application/x-conference nsc
|
||||
application/x-cpio cpio
|
||||
application/x-csh csh
|
||||
application/x-debian-package deb udeb
|
||||
application/x-dgc-compressed dgc
|
||||
application/x-director dir dcr dxr cst cct cxt w3d fgd swa
|
||||
application/x-doom wad
|
||||
application/x-dtbncx+xml ncx
|
||||
application/x-dtbook+xml dtb
|
||||
application/x-dtbresource+xml res
|
||||
application/x-dvi dvi
|
||||
application/x-envoy evy
|
||||
application/x-eva eva
|
||||
application/x-font-bdf bdf
|
||||
application/x-font-ghostscript gsf
|
||||
application/x-font-linux-psf psf
|
||||
application/x-font-pcf pcf
|
||||
application/x-font-snf snf
|
||||
application/x-font-type1 pfa pfb pfm afm
|
||||
application/x-freearc arc
|
||||
application/x-futuresplash spl
|
||||
application/x-gca-compressed gca
|
||||
application/x-glulx ulx
|
||||
application/x-gnumeric gnumeric
|
||||
application/x-gramps-xml gramps
|
||||
application/x-gtar gtar
|
||||
application/x-hdf hdf
|
||||
application/x-install-instructions install
|
||||
application/x-iso9660-image iso
|
||||
application/x-java-jnlp-file jnlp
|
||||
application/x-latex latex
|
||||
application/x-lzh-compressed lzh lha
|
||||
application/x-mie mie
|
||||
application/x-mobipocket-ebook prc mobi
|
||||
application/x-ms-application application
|
||||
application/x-ms-shortcut lnk
|
||||
application/x-ms-wmd wmd
|
||||
application/x-ms-wmz wmz
|
||||
application/x-ms-xbap xbap
|
||||
application/x-msaccess mdb
|
||||
application/x-msbinder obd
|
||||
application/x-mscardfile crd
|
||||
application/x-msclip clp
|
||||
application/x-msdownload exe dll com bat msi
|
||||
application/x-msmediaview mvb m13 m14
|
||||
application/x-msmetafile wmf wmz emf emz
|
||||
application/x-msmoney mny
|
||||
application/x-mspublisher pub
|
||||
application/x-msschedule scd
|
||||
application/x-msterminal trm
|
||||
application/x-mswrite wri
|
||||
application/x-netcdf nc cdf
|
||||
application/x-nzb nzb
|
||||
application/x-pkcs12 p12 pfx
|
||||
application/x-pkcs7-certificates p7b spc
|
||||
application/x-pkcs7-certreqresp p7r
|
||||
application/x-rar-compressed rar
|
||||
application/x-research-info-systems ris
|
||||
application/x-sh sh
|
||||
application/x-shar shar
|
||||
application/x-shockwave-flash swf
|
||||
application/x-silverlight-app xap
|
||||
application/x-sql sql
|
||||
application/x-stuffit sit
|
||||
application/x-stuffitx sitx
|
||||
application/x-subrip srt
|
||||
application/x-sv4cpio sv4cpio
|
||||
application/x-sv4crc sv4crc
|
||||
application/x-t3vm-image t3
|
||||
application/x-tads gam
|
||||
application/x-tar tar
|
||||
application/x-tcl tcl
|
||||
application/x-tex tex
|
||||
application/x-tex-tfm tfm
|
||||
application/x-texinfo texinfo texi
|
||||
application/x-tgif obj
|
||||
application/x-ustar ustar
|
||||
application/x-wais-source src
|
||||
application/x-x509-ca-cert der crt
|
||||
application/x-xfig fig
|
||||
application/x-xliff+xml xlf
|
||||
application/x-xpinstall xpi
|
||||
application/x-xz xz
|
||||
application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8
|
||||
application/xaml+xml xaml
|
||||
application/xcap-diff+xml xdf
|
||||
application/xenc+xml xenc
|
||||
application/xhtml+xml xhtml xht
|
||||
application/xml xml xsl
|
||||
application/xml-dtd dtd
|
||||
application/xop+xml xop
|
||||
application/xproc+xml xpl
|
||||
application/xslt+xml xslt
|
||||
application/xspf+xml xspf
|
||||
application/xv+xml mxml xhvml xvml xvm
|
||||
application/yang yang
|
||||
application/yin+xml yin
|
||||
application/zip zip
|
||||
audio/adpcm adp
|
||||
audio/basic au snd
|
||||
audio/midi mid midi kar rmi
|
||||
audio/mp4 m4a mp4a
|
||||
audio/mpeg mpga mp2 mp2a mp3 m2a m3a
|
||||
audio/ogg oga ogg spx
|
||||
audio/s3m s3m
|
||||
audio/silk sil
|
||||
audio/vnd.dece.audio uva uvva
|
||||
audio/vnd.digital-winds eol
|
||||
audio/vnd.dra dra
|
||||
audio/vnd.dts dts
|
||||
audio/vnd.dts.hd dtshd
|
||||
audio/vnd.lucent.voice lvp
|
||||
audio/vnd.ms-playready.media.pya pya
|
||||
audio/vnd.nuera.ecelp4800 ecelp4800
|
||||
audio/vnd.nuera.ecelp7470 ecelp7470
|
||||
audio/vnd.nuera.ecelp9600 ecelp9600
|
||||
audio/vnd.rip rip
|
||||
audio/webm weba
|
||||
audio/x-aac aac
|
||||
audio/x-aiff aif aiff aifc
|
||||
audio/x-caf caf
|
||||
audio/x-flac flac
|
||||
audio/x-matroska mka
|
||||
audio/x-mpegurl m3u
|
||||
audio/x-ms-wax wax
|
||||
audio/x-ms-wma wma
|
||||
audio/x-pn-realaudio ram ra
|
||||
audio/x-pn-realaudio-plugin rmp
|
||||
audio/x-wav wav
|
||||
audio/xm xm
|
||||
chemical/x-cdx cdx
|
||||
chemical/x-cif cif
|
||||
chemical/x-cmdf cmdf
|
||||
chemical/x-cml cml
|
||||
chemical/x-csml csml
|
||||
chemical/x-xyz xyz
|
||||
font/collection ttc
|
||||
font/otf otf
|
||||
font/ttf ttf
|
||||
font/woff woff
|
||||
font/woff2 woff2
|
||||
image/bmp bmp
|
||||
image/cgm cgm
|
||||
image/g3fax g3
|
||||
image/gif gif
|
||||
image/ief ief
|
||||
image/jpeg jpeg jpg jpe
|
||||
image/ktx ktx
|
||||
image/png png
|
||||
image/prs.btif btif
|
||||
image/sgi sgi
|
||||
image/svg+xml svg svgz
|
||||
image/tiff tiff tif
|
||||
image/vnd.adobe.photoshop psd
|
||||
image/vnd.dece.graphic uvi uvvi uvg uvvg
|
||||
image/vnd.djvu djvu djv
|
||||
image/vnd.dvb.subtitle sub
|
||||
image/vnd.dwg dwg
|
||||
image/vnd.dxf dxf
|
||||
image/vnd.fastbidsheet fbs
|
||||
image/vnd.fpx fpx
|
||||
image/vnd.fst fst
|
||||
image/vnd.fujixerox.edmics-mmr mmr
|
||||
image/vnd.fujixerox.edmics-rlc rlc
|
||||
image/vnd.ms-modi mdi
|
||||
image/vnd.ms-photo wdp
|
||||
image/vnd.net-fpx npx
|
||||
image/vnd.wap.wbmp wbmp
|
||||
image/vnd.xiff xif
|
||||
image/webp webp
|
||||
image/x-3ds 3ds
|
||||
image/x-cmu-raster ras
|
||||
image/x-cmx cmx
|
||||
image/x-freehand fh fhc fh4 fh5 fh7
|
||||
image/x-icon ico
|
||||
image/x-mrsid-image sid
|
||||
image/x-pcx pcx
|
||||
image/x-pict pic pct
|
||||
image/x-portable-anymap pnm
|
||||
image/x-portable-bitmap pbm
|
||||
image/x-portable-graymap pgm
|
||||
image/x-portable-pixmap ppm
|
||||
image/x-rgb rgb
|
||||
image/x-tga tga
|
||||
image/x-xbitmap xbm
|
||||
image/x-xpixmap xpm
|
||||
image/x-xwindowdump xwd
|
||||
message/rfc822 eml mime
|
||||
model/iges igs iges
|
||||
model/mesh msh mesh silo
|
||||
model/vnd.collada+xml dae
|
||||
model/vnd.dwf dwf
|
||||
model/vnd.gdl gdl
|
||||
model/vnd.gtw gtw
|
||||
model/vnd.mts mts
|
||||
model/vnd.vtu vtu
|
||||
model/vrml wrl vrml
|
||||
model/x3d+binary x3db x3dbz
|
||||
model/x3d+vrml x3dv x3dvz
|
||||
model/x3d+xml x3d x3dz
|
||||
text/cache-manifest appcache
|
||||
text/calendar ics ifb
|
||||
text/css css
|
||||
text/csv csv
|
||||
text/html html htm
|
||||
text/n3 n3
|
||||
text/plain txt text conf def list log in
|
||||
text/prs.lines.tag dsc
|
||||
text/richtext rtx
|
||||
text/sgml sgml sgm
|
||||
text/tab-separated-values tsv
|
||||
text/troff t tr roff man me ms
|
||||
text/turtle ttl
|
||||
text/uri-list uri uris urls
|
||||
text/vcard vcard
|
||||
text/vnd.curl curl
|
||||
text/vnd.curl.dcurl dcurl
|
||||
text/vnd.curl.mcurl mcurl
|
||||
text/vnd.curl.scurl scurl
|
||||
text/vnd.dvb.subtitle sub
|
||||
text/vnd.fly fly
|
||||
text/vnd.fmi.flexstor flx
|
||||
text/vnd.graphviz gv
|
||||
text/vnd.in3d.3dml 3dml
|
||||
text/vnd.in3d.spot spot
|
||||
text/vnd.sun.j2me.app-descriptor jad
|
||||
text/vnd.wap.wml wml
|
||||
text/vnd.wap.wmlscript wmls
|
||||
text/x-asm s asm
|
||||
text/x-c c cc cxx cpp h hh dic
|
||||
text/x-fortran f for f77 f90
|
||||
text/x-java-source java
|
||||
text/x-nfo nfo
|
||||
text/x-opml opml
|
||||
text/x-pascal p pas
|
||||
text/x-setext etx
|
||||
text/x-sfv sfv
|
||||
text/x-uuencode uu
|
||||
text/x-vcalendar vcs
|
||||
text/x-vcard vcf
|
||||
video/3gpp 3gp
|
||||
video/3gpp2 3g2
|
||||
video/h261 h261
|
||||
video/h263 h263
|
||||
video/h264 h264
|
||||
video/jpeg jpgv
|
||||
video/jpm jpm jpgm
|
||||
video/mj2 mj2 mjp2
|
||||
video/mp4 mp4 mp4v mpg4
|
||||
video/mpeg mpeg mpg mpe m1v m2v
|
||||
video/ogg ogv
|
||||
video/quicktime qt mov
|
||||
video/vnd.dece.hd uvh uvvh
|
||||
video/vnd.dece.mobile uvm uvvm
|
||||
video/vnd.dece.pd uvp uvvp
|
||||
video/vnd.dece.sd uvs uvvs
|
||||
video/vnd.dece.video uvv uvvv
|
||||
video/vnd.dvb.file dvb
|
||||
video/vnd.fvt fvt
|
||||
video/vnd.mpegurl mxu m4u
|
||||
video/vnd.ms-playready.media.pyv pyv
|
||||
video/vnd.uvvu.mp4 uvu uvvu
|
||||
video/vnd.vivo viv
|
||||
video/webm webm
|
||||
video/x-f4v f4v
|
||||
video/x-fli fli
|
||||
video/x-flv flv
|
||||
video/x-m4v m4v
|
||||
video/x-matroska mkv mk3d mks
|
||||
video/x-mng mng
|
||||
video/x-ms-asf asf asx
|
||||
video/x-ms-vob vob
|
||||
video/x-ms-wm wm
|
||||
video/x-ms-wmv wmv
|
||||
video/x-ms-wmx wmx
|
||||
video/x-ms-wvx wvx
|
||||
video/x-msvideo avi
|
||||
video/x-sgi-movie movie
|
||||
video/x-smv smv
|
||||
x-conference/x-cooltalk ice
|
||||
@@ -1,20 +0,0 @@
|
||||
import mime_raw from './mime-types.md';
|
||||
|
||||
const map: Map<string, string> = new Map();
|
||||
|
||||
mime_raw.split('\n').forEach((row: string) => {
|
||||
const match = /(.+?)\t+(.+)/.exec(row);
|
||||
if (!match) return;
|
||||
|
||||
const type = match[1];
|
||||
const extensions = match[2].split(' ');
|
||||
|
||||
extensions.forEach(ext => {
|
||||
map.set(ext, type);
|
||||
});
|
||||
});
|
||||
|
||||
export function lookup(file: string) {
|
||||
const match = /\.([^\.]+)$/.exec(file);
|
||||
return match && map.get(match[1]);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -44,7 +57,7 @@ export interface Req extends ClientRequest {
|
||||
method: string;
|
||||
path: string;
|
||||
params: Record<string, string>;
|
||||
query: Record<string, string>;
|
||||
query: Record<string, string | string[]>;
|
||||
headers: Record<string, string>;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Introduction
|
||||
|
||||
### Before we begin
|
||||
|
||||
> Sapper is in early development, and some things may change before we hit version 1.0. This document is a work-in-progress. If you get stuck, reach out for help in the [Discord chatroom](https://svelte.dev/chat).
|
||||
> Sapper is in early development, and some things may change before we hit version 1.0. This document is a work-in-progress. If you get stuck, reach out for help in the [Discord chatroom](https://discord.gg/yy75DKs).
|
||||
>
|
||||
> See the [migration guides](migrating) for help upgrading from older versions.
|
||||
|
||||
@@ -32,7 +32,7 @@ For web developers, the stakes are generally lower than for combat engineers. Bu
|
||||
[Next.js](https://github.com/zeit/next.js) is a React framework from [Zeit](https://zeit.co), and is the inspiration for Sapper. There are a few notable differences, however:
|
||||
|
||||
* Sapper is powered by Svelte instead of React, so it's faster and your apps are smaller
|
||||
* Instead of route masking, we encode route parameters in filenames (see the [routing](docs#Routing) section below)
|
||||
* Instead of route masking, we encode route parameters in filenames (see the [routing](docs#routing) section below)
|
||||
* As well as *pages*, you can create *server routes* in your `src/routes` directory. This makes it very easy to, for example, add a JSON API such as the one powering this very page (try visiting [/docs.json](/docs.json))
|
||||
* Links are just `<a>` elements, rather than framework-specific `<Link>` components. That means, for example, that [this link right here](/), despite being inside a blob of markdown, works with the router as you'd expect
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ If you take a look inside the [sapper-template](https://github.com/sveltejs/sapp
|
||||
|
||||
When you first run Sapper, it will create an additional `__sapper__` directory containing generated files.
|
||||
|
||||
You'll notice a few extra files and a `cypress` directory which relates to [testing](docs#Testing) — we don't need to worry about those right now.
|
||||
You'll notice a few extra files and a `cypress` directory which relates to [testing](docs#testing) — we don't need to worry about those right now.
|
||||
|
||||
> You *can* create these files from scratch, but it's much better to use the template. See [getting started](docs#Getting_started) for instructions on how to easily clone it
|
||||
> You *can* create these files from scratch, but it's much better to use the template. See [getting started](docs#getting-started) for instructions on how to easily clone it
|
||||
|
||||
|
||||
### package.json
|
||||
@@ -35,9 +35,9 @@ Your package.json contains your app's dependencies and defines a number of scrip
|
||||
|
||||
* `npm run dev` — start the app in development mode, and watch source files for changes
|
||||
* `npm run build` — build the app in production mode
|
||||
* `npm run export` — bake out a static version, if applicable (see [exporting](docs#Exporting))
|
||||
* `npm run export` — bake out a static version, if applicable (see [exporting](docs#exporting))
|
||||
* `npm start` — start the app in production mode after you've built it
|
||||
* `npm test` — run the tests (see [testing](docs#Testing))
|
||||
* `npm test` — run the tests (see [testing](docs#testing))
|
||||
|
||||
|
||||
### src
|
||||
@@ -56,7 +56,7 @@ sapper.start({
|
||||
});
|
||||
```
|
||||
|
||||
In many cases, that's the entirety of your entry module, though you can do as much or as little here as you wish. See the [client API](docs#Client_API) section for more information on functions you can import.
|
||||
In many cases, that's the entirety of your entry module, though you can do as much or as little here as you wish. See the [client API](docs#client-api) section for more information on functions you can import.
|
||||
|
||||
|
||||
#### src/server.js
|
||||
@@ -88,7 +88,7 @@ Because every app needs a slightly different service worker (sometimes it's appr
|
||||
|
||||
This file is a template for responses from the server. Sapper will inject content that replaces the following tags:
|
||||
|
||||
* `%sapper.base%` — a `<base>` element (see [base URLs](docs#Base_URLs))
|
||||
* `%sapper.base%` — a `<base>` element (see [base URLs](docs#base-urls))
|
||||
* `%sapper.styles%` — critical CSS for the page being requested
|
||||
* `%sapper.head%` — HTML representing page-specific `<head>` contents, like `<title>`
|
||||
* `%sapper.html%` — HTML representing the body of the page being rendered
|
||||
@@ -97,7 +97,7 @@ This file is a template for responses from the server. Sapper will inject conten
|
||||
|
||||
### src/routes
|
||||
|
||||
This is the meat of your app — the pages and server routes. See the section on [routing](docs#Routing) for the juicy details.
|
||||
This is the meat of your app — the pages and server routes. See the section on [routing](docs#routing) for the juicy details.
|
||||
|
||||
|
||||
### static
|
||||
|
||||
@@ -70,7 +70,7 @@ Dynamic parameters are encoded using `[brackets]`. For example, here's how you c
|
||||
</div>
|
||||
```
|
||||
|
||||
> See the section on [preloading](docs#Preloading) for more info about `preload` and `this.fetch`
|
||||
> See the section on [preloading](docs#preloading) for more info about `preload` and `this.fetch`
|
||||
|
||||
|
||||
### Server routes
|
||||
|
||||
@@ -36,7 +36,7 @@ Programmatically navigates to the given `href`. If the destination is a Sapper r
|
||||
|
||||
* `href` — the page to prefetch
|
||||
|
||||
Programmatically prefetches the given page, which means a) ensuring that the code for the page is loaded, and b) calling the page's `preload` method with the appropriate options. This is the same behaviour that Sapper triggers when the user taps or mouses over an `<a>` element with [rel=prefetch](docs#Prefetching).
|
||||
Programmatically prefetches the given page, which means a) ensuring that the code for the page is loaded, and b) calling the page's `preload` method with the appropriate options. This is the same behaviour that Sapper triggers when the user taps or mouses over an `<a>` element with [rel=prefetch](docs#prefetching).
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Preloading
|
||||
---
|
||||
|
||||
As seen in the [routing](docs#Routing) section, page components can have an optional `preload` function that will load some data that the page depends on. This is similar to `getInitialProps` in Next.js or `asyncData` in Nuxt.js.
|
||||
As seen in the [routing](docs#routing) section, page components can have an optional `preload` function that will load some data that the page depends on. This is similar to `getInitialProps` in Next.js or `asyncData` in Nuxt.js.
|
||||
|
||||
```html
|
||||
<script context="module">
|
||||
|
||||
@@ -21,7 +21,7 @@ express() // or Polka, or a similar framework
|
||||
|
||||
Sapper will detect the base path and configure both the server-side and client-side routers accordingly.
|
||||
|
||||
If you're [exporting](docs#Exporting) your app, you will need to tell the exporter where to begin crawling:
|
||||
If you're [exporting](docs#exporting) your app, you will need to tell the exporter where to begin crawling:
|
||||
|
||||
```bash
|
||||
sapper export --basepath my-base-path
|
||||
|
||||
@@ -292,7 +292,7 @@ Once your `App.html` has been created and your server and client apps updated, y
|
||||
|
||||
##### app/template.html
|
||||
|
||||
* Your `<head>` element must contain `%sapper.base%` (see ([base URLs](docs#Base_URLs))
|
||||
* Your `<head>` element must contain `%sapper.base%` (see ([base URLs](docs#base-urls))
|
||||
* Remove references to your service worker; this is now handled by `%sapper.scripts%`
|
||||
|
||||
##### Pages
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<p>Please try reloading the page.</p>
|
||||
{/if}
|
||||
|
||||
<p>If the error persists, please drop by <a href="https://svelte.dev/chat">Discord chatroom</a> and let us know, or raise an issue on <a href="https://github.com/sveltejs/svelte">GitHub</a>. Thanks!</p>
|
||||
<p>If the error persists, please drop by <a href="https://discord.gg/yy75DKs">Discord chatroom</a> and let us know, or raise an issue on <a href="https://github.com/sveltejs/svelte">GitHub</a>. Thanks!</p>
|
||||
{/if}
|
||||
{:else}
|
||||
<h1>It looks like you're offline</h1>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<NavItem external="https://svelte.dev">Svelte</NavItem>
|
||||
|
||||
<NavItem external="https://svelte.dev/chat" title="Discord Chat">
|
||||
<NavItem external="https://discord.gg/yy75DKs" title="Discord Chat">
|
||||
<Icon name="message-square"/>
|
||||
</NavItem>
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ type Opts = {
|
||||
static?: string;
|
||||
legacy?: boolean;
|
||||
bundler?: 'rollup' | 'webpack';
|
||||
ext?: string;
|
||||
oncompile?: ({ type, result }: { type: string, result: CompileResult }) => void;
|
||||
};
|
||||
|
||||
@@ -33,7 +32,6 @@ export async function build({
|
||||
|
||||
bundler,
|
||||
legacy = false,
|
||||
ext,
|
||||
oncompile = noop
|
||||
}: Opts = {}) {
|
||||
bundler = validate_bundler(bundler);
|
||||
@@ -70,7 +68,7 @@ export async function build({
|
||||
|
||||
fs.writeFileSync(`${dest}/template.html`, minify_html(template));
|
||||
|
||||
const manifest_data = create_manifest_data(routes, ext);
|
||||
const manifest_data = create_manifest_data(routes);
|
||||
|
||||
// create src/node_modules/@sapper/app.mjs and server.mjs
|
||||
create_app({
|
||||
@@ -124,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,
|
||||
|
||||
115
src/api/dev.ts
115
src/api/dev.ts
@@ -28,8 +28,7 @@ type Opts = {
|
||||
hot?: boolean,
|
||||
'devtools-port'?: number,
|
||||
bundler?: 'rollup' | 'webpack',
|
||||
port?: number,
|
||||
ext: string
|
||||
port?: number
|
||||
};
|
||||
|
||||
export function dev(opts: Opts) {
|
||||
@@ -48,7 +47,7 @@ class Watcher extends EventEmitter {
|
||||
}
|
||||
port: number;
|
||||
closed: boolean;
|
||||
|
||||
|
||||
dev_port: number;
|
||||
live: boolean;
|
||||
hot: boolean;
|
||||
@@ -68,7 +67,6 @@ class Watcher extends EventEmitter {
|
||||
unique_warnings: Set<string>;
|
||||
unique_errors: Set<string>;
|
||||
}
|
||||
ext: string;
|
||||
|
||||
constructor({
|
||||
cwd = '.',
|
||||
@@ -82,8 +80,7 @@ class Watcher extends EventEmitter {
|
||||
hot,
|
||||
'devtools-port': devtools_port,
|
||||
bundler,
|
||||
port = +process.env.PORT,
|
||||
ext
|
||||
port = +process.env.PORT
|
||||
}: Opts) {
|
||||
super();
|
||||
|
||||
@@ -98,7 +95,7 @@ class Watcher extends EventEmitter {
|
||||
output: path.resolve(cwd, output),
|
||||
static: path.resolve(cwd, static_files)
|
||||
};
|
||||
this.ext = ext;
|
||||
|
||||
this.port = port;
|
||||
this.closed = false;
|
||||
|
||||
@@ -164,7 +161,7 @@ class Watcher extends EventEmitter {
|
||||
let manifest_data: ManifestData;
|
||||
|
||||
try {
|
||||
manifest_data = create_manifest_data(routes, this.ext);
|
||||
manifest_data = create_manifest_data(routes);
|
||||
create_app({
|
||||
bundler: this.bundler,
|
||||
manifest_data,
|
||||
@@ -192,7 +189,7 @@ class Watcher extends EventEmitter {
|
||||
},
|
||||
() => {
|
||||
try {
|
||||
const new_manifest_data = create_manifest_data(routes, this.ext);
|
||||
const new_manifest_data = create_manifest_data(routes);
|
||||
create_app({
|
||||
bundler: this.bundler,
|
||||
manifest_data, // TODO is this right? not new_manifest_data?
|
||||
@@ -209,18 +206,14 @@ class Watcher extends EventEmitter {
|
||||
});
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
),
|
||||
|
||||
if (this.live) {
|
||||
this.filewatchers.push(
|
||||
fs.watch(`${src}/template.html`, () => {
|
||||
this.dev_server.send({
|
||||
action: 'reload'
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
fs.watch(`${src}/template.html`, () => {
|
||||
this.dev_server.send({
|
||||
action: 'reload'
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
let deferred = new Deferred();
|
||||
|
||||
@@ -259,7 +252,7 @@ class Watcher extends EventEmitter {
|
||||
this.dev_server.send({
|
||||
status: 'completed'
|
||||
});
|
||||
} else if (this.live) {
|
||||
} else {
|
||||
this.dev_server.send({
|
||||
action: 'reload'
|
||||
});
|
||||
@@ -274,54 +267,48 @@ class Watcher extends EventEmitter {
|
||||
});
|
||||
};
|
||||
|
||||
const start_server = () => {
|
||||
// we need to give the child process its own DevTools port,
|
||||
// otherwise Node will try to use the parent's (and fail)
|
||||
const debugArgRegex = /--inspect(?:-brk|-port)?|--debug-port/;
|
||||
const execArgv = process.execArgv.slice();
|
||||
if (execArgv.some((arg: string) => !!arg.match(debugArgRegex))) {
|
||||
execArgv.push(`--inspect-port=${this.devtools_port}`);
|
||||
}
|
||||
|
||||
this.proc = child_process.fork(`${dest}/server/server.js`, [], {
|
||||
cwd: process.cwd(),
|
||||
env: Object.assign({
|
||||
PORT: this.port
|
||||
}, process.env),
|
||||
stdio: ['ipc'],
|
||||
execArgv
|
||||
});
|
||||
|
||||
this.proc.stdout.on('data', chunk => {
|
||||
this.emit('stdout', chunk);
|
||||
});
|
||||
|
||||
this.proc.stderr.on('data', chunk => {
|
||||
this.emit('stderr', chunk);
|
||||
});
|
||||
|
||||
this.proc.on('message', message => {
|
||||
if (message.__sapper__ && message.event === 'basepath') {
|
||||
this.emit('basepath', {
|
||||
basepath: message.basepath
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.proc.on('exit', emitFatal);
|
||||
};
|
||||
|
||||
if (this.proc) {
|
||||
this.proc.removeListener('exit', emitFatal);
|
||||
this.proc.kill();
|
||||
this.proc.on('exit', () => {
|
||||
start_server();
|
||||
restart();
|
||||
});
|
||||
this.proc.on('exit', restart);
|
||||
} else {
|
||||
start_server();
|
||||
restart();
|
||||
}
|
||||
|
||||
// we need to give the child process its own DevTools port,
|
||||
// otherwise Node will try to use the parent's (and fail)
|
||||
const debugArgRegex = /--inspect(?:-brk|-port)?|--debug-port/;
|
||||
const execArgv = process.execArgv.slice();
|
||||
if (execArgv.some((arg: string) => !!arg.match(debugArgRegex))) {
|
||||
execArgv.push(`--inspect-port=${this.devtools_port}`);
|
||||
}
|
||||
|
||||
this.proc = child_process.fork(`${dest}/server/server.js`, [], {
|
||||
cwd: process.cwd(),
|
||||
env: Object.assign({
|
||||
PORT: this.port
|
||||
}, process.env),
|
||||
stdio: ['ipc'],
|
||||
execArgv
|
||||
});
|
||||
|
||||
this.proc.stdout.on('data', chunk => {
|
||||
this.emit('stdout', chunk);
|
||||
});
|
||||
|
||||
this.proc.stderr.on('data', chunk => {
|
||||
this.emit('stderr', chunk);
|
||||
});
|
||||
|
||||
this.proc.on('message', message => {
|
||||
if (message.__sapper__ && message.event === 'basepath') {
|
||||
this.emit('basepath', {
|
||||
basepath: message.basepath
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.proc.on('exit', emitFatal);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -346,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,
|
||||
|
||||
@@ -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);
|
||||
@@ -132,23 +131,19 @@ async function _export({
|
||||
if (seen.has(pathname)) return;
|
||||
seen.add(pathname);
|
||||
|
||||
const r = await q.add(async () => {
|
||||
const timeout_deferred = new Deferred();
|
||||
const the_timeout = setTimeout(() => {
|
||||
timeout_deferred.reject(new Error(`Timed out waiting for ${url.href}`));
|
||||
}, timeout);
|
||||
const timeout_deferred = new Deferred();
|
||||
const the_timeout = setTimeout(() => {
|
||||
timeout_deferred.reject(new Error(`Timed out waiting for ${url.href}`));
|
||||
}, timeout);
|
||||
|
||||
const r = await Promise.race([
|
||||
fetch(url.href, {
|
||||
redirect: 'manual'
|
||||
}),
|
||||
timeout_deferred.promise
|
||||
]);
|
||||
const r = await Promise.race([
|
||||
q.add(() => fetch(url.href, {
|
||||
redirect: 'manual'
|
||||
})),
|
||||
timeout_deferred.promise
|
||||
]);
|
||||
|
||||
clearTimeout(the_timeout); // prevent it hanging at the end
|
||||
|
||||
return r;
|
||||
}) as Response;
|
||||
clearTimeout(the_timeout); // prevent it hanging at the end
|
||||
|
||||
let type = r.headers.get('Content-Type');
|
||||
|
||||
@@ -156,8 +151,6 @@ async function _export({
|
||||
|
||||
const range = ~~(r.status / 100);
|
||||
|
||||
let tasks = [];
|
||||
|
||||
if (range === 2) {
|
||||
if (type === 'text/html') {
|
||||
// parse link rel=preload headers and embed them in the HTML
|
||||
@@ -179,6 +172,8 @@ async function _export({
|
||||
let match;
|
||||
let pattern = /<a ([\s\S]+?)>/gm;
|
||||
|
||||
let promise;
|
||||
|
||||
while (match = pattern.exec(cleaned)) {
|
||||
const attrs = match[1];
|
||||
const href = get_href(attrs);
|
||||
@@ -187,10 +182,12 @@ async function _export({
|
||||
const url = resolve(base.href, href);
|
||||
|
||||
if (url.protocol === protocol && url.host === host) {
|
||||
tasks.push(handle(url));
|
||||
promise = handle(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await promise;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,12 +198,10 @@ async function _export({
|
||||
type = 'text/html';
|
||||
body = `<script>window.location.href = "${location.replace(origin, '')}"</script>`;
|
||||
|
||||
tasks.push(handle(resolve(root.href, location)));
|
||||
await handle(resolve(root.href, location));
|
||||
}
|
||||
|
||||
save(pathname, r.status, type, body);
|
||||
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -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'))
|
||||
);
|
||||
}
|
||||
22
src/cli.ts
22
src/cli.ts
@@ -31,7 +31,6 @@ prog.command('dev')
|
||||
.option('--static', 'Static files directory', 'static')
|
||||
.option('--output', 'Sapper output directory', 'src/node_modules/@sapper')
|
||||
.option('--build-dir', 'Development build directory', '__sapper__/dev')
|
||||
.option('--ext', 'Custom Route Extension', '.svelte .html')
|
||||
.action(async (opts: {
|
||||
port: number,
|
||||
open: boolean,
|
||||
@@ -44,8 +43,7 @@ prog.command('dev')
|
||||
routes: string,
|
||||
static: string,
|
||||
output: string,
|
||||
'build-dir': string,
|
||||
ext: string
|
||||
'build-dir': string
|
||||
}) => {
|
||||
const { dev } = await import('./api/dev');
|
||||
|
||||
@@ -61,8 +59,7 @@ prog.command('dev')
|
||||
'dev-port': opts['dev-port'],
|
||||
live: opts.live,
|
||||
hot: opts.hot,
|
||||
bundler: opts.bundler,
|
||||
ext: opts.ext
|
||||
bundler: opts.bundler
|
||||
});
|
||||
|
||||
let first = true;
|
||||
@@ -154,7 +151,6 @@ prog.command('build [dest]')
|
||||
.option('--src', 'Source directory', 'src')
|
||||
.option('--routes', 'Routes directory', 'src/routes')
|
||||
.option('--output', 'Sapper output directory', 'src/node_modules/@sapper')
|
||||
.option('--ext', 'Custom Route Extension', '.svelte .html')
|
||||
.example(`build custom-dir -p 4567`)
|
||||
.action(async (dest = '__sapper__/build', opts: {
|
||||
port: string,
|
||||
@@ -163,13 +159,12 @@ prog.command('build [dest]')
|
||||
cwd: string,
|
||||
src: string,
|
||||
routes: string,
|
||||
output: string,
|
||||
ext: string
|
||||
output: string
|
||||
}) => {
|
||||
console.log(`> Building...`);
|
||||
|
||||
try {
|
||||
await _build(opts.bundler, opts.legacy, opts.cwd, opts.src, opts.routes, opts.output, dest, opts.ext);
|
||||
await _build(opts.bundler, opts.legacy, opts.cwd, opts.src, opts.routes, opts.output, dest);
|
||||
|
||||
const launcher = path.resolve(dest, 'index.js');
|
||||
|
||||
@@ -204,7 +199,6 @@ prog.command('export [dest]')
|
||||
.option('--static', 'Static files directory', 'static')
|
||||
.option('--output', 'Sapper output directory', 'src/node_modules/@sapper')
|
||||
.option('--build-dir', 'Intermediate build directory', '__sapper__/build')
|
||||
.option('--ext', 'Custom Route Extension', '.svelte .html')
|
||||
.action(async (dest = '__sapper__/export', opts: {
|
||||
build: boolean,
|
||||
legacy: boolean,
|
||||
@@ -218,12 +212,11 @@ prog.command('export [dest]')
|
||||
static: string,
|
||||
output: string,
|
||||
'build-dir': string,
|
||||
ext: string
|
||||
}) => {
|
||||
try {
|
||||
if (opts.build) {
|
||||
console.log(`> Building...`);
|
||||
await _build(opts.bundler, opts.legacy, opts.cwd, opts.src, opts.routes, opts.output, opts['build-dir'], opts.ext);
|
||||
await _build(opts.bundler, opts.legacy, opts.cwd, opts.src, opts.routes, opts.output, opts['build-dir']);
|
||||
console.error(`\n> Built in ${elapsed(start)}`);
|
||||
}
|
||||
|
||||
@@ -272,8 +265,7 @@ async function _build(
|
||||
src: string,
|
||||
routes: string,
|
||||
output: string,
|
||||
dest: string,
|
||||
ext: string
|
||||
dest: string
|
||||
) {
|
||||
const { build } = await import('./api/build');
|
||||
|
||||
@@ -284,7 +276,7 @@ async function _build(
|
||||
src,
|
||||
routes,
|
||||
dest,
|
||||
ext,
|
||||
|
||||
oncompile: event => {
|
||||
let banner = `built ${event.type}`;
|
||||
let c = (txt: string) => colors.cyan(txt);
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,10 +4,9 @@ import svelte from 'svelte/compiler';
|
||||
import { Page, PageComponent, ServerRoute, ManifestData } from '../interfaces';
|
||||
import { posixify, reserved_words } from '../utils';
|
||||
|
||||
export default function create_manifest_data(cwd: string, extensions: string = '.svelte .html'): ManifestData {
|
||||
|
||||
const component_extensions = extensions.split(' ');
|
||||
const component_extensions = ['.svelte', '.html']; // TODO make this configurable (to include e.g. .svelte.md?)
|
||||
|
||||
export default function create_manifest_data(cwd: string): ManifestData {
|
||||
// TODO remove in a future version
|
||||
if (!fs.existsSync(cwd)) {
|
||||
throw new Error(`As of Sapper 0.21, the routes/ directory should become src/routes/`);
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
<script context="module">
|
||||
export function preload({ query, params }) {
|
||||
const { rest } = params;
|
||||
return { rest };
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { stores } from '@sapper/app';
|
||||
const { page } = stores();
|
||||
export let rest;
|
||||
</script>
|
||||
|
||||
<h1>{$page.params.rest.join(',')}</h1>
|
||||
<h2>{rest.join(',')}</h2>
|
||||
|
||||
<a href="xyz/abc/qwe/deep.json">deep</a>
|
||||
<a href="xyz/abc">back</a>
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
<script context="module">
|
||||
export function preload({ query, params }) {
|
||||
const { rest } = params;
|
||||
return { rest };
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { stores } from '@sapper/app';
|
||||
const { page } = stores();
|
||||
export let rest;
|
||||
</script>
|
||||
|
||||
<h1>{$page.params.rest.join(',')}</h1>
|
||||
<h2>{rest.join(',')}</h2>
|
||||
|
||||
<a href="xyz/abc/deep">deep</a>
|
||||
<a href="xyz/abc">deep</a>
|
||||
<a href="xyz/abc/def">deep</a>
|
||||
<a href="xyz/abc/def/ghi">deep</a>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware())
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as assert from 'assert';
|
||||
import * as http from 'http';
|
||||
import {build} from '../../../api';
|
||||
import {AppRunner} from '../AppRunner';
|
||||
import { build } from '../../../api';
|
||||
import { AppRunner } from '../AppRunner';
|
||||
|
||||
declare let deleted: { id: number };
|
||||
declare let el: any;
|
||||
@@ -140,7 +140,7 @@ describe('basics', function() {
|
||||
);
|
||||
|
||||
// TODO preload more than just the entry point
|
||||
const regex = /<\/client\/client\.\w+\.js>;rel="modulepreload"/;
|
||||
const regex = /<\/sapper\/client\.\w+\.js>;rel="modulepreload"/;
|
||||
const link = <string>headers['link'];
|
||||
|
||||
assert.ok(regex.test(link), link);
|
||||
@@ -267,6 +267,7 @@ describe('basics', function() {
|
||||
await r.sapper.start();
|
||||
|
||||
assert.equal(await r.text('h1'), 'foo');
|
||||
|
||||
await r.page.click('[href="dirs/bar"]');
|
||||
await r.wait();
|
||||
assert.equal(await r.text('h1'), 'bar');
|
||||
@@ -277,26 +278,11 @@ describe('basics', function() {
|
||||
await r.sapper.start();
|
||||
|
||||
assert.equal(await r.text('h1'), 'abc,xyz');
|
||||
await r.page.click('[href="xyz/abc/def/ghi"]');
|
||||
await r.wait();
|
||||
assert.equal(await r.text('h1'), 'xyz,abc,def,ghi');
|
||||
assert.equal(await r.text('h2'), 'xyz,abc,def,ghi');
|
||||
await r.page.click('[href="xyz/abc/def"]');
|
||||
await r.wait();
|
||||
assert.equal(await r.text('h1'), 'xyz,abc,def');
|
||||
assert.equal(await r.text('h2'), 'xyz,abc,def');
|
||||
await r.page.click('[href="xyz/abc/def"]');
|
||||
await r.wait();
|
||||
assert.equal(await r.text('h1'), 'xyz,abc,def');
|
||||
assert.equal(await r.text('h2'), 'xyz,abc,def');
|
||||
await r.page.click('[href="xyz/abc"]');
|
||||
await r.wait();
|
||||
assert.equal(await r.text('h1'), 'xyz,abc');
|
||||
assert.equal(await r.text('h2'), 'xyz,abc');
|
||||
|
||||
await r.page.click('[href="xyz/abc/deep"]');
|
||||
await r.wait();
|
||||
assert.equal(await r.text('h1'), 'xyz,abc');
|
||||
assert.equal(await r.text('h2'), 'xyz,abc');
|
||||
|
||||
await r.page.click('[href="xyz/abc/qwe/deep.json"]');
|
||||
await r.wait();
|
||||
assert.equal(
|
||||
|
||||
@@ -2,11 +2,12 @@ const { NODE_ENV, PORT } = process.env;
|
||||
|
||||
export const dev = NODE_ENV === 'development';
|
||||
|
||||
export function start(app) {
|
||||
export function start(server) {
|
||||
const port = parseInt(PORT) || 0;
|
||||
|
||||
app.listen(port, () => {
|
||||
const address = app.server.address();
|
||||
server.listen(port, () => {
|
||||
server = server.server || server;
|
||||
const address = server.address();
|
||||
|
||||
process.env.PORT = address.port;
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import resolve from 'rollup-plugin-node-resolve';
|
||||
import replace from 'rollup-plugin-replace';
|
||||
import svelte from 'rollup-plugin-svelte';
|
||||
|
||||
const mode = process.env.NODE_ENV;
|
||||
const dev = mode === 'development';
|
||||
|
||||
const config = require('../../../config/rollup.js');
|
||||
|
||||
export default {
|
||||
client: {
|
||||
input: config.client.input(),
|
||||
output: config.client.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': true,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||
}),
|
||||
svelte({
|
||||
extensions: ['.whokilledthemuffinman', '.jesuslivesineveryone', '.mdx', '.svelte', '.html'],
|
||||
dev,
|
||||
hydratable: true,
|
||||
emitCss: true
|
||||
}),
|
||||
resolve()
|
||||
]
|
||||
},
|
||||
|
||||
server: {
|
||||
input: config.server.input(),
|
||||
output: config.server.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': false,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||
}),
|
||||
svelte({
|
||||
extensions: ['.whokilledthemuffinman', '.jesuslivesineveryone', '.mdx', '.svelte', '.html'],
|
||||
generate: 'ssr',
|
||||
dev
|
||||
}),
|
||||
resolve({
|
||||
preferBuiltins: true
|
||||
})
|
||||
],
|
||||
external: ['sirv', 'polka']
|
||||
},
|
||||
|
||||
serviceworker: {
|
||||
input: config.serviceworker.input(),
|
||||
output: config.serviceworker.output(),
|
||||
plugins: [
|
||||
resolve(),
|
||||
replace({
|
||||
'process.browser': true,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||
})
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import * as sapper from '@sapper/app';
|
||||
|
||||
window.start = () => sapper.start({
|
||||
target: document.querySelector('#sapper')
|
||||
});
|
||||
|
||||
window.prefetchRoutes = () => sapper.prefetchRoutes();
|
||||
window.prefetch = href => sapper.prefetch(href);
|
||||
window.goto = href => sapper.goto(href);
|
||||
@@ -1,6 +0,0 @@
|
||||
<script>
|
||||
import { stores } from '@sapper/app';
|
||||
const { page } = stores();
|
||||
</script>
|
||||
|
||||
<h1>{$page.params.slug.toUpperCase()}</h1>
|
||||
@@ -1,3 +0,0 @@
|
||||
<h1>hi</h1>
|
||||
|
||||
<p>hi</p>
|
||||
@@ -1 +0,0 @@
|
||||
<h1>a</h1>
|
||||
@@ -1 +0,0 @@
|
||||
<h1>Tremendous!</h1>
|
||||
@@ -1,8 +0,0 @@
|
||||
<h1>Great success!</h1>
|
||||
|
||||
<a href="a">a</a>
|
||||
<a href="ambiguous/ok.json">ok</a>
|
||||
<a href="echo-query?message">ok</a>
|
||||
<a href="echo-query?p=one&p=two">ok</a>
|
||||
|
||||
<div class='hydrate-test'></div>
|
||||
@@ -1 +0,0 @@
|
||||
<h1>Bazooom!</h1>
|
||||
@@ -1,9 +0,0 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware())
|
||||
|
||||
start(app);
|
||||
@@ -1,81 +0,0 @@
|
||||
import * as sapper from '@sapper/service-worker';
|
||||
|
||||
const ASSETS = `cache${sapper.timestamp}`;
|
||||
|
||||
// `app.shell` is an array of all the files generated by webpack,
|
||||
// `app.files` is an array of everything in the `static` directory
|
||||
const to_cache = sapper.shell.concat(sapper.files);
|
||||
const cached = new Set(to_cache);
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(ASSETS)
|
||||
.then(cache => cache.addAll(to_cache))
|
||||
.then(() => {
|
||||
self.skipWaiting();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(async keys => {
|
||||
// delete old caches
|
||||
for (const key of keys) {
|
||||
if (key !== ASSETS) await caches.delete(key);
|
||||
}
|
||||
|
||||
self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
if (event.request.method !== 'GET') return;
|
||||
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// don't try to handle e.g. data: URIs
|
||||
if (!url.protocol.startsWith('http')) return;
|
||||
|
||||
// ignore dev server requests
|
||||
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||
|
||||
// always serve assets and webpack-generated files from cache
|
||||
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||
event.respondWith(caches.match(event.request));
|
||||
return;
|
||||
}
|
||||
|
||||
// for pages, you might want to serve a shell `index.html` file,
|
||||
// which Sapper has generated for you. It's not right for every
|
||||
// app, but if it's right for yours then uncomment this section
|
||||
/*
|
||||
event.respondWith(caches.match('/index.html'));
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
if (event.request.cache === 'only-if-cached') return;
|
||||
|
||||
// for everything else, try the network first, falling back to
|
||||
// cache if the user is offline. (If the pages never change, you
|
||||
// might prefer a cache-first approach to a network-first one.)
|
||||
event.respondWith(
|
||||
caches
|
||||
.open(`offline${sapper.timestamp}`)
|
||||
.then(async cache => {
|
||||
try {
|
||||
const response = await fetch(event.request);
|
||||
cache.put(event.request, response.clone());
|
||||
return response;
|
||||
} catch(err) {
|
||||
const response = await cache.match(event.request);
|
||||
if (response) return response;
|
||||
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
|
||||
%sapper.base%
|
||||
%sapper.styles%
|
||||
%sapper.head%
|
||||
</head>
|
||||
<body>
|
||||
<div id='sapper'>%sapper.html%</div>
|
||||
%sapper.scripts%
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,61 +0,0 @@
|
||||
import * as assert from 'assert';
|
||||
import { build } from '../../../api';
|
||||
import { AppRunner } from '../AppRunner';
|
||||
|
||||
describe('custom extensions', function() {
|
||||
this.timeout(10000);
|
||||
|
||||
let r: AppRunner;
|
||||
|
||||
// hooks
|
||||
before('build app', () => build({ cwd: __dirname , ext: '.jesuslivesineveryone .whokilledthemuffinman .mdx .svelte' }));
|
||||
before('start runner', async () => {
|
||||
r = await new AppRunner().start(__dirname);
|
||||
});
|
||||
|
||||
after(() => r && r.end());
|
||||
|
||||
|
||||
|
||||
it('works with arbitrary extensions', async () => {
|
||||
await r.load(`/`);
|
||||
|
||||
|
||||
assert.equal(
|
||||
await r.text('h1'),
|
||||
'Great success!'
|
||||
);
|
||||
});
|
||||
|
||||
it('works with other arbitrary extensions', async () => {
|
||||
await r.load(`/const`);
|
||||
|
||||
assert.equal(
|
||||
await r.text('h1'),
|
||||
'Tremendous!'
|
||||
);
|
||||
|
||||
await r.load(`/a`);
|
||||
|
||||
assert.equal(
|
||||
await r.text('h1'),
|
||||
'a'
|
||||
);
|
||||
|
||||
await r.load(`/test-slug`);
|
||||
|
||||
assert.equal(
|
||||
await r.text('h1'),
|
||||
'TEST-SLUG'
|
||||
);
|
||||
|
||||
await r.load(`/unsafe-replacement`);
|
||||
|
||||
assert.equal(
|
||||
await r.text('h1'),
|
||||
'Bazooom!'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import resolve from 'rollup-plugin-node-resolve';
|
||||
import replace from 'rollup-plugin-replace';
|
||||
import svelte from 'rollup-plugin-svelte';
|
||||
|
||||
const mode = process.env.NODE_ENV;
|
||||
const dev = mode === 'development';
|
||||
|
||||
const config = require('../../../config/rollup.js');
|
||||
|
||||
export default {
|
||||
client: {
|
||||
input: config.client.input(),
|
||||
output: config.client.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': true,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||
}),
|
||||
svelte({
|
||||
dev,
|
||||
hydratable: true,
|
||||
emitCss: true
|
||||
}),
|
||||
resolve()
|
||||
]
|
||||
},
|
||||
|
||||
server: {
|
||||
input: config.server.input(),
|
||||
output: config.server.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': false,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||
}),
|
||||
svelte({
|
||||
generate: 'ssr',
|
||||
dev
|
||||
}),
|
||||
resolve({
|
||||
preferBuiltins: true
|
||||
})
|
||||
],
|
||||
external: ['sirv', 'polka']
|
||||
},
|
||||
|
||||
serviceworker: {
|
||||
input: config.serviceworker.input(),
|
||||
output: config.serviceworker.output(),
|
||||
plugins: [
|
||||
resolve(),
|
||||
replace({
|
||||
'process.browser': true,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||
})
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import * as sapper from '@sapper/app';
|
||||
|
||||
window.start = () => sapper.start({
|
||||
target: document.querySelector('#sapper')
|
||||
});
|
||||
|
||||
window.prefetchRoutes = () => sapper.prefetchRoutes();
|
||||
window.prefetch = href => sapper.prefetch(href);
|
||||
window.goto = href => sapper.goto(href);
|
||||
@@ -1,3 +0,0 @@
|
||||
<h1>{status}</h1>
|
||||
|
||||
<p>{error.message}</p>
|
||||
@@ -1,15 +0,0 @@
|
||||
<script context="module">
|
||||
export function preload({ params }) {
|
||||
if (params.x === 'a') {
|
||||
return new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let x;
|
||||
</script>
|
||||
|
||||
<a href="b-{x}">b-{x}</a>
|
||||
@@ -1,5 +0,0 @@
|
||||
<script>
|
||||
export let x;
|
||||
</script>
|
||||
|
||||
<p>b-{x}</p>
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
<a href="a-a">1</a>
|
||||
<a href="a-b">2</a>
|
||||
@@ -1,13 +0,0 @@
|
||||
import sirv from 'sirv';
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start, dev } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(
|
||||
sirv('static', { dev }),
|
||||
sapper.middleware()
|
||||
);
|
||||
|
||||
start(app);
|
||||
@@ -1,82 +0,0 @@
|
||||
import * as sapper from '@sapper/service-worker';
|
||||
|
||||
const ASSETS = `cache${sapper.timestamp}`;
|
||||
|
||||
// `shell` is an array of all the files generated by webpack,
|
||||
// `files` is an array of everything in the `static` directory
|
||||
const to_cache = sapper.shell.concat(sapper.files);
|
||||
const cached = new Set(to_cache);
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(ASSETS)
|
||||
.then(cache => cache.addAll(to_cache))
|
||||
.then(() => {
|
||||
self.skipWaiting();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(async keys => {
|
||||
// delete old caches
|
||||
for (const key of keys) {
|
||||
if (key !== ASSETS) await caches.delete(key);
|
||||
}
|
||||
|
||||
self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
if (event.request.method !== 'GET') return;
|
||||
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// don't try to handle e.g. data: URIs
|
||||
if (!url.protocol.startsWith('http')) return;
|
||||
|
||||
// ignore dev server requests
|
||||
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||
|
||||
// always serve assets and webpack-generated files from cache
|
||||
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||
event.respondWith(caches.match(event.request));
|
||||
return;
|
||||
}
|
||||
|
||||
// for pages, you might want to serve a shell `index.html` file,
|
||||
// which Sapper has generated for you. It's not right for every
|
||||
// app, but if it's right for yours then uncomment this section
|
||||
/*
|
||||
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||
event.respondWith(caches.match('/index.html'));
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
if (event.request.cache === 'only-if-cached') return;
|
||||
|
||||
// for everything else, try the network first, falling back to
|
||||
// cache if the user is offline. (If the pages never change, you
|
||||
// might prefer a cache-first approach to a network-first one.)
|
||||
event.respondWith(
|
||||
caches
|
||||
.open(`offline${sapper.timestamp}`)
|
||||
.then(async cache => {
|
||||
try {
|
||||
const response = await fetch(event.request);
|
||||
cache.put(event.request, response.clone());
|
||||
return response;
|
||||
} catch(err) {
|
||||
const response = await cache.match(event.request);
|
||||
if (response) return response;
|
||||
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
|
||||
%sapper.base%
|
||||
%sapper.styles%
|
||||
%sapper.head%
|
||||
</head>
|
||||
<body>
|
||||
<div id='sapper'>%sapper.html%</div>
|
||||
%sapper.scripts%
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +0,0 @@
|
||||
body {
|
||||
font-family: 'Comic Sans MS';
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import * as api from '../../../api';
|
||||
|
||||
describe('export-queue', function() {
|
||||
this.timeout(10000);
|
||||
|
||||
// hooks
|
||||
before('build app', () => api.build({ cwd: __dirname }));
|
||||
|
||||
// tests
|
||||
it('exports a site with inconsistent load time', async () => {
|
||||
await api.export({ cwd: __dirname });
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,6 @@
|
||||
import sirv from 'sirv';
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
import { start } from '../../common.js';
|
||||
|
||||
import { start, dev } from '../../common.js';
|
||||
const server = sapper.server();
|
||||
|
||||
const app = polka()
|
||||
.use(
|
||||
sirv('static', { dev }),
|
||||
sapper.middleware()
|
||||
);
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import sirv from 'sirv';
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
import { start } from '../../common.js';
|
||||
|
||||
import { start, dev } from '../../common.js';
|
||||
const server = sapper.server();
|
||||
|
||||
const app = polka()
|
||||
.use(
|
||||
sirv('static', { dev }),
|
||||
sapper.middleware()
|
||||
);
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -13,8 +13,8 @@ describe('export', function() {
|
||||
it('crawls a site', () => {
|
||||
const files = walk(`${__dirname}/__sapper__/export`);
|
||||
|
||||
const client_assets = files.filter(file => file.startsWith('client/'));
|
||||
const non_client_assets = files.filter(file => !file.startsWith('client/')).sort();
|
||||
const client_assets = files.filter(file => file.startsWith('sapper/'));
|
||||
const non_client_assets = files.filter(file => !file.startsWith('sapper/')).sort();
|
||||
|
||||
assert.ok(client_assets.length > 0);
|
||||
|
||||
|
||||
@@ -16,5 +16,4 @@
|
||||
</script>
|
||||
|
||||
<span>z: {$page.params.z} {count}</span>
|
||||
<a href="foo/bar/qux">goto foo/bar/qux</a>
|
||||
<a href="foo/abc/def">goto foo/abc/def</a>
|
||||
<a href="foo/bar/qux">click me</a>
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -23,8 +23,7 @@ describe('layout', function() {
|
||||
assert.deepEqual(text1.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||
'y: bar 1',
|
||||
'z: baz 1',
|
||||
'goto foo/bar/qux',
|
||||
'goto foo/abc/def',
|
||||
'click me',
|
||||
'child segment: baz'
|
||||
]);
|
||||
|
||||
@@ -33,8 +32,7 @@ describe('layout', function() {
|
||||
assert.deepEqual(text2.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||
'y: bar 1',
|
||||
'z: baz 1',
|
||||
'goto foo/bar/qux',
|
||||
'goto foo/abc/def',
|
||||
'click me',
|
||||
'child segment: baz'
|
||||
]);
|
||||
|
||||
@@ -45,22 +43,9 @@ describe('layout', function() {
|
||||
assert.deepEqual(text3.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||
'y: bar 1',
|
||||
'z: qux 2',
|
||||
'goto foo/bar/qux',
|
||||
'goto foo/abc/def',
|
||||
'click me',
|
||||
'child segment: qux'
|
||||
]);
|
||||
|
||||
await r.page.click('[href="foo/abc/def"]');
|
||||
await r.wait();
|
||||
|
||||
const text4 = await r.text('#sapper');
|
||||
assert.deepEqual(text4.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||
'y: abc 2',
|
||||
'z: def 3',
|
||||
'goto foo/bar/qux',
|
||||
'goto foo/abc/def',
|
||||
'child segment: def'
|
||||
]);
|
||||
});
|
||||
|
||||
it('survives the tests with no server errors', () => {
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<script context="module">
|
||||
export function preload(page) {
|
||||
return {
|
||||
query: page.query
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let query;
|
||||
</script>
|
||||
|
||||
<pre>{JSON.stringify(query)}</pre>
|
||||
|
||||
<a href="echo?foo=1">foo=1</a>
|
||||
<a href="echo?foo=2">foo=2</a>
|
||||
<a href="echo?foo=3">foo=3</a>
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -109,23 +109,4 @@ describe('preloading', function() {
|
||||
it('survives the tests with no server errors', () => {
|
||||
assert.deepEqual(r.errors, []);
|
||||
});
|
||||
|
||||
it('re-runs preload when page.query changes', async () => {
|
||||
await r.load('/echo?foo=1');
|
||||
await r.sapper.start();
|
||||
await r.sapper.prefetchRoutes();
|
||||
|
||||
assert.equal(
|
||||
await r.text('pre'),
|
||||
`{"foo":"1"}`
|
||||
);
|
||||
|
||||
await r.page.click('a[href="echo?foo=2"]');
|
||||
await r.wait();
|
||||
|
||||
assert.equal(
|
||||
await r.text('pre'),
|
||||
`{"foo":"2"}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -40,8 +40,8 @@ describe('with-basepath', function() {
|
||||
it('crawls an exported site with basepath', () => {
|
||||
const files = walk(`${__dirname}/__sapper__/export`);
|
||||
|
||||
const client_assets = files.filter(file => file.startsWith('custom-basepath/client/'));
|
||||
const non_client_assets = files.filter(file => !file.startsWith('custom-basepath/client/')).sort();
|
||||
const client_assets = files.filter(file => file.startsWith('custom-basepath/sapper/'));
|
||||
const non_client_assets = files.filter(file => !file.startsWith('custom-basepath/sapper/')).sort();
|
||||
|
||||
assert.ok(client_assets.length > 0);
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -18,8 +18,8 @@ describe('with-sourcemaps-webpack', function() {
|
||||
assert.equal(shell.filter(_ => _.endsWith('.map')).length, 0,
|
||||
'sourcemap files are not cached in SW');
|
||||
|
||||
const clientShellDir = path.resolve(`${__dirname}/__sapper__/build`, path.dirname(shell[0]));
|
||||
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
||||
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
||||
const client_shell_dir = path.resolve(`${__dirname}/__sapper__/build/client`, path.dirname(shell[0]));
|
||||
const sourcemap_files = fs.readdirSync(client_shell_dir).filter(_ => _.endsWith('.map'));
|
||||
assert.ok(sourcemap_files.length > 0, 'sourcemap files exist');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import polka from 'polka';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
import { start } from '../../common.js';
|
||||
|
||||
const app = polka()
|
||||
.use(sapper.middleware());
|
||||
const server = sapper.server();
|
||||
|
||||
start(app);
|
||||
start(server);
|
||||
|
||||
@@ -18,8 +18,8 @@ describe('with-sourcemaps', function() {
|
||||
assert.equal(shell.filter(_ => _.endsWith('.map')).length, 0,
|
||||
'sourcemap files are not cached in SW');
|
||||
|
||||
const clientShellDir = path.resolve(`${__dirname}/__sapper__/build`, path.dirname(shell[0]));
|
||||
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
||||
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
||||
const client_shell_dir = path.resolve(`${__dirname}/__sapper__/build/client`, path.dirname(shell[0]));
|
||||
const sourcemap_files = fs.readdirSync(client_shell_dir).filter(_ => _.endsWith('.map'));
|
||||
assert.ok(sourcemap_files.length > 0, 'sourcemap files exist');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -177,66 +177,4 @@ describe('manifest_data', () => {
|
||||
pattern: /^\/foo\/?$/
|
||||
}]);
|
||||
});
|
||||
|
||||
it('works with custom extensions' , () => {
|
||||
const { components, pages, server_routes } = create_manifest_data(path.join(__dirname, 'samples/custom-extension'), '.jazz .beebop .funk .html');
|
||||
|
||||
const index = { name: 'index', file: 'index.funk', has_preload: false };
|
||||
const about = { name: 'about', file: 'about.jazz', has_preload: false };
|
||||
const blog = { name: 'blog', file: 'blog/index.html', has_preload: false };
|
||||
const blog_$slug = { name: 'blog_$slug', file: 'blog/[slug].beebop', has_preload: false };
|
||||
|
||||
assert.deepEqual(components, [
|
||||
index,
|
||||
about,
|
||||
blog,
|
||||
blog_$slug
|
||||
]);
|
||||
|
||||
assert.deepEqual(pages, [
|
||||
{
|
||||
pattern: /^\/$/,
|
||||
parts: [
|
||||
{ component: index, params: [] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
pattern: /^\/about\/?$/,
|
||||
parts: [
|
||||
{ component: about, params: [] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
pattern: /^\/blog\/?$/,
|
||||
parts: [
|
||||
{ component: blog, params: [] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
pattern: /^\/blog\/([^\/]+?)\/?$/,
|
||||
parts: [
|
||||
null,
|
||||
{ component: blog_$slug, params: ['slug'] }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
assert.deepEqual(server_routes, [
|
||||
{
|
||||
name: 'route_blog_json',
|
||||
pattern: /^\/blog.json$/,
|
||||
file: 'blog/index.json.js',
|
||||
params: []
|
||||
},
|
||||
{
|
||||
name: 'route_blog_$slug_json',
|
||||
pattern: /^\/blog\/([^\/]+?).json$/,
|
||||
file: 'blog/[slug].json.js',
|
||||
params: ['slug']
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user