kit icon indicating copy to clipboard operation
kit copied to clipboard

adapter-static: control “`route.html` or `route/index.html`” output separately from `trailingSlash` option

Open GeoffreyBooth opened this issue 2 years ago • 8 comments

Describe the problem

I’m generating a static site that I’m putting in an Amazon S3 bucket where it gets served by CDN. My app has a file path like this:

src/routes/foo/+page.js
src/routes/foo/+page.svelte
  1. When I build the site, I want this output as build/foo/index.html.
  2. I want it accessible to my users at /foo, with no trailing slash.

My understanding of the docs is that the only option I have to influence this is export const trailingSlash in my src/routes/+layout.js file. If I use either export const trailingSlash = 'never' or 'ignore', the build command produces build/foo.html. This doesn’t work for me, as my CDN doesn’t resolve /foo to /foo.html.

This leaves export const trailingSlash = 'always', which does cause the build command to produce my desired output of build/foo/index.html. But of course the point of trailingSlash = 'always' is to prevent a path of /foo from working; it must be /foo/. This isn’t the style we use for other URLs, and we want these URLs to be shareable without users needing to know that they shouldn’t strip off this unusual trailing slash. Or to boil down my feature request into a single sentence:

  • I want to use adapter-static to output “folder-based” routes (like src/routes/foo/+page.js) as folders containing index.html files (like build/foo/index.html) without also needing to make trailing slashes required.

Describe the proposed solution

It seems to me like the simplest solution would be to create a new option to explicitly control HTML file output style (whether to output as foo.html or as foo/index.html), and if present it would override the choice determined by trailingSlash.

Alternatives considered

I read https://github.com/sveltejs/kit/issues/5334 and that issue seemed to get derailed into discussions of redirects and other aspects I’m not concerned with. I agree with the original poster’s feeling that it seems wrong that trailingSlash seems to collapse together two orthogonal options (how to treat trailing slashes in paths, and whether to output foo/+page.js as foo.html or foo/index.html).

After writing all of the above I just discovered https://github.com/sveltejs/kit/pull/3801, where what I’m asking for seems to have been removed because the assumption was that there wouldn’t be static hosts out there that behave the way I’m describing, where a hosted foo.html isn’t accessible via /foo and foo/index.html requires a trailing slash. These are configurable options; SvelteKit shouldn’t assume that no hosts support resolving foo/index.html for /foo(no trailing slash). Amazon S3’s website hosting default behavior is to redirect /foo to /foo/ and serve the index file for /foo/, but this can be changed.

Importance

i cannot use SvelteKit without it

Additional Information

No response

GeoffreyBooth avatar Jan 29 '23 01:01 GeoffreyBooth

For anyone else using Amazon S3 who wants paths without trailing slashes, I found a workaround:

  • In your src/routes/+layout.js file, add export const trailingSlash = 'never'. This will cause your build to be output with file paths like build/foo.html.
  • When you upload to S3, save these files without an extension and with Content-Type: text/html. For example, aws s3api put-object --bucket your-bucket --key foo --body foo.html --content-type text/html. Do this for all HTML files except those named index.html.

The explicit content type metadata tells S3 how to serve this object, even without an extension. And since the build was configured to not use trailing slashes, the app’s client-side router also expects this slashless path.

GeoffreyBooth avatar Jan 31 '23 19:01 GeoffreyBooth

I just started using SvelteKit and had the same requirement trailingSlash = 'never', but with <page>/index.html static files. I have build this monstrosity to rename all <page>.html files to <page>/index.html.

patrick-zippenfenig avatar Mar 31 '23 13:03 patrick-zippenfenig

@patrick-zippenfenig cheers for this, ran into the same issue. Though this does seem to break the relative paths of css files and other includes done in the html. Modified the script a bit to do what Geoffrey suggested

agmcleod avatar Dec 06 '23 15:12 agmcleod

One workaround is to structure your route such as src/routes/foo/index.html/+page.svelte. This should result in the prerendered page /foo/index.html but you run into the risk of this issue https://github.com/sveltejs/kit/issues/8676

teemingc avatar Dec 06 '23 16:12 teemingc

I'm also running into this. @GeoffreyBooth's workaround does get me there, but I wouldn't consider it a solution because it requires saving the files without an extension in the project, e.g. foo instead of foo.html.

I would love to see this addressed, happy to help test a fix (although testing is the straightforward part probably).

rdeese avatar Dec 15 '23 16:12 rdeese

I've found a solution that works for me. Unlike what @GeoffreyBooth claims in the original issue, paths without a trailing slash do work when static hosting on AWS, if your static site is built with trailingSlash = 'always'. This is because AWS automatically redirects e.g. /foo to /foo/, and serves /foo/index.html (which is generated by SvelteKit, so long as you set trailingSlash = 'always').

So I guess specifically I disagree with two claims that @GeoffreyBooth makes:

But of course the point of trailingSlash = 'always' is to prevent a path of /foo from working

/foo does work using S3 static hosting -- it redirects to /foo/

and

we want these URLs to be shareable without users needing to know that they shouldn’t strip off this unusual trailing slash.

The URL /foo is shareable because it will automatically redirect. It doesn't matter if users strip the trailing slash.

I hope this is helpful for anyone sharing this issue.

rdeese avatar Dec 17 '23 05:12 rdeese

So I guess specifically I disagree with two claims that @GeoffreyBooth makes:

My point is that most websites don't have paths that end in slashes, and such URLs look incorrect to average users. We want paths that don't end in slashes and that don't redirect to paths that end in slashes.

GeoffreyBooth avatar Dec 17 '23 15:12 GeoffreyBooth

My adapter-static s3 website was working through the direct *.s3-website.amazonaws.com url, but not through cloudfront. Here is what I ended up doing.

In order to use the sveltekit build output without changing filenames, I used

trailingSlash: 'always'

and a cloudfront function on the distribution along the lines of

request.uri = uri.endsWith('/') 
            ? uri + 'index.html' 
            : uri + '/index.html'

sallaben avatar Dec 31 '23 19:12 sallaben