Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.

Commit 9ff87af

Browse files
authored
Merge pull request #698 from mrkishi/gh-689
Fix export queue
2 parents 75afc69 + 9dd63ab commit 9ff87af

File tree

12 files changed

+239
-17
lines changed

12 files changed

+239
-17
lines changed

src/api/export.ts

+21-17
Original file line numberDiff line numberDiff line change
@@ -132,26 +132,32 @@ async function _export({
132132
if (seen.has(pathname)) return;
133133
seen.add(pathname);
134134

135-
const timeout_deferred = new Deferred();
136-
const the_timeout = setTimeout(() => {
137-
timeout_deferred.reject(new Error(`Timed out waiting for ${url.href}`));
138-
}, timeout);
135+
const r = await q.add(async () => {
136+
const timeout_deferred = new Deferred();
137+
const the_timeout = setTimeout(() => {
138+
timeout_deferred.reject(new Error(`Timed out waiting for ${url.href}`));
139+
}, timeout);
139140

140-
const r = await Promise.race([
141-
q.add(() => fetch(url.href, {
142-
redirect: 'manual'
143-
})),
144-
timeout_deferred.promise
145-
]);
141+
const r = await Promise.race([
142+
fetch(url.href, {
143+
redirect: 'manual'
144+
}),
145+
timeout_deferred.promise
146+
]);
146147

147-
clearTimeout(the_timeout); // prevent it hanging at the end
148+
clearTimeout(the_timeout); // prevent it hanging at the end
149+
150+
return r;
151+
}) as Response;
148152

149153
let type = r.headers.get('Content-Type');
150154

151155
let body = await r.text();
152156

153157
const range = ~~(r.status / 100);
154158

159+
let tasks = [];
160+
155161
if (range === 2) {
156162
if (type === 'text/html') {
157163
// parse link rel=preload headers and embed them in the HTML
@@ -173,8 +179,6 @@ async function _export({
173179
let match;
174180
let pattern = /<a ([\s\S]+?)>/gm;
175181

176-
let promise;
177-
178182
while (match = pattern.exec(cleaned)) {
179183
const attrs = match[1];
180184
const href = get_href(attrs);
@@ -183,12 +187,10 @@ async function _export({
183187
const url = resolve(base.href, href);
184188

185189
if (url.protocol === protocol && url.host === host) {
186-
promise = handle(url);
190+
tasks.push(handle(url));
187191
}
188192
}
189193
}
190-
191-
await promise;
192194
}
193195
}
194196
}
@@ -199,10 +201,12 @@ async function _export({
199201
type = 'text/html';
200202
body = `<script>window.location.href = "${location.replace(origin, '')}"</script>`;
201203

202-
await handle(resolve(root.href, location));
204+
tasks.push(handle(resolve(root.href, location)));
203205
}
204206

205207
save(pathname, r.status, type, body);
208+
209+
await Promise.all(tasks);
206210
}
207211

208212
try {
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import resolve from 'rollup-plugin-node-resolve';
2+
import replace from 'rollup-plugin-replace';
3+
import svelte from 'rollup-plugin-svelte';
4+
5+
const mode = process.env.NODE_ENV;
6+
const dev = mode === 'development';
7+
8+
const config = require('../../../config/rollup.js');
9+
10+
export default {
11+
client: {
12+
input: config.client.input(),
13+
output: config.client.output(),
14+
plugins: [
15+
replace({
16+
'process.browser': true,
17+
'process.env.NODE_ENV': JSON.stringify(mode)
18+
}),
19+
svelte({
20+
dev,
21+
hydratable: true,
22+
emitCss: true
23+
}),
24+
resolve()
25+
]
26+
},
27+
28+
server: {
29+
input: config.server.input(),
30+
output: config.server.output(),
31+
plugins: [
32+
replace({
33+
'process.browser': false,
34+
'process.env.NODE_ENV': JSON.stringify(mode)
35+
}),
36+
svelte({
37+
generate: 'ssr',
38+
dev
39+
}),
40+
resolve({
41+
preferBuiltins: true
42+
})
43+
],
44+
external: ['sirv', 'polka']
45+
},
46+
47+
serviceworker: {
48+
input: config.serviceworker.input(),
49+
output: config.serviceworker.output(),
50+
plugins: [
51+
resolve(),
52+
replace({
53+
'process.browser': true,
54+
'process.env.NODE_ENV': JSON.stringify(mode)
55+
})
56+
]
57+
}
58+
};

test/apps/export-queue/src/client.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as sapper from '@sapper/app';
2+
3+
window.start = () => sapper.start({
4+
target: document.querySelector('#sapper')
5+
});
6+
7+
window.prefetchRoutes = () => sapper.prefetchRoutes();
8+
window.prefetch = href => sapper.prefetch(href);
9+
window.goto = href => sapper.goto(href);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<h1>{status}</h1>
2+
3+
<p>{error.message}</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script context="module">
2+
export function preload({ params }) {
3+
if (params.x === 'a') {
4+
return new Promise(resolve => setTimeout(resolve, 100));
5+
}
6+
7+
return params;
8+
}
9+
</script>
10+
11+
<script>
12+
export let x;
13+
</script>
14+
15+
<a href="b-{x}">b-{x}</a>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
export let x;
3+
</script>
4+
5+
<p>b-{x}</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
<a href="a-a">1</a>
3+
<a href="a-b">2</a>

test/apps/export-queue/src/server.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import sirv from 'sirv';
2+
import polka from 'polka';
3+
import * as sapper from '@sapper/server';
4+
5+
import { start, dev } from '../../common.js';
6+
7+
const app = polka()
8+
.use(
9+
sirv('static', { dev }),
10+
sapper.middleware()
11+
);
12+
13+
start(app);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import * as sapper from '@sapper/service-worker';
2+
3+
const ASSETS = `cache${sapper.timestamp}`;
4+
5+
// `shell` is an array of all the files generated by webpack,
6+
// `files` is an array of everything in the `static` directory
7+
const to_cache = sapper.shell.concat(sapper.files);
8+
const cached = new Set(to_cache);
9+
10+
self.addEventListener('install', event => {
11+
event.waitUntil(
12+
caches
13+
.open(ASSETS)
14+
.then(cache => cache.addAll(to_cache))
15+
.then(() => {
16+
self.skipWaiting();
17+
})
18+
);
19+
});
20+
21+
self.addEventListener('activate', event => {
22+
event.waitUntil(
23+
caches.keys().then(async keys => {
24+
// delete old caches
25+
for (const key of keys) {
26+
if (key !== ASSETS) await caches.delete(key);
27+
}
28+
29+
self.clients.claim();
30+
})
31+
);
32+
});
33+
34+
self.addEventListener('fetch', event => {
35+
if (event.request.method !== 'GET') return;
36+
37+
const url = new URL(event.request.url);
38+
39+
// don't try to handle e.g. data: URIs
40+
if (!url.protocol.startsWith('http')) return;
41+
42+
// ignore dev server requests
43+
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
44+
45+
// always serve assets and webpack-generated files from cache
46+
if (url.host === self.location.host && cached.has(url.pathname)) {
47+
event.respondWith(caches.match(event.request));
48+
return;
49+
}
50+
51+
// for pages, you might want to serve a shell `index.html` file,
52+
// which Sapper has generated for you. It's not right for every
53+
// app, but if it's right for yours then uncomment this section
54+
/*
55+
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
56+
event.respondWith(caches.match('/index.html'));
57+
return;
58+
}
59+
*/
60+
61+
if (event.request.cache === 'only-if-cached') return;
62+
63+
// for everything else, try the network first, falling back to
64+
// cache if the user is offline. (If the pages never change, you
65+
// might prefer a cache-first approach to a network-first one.)
66+
event.respondWith(
67+
caches
68+
.open(`offline${sapper.timestamp}`)
69+
.then(async cache => {
70+
try {
71+
const response = await fetch(event.request);
72+
cache.put(event.request, response.clone());
73+
return response;
74+
} catch(err) {
75+
const response = await cache.match(event.request);
76+
if (response) return response;
77+
78+
throw err;
79+
}
80+
})
81+
);
82+
});
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset='utf-8'>
5+
6+
%sapper.base%
7+
%sapper.styles%
8+
%sapper.head%
9+
</head>
10+
<body>
11+
<div id='sapper'>%sapper.html%</div>
12+
%sapper.scripts%
13+
</body>
14+
</html>
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
body {
2+
font-family: 'Comic Sans MS';
3+
}

test/apps/export-queue/test.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as api from '../../../api';
2+
3+
describe('export-queue', function() {
4+
this.timeout(10000);
5+
6+
// hooks
7+
before('build app', () => api.build({ cwd: __dirname }));
8+
9+
// tests
10+
it('exports a site with inconsistent load time', async () => {
11+
await api.export({ cwd: __dirname });
12+
});
13+
});

0 commit comments

Comments
 (0)