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

Commit 034923b

Browse files
committed
feat: sapper export --no-subfolders
Prevent trailing slash redirect for hosts that prefer `export/foo.htm` instead of `export/foo/index.htm` (github pages)
1 parent e3721bf commit 034923b

27 files changed

+422
-1
lines changed

site/content/docs/10-exporting.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,5 @@ Because `sapper export` writes to the filesystem, it isn't possible to have two
6969
The solution is to rename one of the routes to avoid conflict — for example, `src/routes/foo-bar.js`. (Note that you would also need to update any code that fetches data from `/foo/bar` to reference `/foo-bar` instead.)
7070

7171
For *pages*, we skirt around this problem by writing `export/foo/index.html` instead of `export/foo`.
72+
73+
For hosts that prefer `export/foo.html` instead of `export/foo/index.html` pass the `--no-subfolders` option to prevent a redirect with a trailing slash added to the url.

src/api/export.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type Opts = {
2222
static?: string;
2323
basepath?: string;
2424
host_header?: string;
25+
subfolders?: boolean,
2526
timeout?: number | false;
2627
concurrent?: number;
2728
oninfo?: ({ message }: { message: string }) => void;
@@ -82,6 +83,7 @@ async function _export({
8283
export_dir = '__sapper__/export',
8384
basepath = '',
8485
host_header = undefined,
86+
subfolders = true,
8587
timeout = 5000,
8688
concurrent = 8,
8789
oninfo = noop,
@@ -147,7 +149,11 @@ async function _export({
147149

148150
if (is_html) {
149151
if (!file.endsWith('.html')) {
150-
file = file === '' ? 'index.html' : `${file}/index.html`;
152+
if (file === '') {
153+
file = 'index.html';
154+
} else if (file !== 'manifest.json') {
155+
file = subfolders ? `${file}/index.html` : `${file}.html`;
156+
}
151157
}
152158

153159
if (typeof body === 'string') {

src/cli.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ prog.command('export [dest]')
207207
.option('--build-dir', 'Intermediate build directory', '__sapper__/build')
208208
.option('--ext', 'Custom page route extensions (space separated)', '.svelte .html')
209209
.option('--entry', 'Custom entry points (space separated)', '/')
210+
.option('--subfolders', 'Generate /path/index.html instead of /path.html', true)
210211
.action(async (dest = '__sapper__/export', opts: {
211212
build: boolean;
212213
legacy: boolean;
@@ -223,6 +224,7 @@ prog.command('export [dest]')
223224
'build-dir': string;
224225
ext: string;
225226
entry: string;
227+
subfolders: boolean;
226228
}) => {
227229
try {
228230
if (opts.build) {
@@ -244,6 +246,7 @@ prog.command('export [dest]')
244246
timeout: opts.timeout,
245247
concurrent: opts.concurrent,
246248
entry: opts.entry,
249+
subfolders: opts.subfolders,
247250

248251
oninfo: event => {
249252
console.log(colors.bold().cyan(`> ${event.message}`));
Loading
Loading
5.55 KB
Binary file not shown.
Lines changed: 58 additions & 0 deletions
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+
};
Lines changed: 9 additions & 0 deletions
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);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
export let status;
3+
export let error;
4+
</script>
5+
6+
<h1>{status}</h1>
7+
8+
<p>{error.message}</p>
9+
10+
<pre>{error.stack}</pre>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script context="module">
2+
export function preload({ params }) {
3+
return this.fetch(`blog/${params.slug}.json`).then(r => r.json()).then(post => {
4+
return { post };
5+
});
6+
}
7+
</script>
8+
9+
<script>
10+
export let post;
11+
</script>
12+
13+
<h1>{post.title}</h1>
14+
15+
{#if post.src}
16+
<picture>
17+
<source srcset={post.srcset}/>
18+
<img src={post.src}/>
19+
</picture>
20+
{/if}
21+
22+
{#if post.pdf}
23+
<a href={post.pdf}>{post.pdf}</a>
24+
{/if}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import posts from './_posts.js';
2+
3+
export function get(req, res) {
4+
const post = posts.find(post => post.slug === req.params.slug);
5+
6+
if (post) {
7+
res.writeHead(200, {
8+
'Content-Type': 'application/json'
9+
});
10+
11+
res.end(JSON.stringify(post));
12+
} else {
13+
res.writeHead(404, {
14+
'Content-Type': 'application/json'
15+
});
16+
17+
res.end(JSON.stringify({ message: 'not found' }));
18+
}
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default [
2+
{ slug: 'foo', title: 'once upon a foo', src: 'img/example-512.png', srcset: 'img/example-512.png 512w, img/example-192.png 192w', pdf: 'pdfs/test.pdf' },
3+
{ slug: 'bar', title: 'a bar is born' },
4+
{ slug: 'baz', title: 'bazzily ever after' }
5+
];
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script context="module">
2+
export function preload() {
3+
return this.fetch('blog.json').then(r => r.json()).then(posts => {
4+
return { posts };
5+
});
6+
}
7+
</script>
8+
9+
<script>
10+
export let posts;
11+
</script>
12+
13+
<h1>blog</h1>
14+
15+
{#each posts as post}
16+
<p><a href="blog/{post.slug}">{post.title}</a></p>
17+
{/each}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import posts from './_posts.js';
2+
3+
export function get(req, res) {
4+
res.writeHead(200, {
5+
'Content-Type': 'application/json'
6+
});
7+
8+
res.end(JSON.stringify(posts));
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script context="module">
2+
export function preload({ params }) {
3+
return params;
4+
}
5+
</script>
6+
7+
<script>
8+
export let a;
9+
export let b;
10+
</script>
11+
12+
<p>{a}/{b}.html</p>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script context="module">
2+
export function preload({ params }) {
3+
return params;
4+
}
5+
</script>
6+
7+
<script>
8+
export let a;
9+
export let b;
10+
</script>
11+
12+
<p>{a}/{b}</p>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script context="module">
2+
export function preload({ params }) {
3+
return params;
4+
}
5+
</script>
6+
7+
<script>
8+
export let a;
9+
10+
const list = Array(20).fill().map((_, i) => i + 1);
11+
</script>
12+
13+
{#each list as b}
14+
<a href="boom/{a}/{b}">{a}/{b}</a>
15+
<a href="boom/{a}/{b}.html">{a}/{b}.html</a>
16+
{/each}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
const list = Array(20).fill().map((_, i) => i + 1);
3+
</script>
4+
5+
{#each list as a}
6+
<a href="boom/{a}">{a}</a>
7+
{/each}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const cwd = process.cwd();
4+
5+
export function get(req, res) {
6+
7+
const { slug } = req.params;
8+
const image = path.join(cwd, `/content/${slug}.png`);
9+
10+
const s = fs.createReadStream(image);
11+
s.on('open', () => {
12+
res.writeHead(200, { 'Content-Type': 'image/png' });
13+
s.pipe(res);
14+
});
15+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<svelte:head>
2+
<link rel='manifest' href='manifest.json'>
3+
</svelte:head>
4+
5+
<h1>Great success!</h1>
6+
7+
<a href="blog">blog</a>
8+
<!-- svelte-ignore a11y-invalid-attribute -->
9+
<a href="">empty anchor</a>
10+
<!-- svelte-ignore a11y-invalid-attribute -->
11+
<a href=''>empty anchor #2</a>
12+
<!-- svelte-ignore a11y-invalid-attribute -->
13+
<a href=>empty anchor #3</a>
14+
<!-- svelte-ignore a11y-invalid-attribute -->
15+
<a href= >empty anchor #4</a>
16+
<a href>empty anchor #5</a>
17+
<!-- svelte-ignore a11y-missing-attribute -->
18+
<a>empty anchor #6</a>
19+
<a href="boom">boom</a>
20+
<a href="test.pdf">pdf file</a>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const cwd = process.cwd();
4+
5+
export function get(req, res, next) {
6+
7+
const { slug } = req.params;
8+
const image = path.join(cwd, `/content/${slug}.pdf`);
9+
10+
const s = fs.createReadStream(image);
11+
s.on('open', () => {
12+
res.writeHead(200, { 'Content-Type': 'application/pdf' });
13+
s.pipe(res);
14+
});
15+
}
Lines changed: 13 additions & 0 deletions
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);

0 commit comments

Comments
 (0)