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

fix: add link rel=preload for exported sites #568

Merged
merged 3 commits into from
Feb 17, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
},
"dependencies": {
"html-minifier": "^3.5.21",
"http-link-header": "^1.0.2",
"shimport": "0.0.14",
"source-map-support": "^0.5.10",
"sourcemap-codec": "^1.4.4",
Expand Down
54 changes: 36 additions & 18 deletions src/api/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import clean_html from './utils/clean_html';
import minify_html from './utils/minify_html';
import Deferred from './utils/Deferred';
import { noop } from './utils/noop';
import { parse as parseLinkHeader } from 'http-link-header';

type Opts = {
build_dir?: string,
Expand All @@ -21,6 +22,12 @@ type Opts = {
onfile?: ({ file, size, status }: { file: string, size: number, status: number }) => void;
};

type Ref = {
uri: string,
rel: string,
as: string
};

function resolve(from: string, to: string) {
return url.parse(url.resolve(from, to));
}
Expand Down Expand Up @@ -139,38 +146,49 @@ async function _export({
clearTimeout(the_timeout); // prevent it hanging at the end

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

let body = await r.text();

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

if (range === 2) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hiding whitespace will make the diff below a lot easier to read.

if (type === 'text/html' && pathname !== '/service-worker-index.html') {
const cleaned = clean_html(body);
if (type === 'text/html') {
// parse link rel=preload headers and embed them in the HTML
let link = parseLinkHeader(r.headers.get('Link') || '');
link.refs.forEach((ref: Ref) => {
if (ref.rel === 'preload') {
body = body.replace('</head>',
`<link rel="preload" as=${JSON.stringify(ref.as)} href=${JSON.stringify(ref.uri)}></head>`)
}
});
if (pathname !== '/service-worker-index.html') {
const cleaned = clean_html(body);

const q = yootils.queue(8);
let promise;
const q = yootils.queue(8);
let promise;

const base_match = /<base ([\s\S]+?)>/m.exec(cleaned);
const base_href = base_match && get_href(base_match[1]);
const base = resolve(url.href, base_href);
const base_match = /<base ([\s\S]+?)>/m.exec(cleaned);
const base_href = base_match && get_href(base_match[1]);
const base = resolve(url.href, base_href);

let match;
let pattern = /<a ([\s\S]+?)>/gm;
let match;
let pattern = /<a ([\s\S]+?)>/gm;

while (match = pattern.exec(cleaned)) {
const attrs = match[1];
const href = get_href(attrs);
while (match = pattern.exec(cleaned)) {
const attrs = match[1];
const href = get_href(attrs);

if (href) {
const url = resolve(base.href, href);
if (href) {
const url = resolve(base.href, href);

if (url.protocol === protocol && url.host === host) {
promise = q.add(() => handle(url));
if (url.protocol === protocol && url.host === host) {
promise = q.add(() => handle(url));
}
}
}
}

await promise;
await promise;
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions test/apps/export-webpack/src/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as sapper from '@sapper/app';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copy-pasta'd the test/apps/export project into test/apps/export-webpack, changing only rollup.config.js by replacing it with webpack.config.js.


window.start = () => sapper.start({
target: document.querySelector('#sapper')
});

window.prefetchRoutes = () => sapper.prefetchRoutes();
window.prefetch = href => sapper.prefetch(href);
window.goto = href => sapper.goto(href);
3 changes: 3 additions & 0 deletions test/apps/export-webpack/src/routes/_error.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<h1>{status}</h1>

<p>{error.message}</p>
13 changes: 13 additions & 0 deletions test/apps/export-webpack/src/routes/blog/[slug].html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script context="module">
export function preload({ params }) {
return this.fetch(`blog/${params.slug}.json`).then(r => r.json()).then(post => {
return { post };
});
}
</script>

<script>
export let post;
</script>

<h1>{post.title}</h1>
19 changes: 19 additions & 0 deletions test/apps/export-webpack/src/routes/blog/[slug].json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import posts from './_posts.js';

export function get(req, res) {
const post = posts.find(post => post.slug === req.params.slug);

if (post) {
res.writeHead(200, {
'Content-Type': 'application/json'
});

res.end(JSON.stringify(post));
} else {
res.writeHead(404, {
'Content-Type': 'application/json'
});

res.end(JSON.stringify({ message: 'not found' }));
}
}
5 changes: 5 additions & 0 deletions test/apps/export-webpack/src/routes/blog/_posts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default [
{ slug: 'foo', title: 'once upon a foo' },
{ slug: 'bar', title: 'a bar is born' },
{ slug: 'baz', title: 'bazzily ever after' }
];
17 changes: 17 additions & 0 deletions test/apps/export-webpack/src/routes/blog/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script context="module">
export function preload() {
return this.fetch('blog.json').then(r => r.json()).then(posts => {
return { posts };
});
}
</script>

<script>
export let posts;
</script>

<h1>blog</h1>

{#each posts as post}
<p><a href="blog/{post.slug}">{post.title}</a></p>
{/each}
9 changes: 9 additions & 0 deletions test/apps/export-webpack/src/routes/blog/index.json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import posts from './_posts.js';

export function get(req, res) {
res.writeHead(200, {
'Content-Type': 'application/json'
});

res.end(JSON.stringify(posts));
}
4 changes: 4 additions & 0 deletions test/apps/export-webpack/src/routes/index.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<h1>Great success!</h1>

<a href="blog">blog</a>
<a href="">empty anchor</a>
15 changes: 15 additions & 0 deletions test/apps/export-webpack/src/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import sirv from 'sirv';
import polka from 'polka';
import * as sapper from '@sapper/server';

const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';

polka()
.use(
sirv('static', { dev }),
sapper.middleware()
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
Loading