Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
GeoffreyBooth opened this issue Jan 29, 2023 · 8 comments
Labels
p2-nice-to-have SvelteKit cannot be used by a small number of people, quality of life improvements, etc.
Milestone

Comments

@GeoffreyBooth
Copy link

GeoffreyBooth commented Jan 29, 2023

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 #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 #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
Copy link
Author

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.

@Rich-Harris Rich-Harris added this to the later milestone Feb 1, 2023
@patrick-zippenfenig
Copy link

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.

@agmcleod
Copy link

agmcleod commented Dec 6, 2023

@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

@eltigerchino
Copy link
Member

eltigerchino commented Dec 6, 2023

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 #8676

@eltigerchino eltigerchino added the p2-nice-to-have SvelteKit cannot be used by a small number of people, quality of life improvements, etc. label Dec 7, 2023
@rdeese
Copy link

rdeese commented Dec 15, 2023

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
Copy link

rdeese commented Dec 17, 2023

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.

@GeoffreyBooth
Copy link
Author

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.

@sallaben
Copy link

sallaben commented Dec 31, 2023

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'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p2-nice-to-have SvelteKit cannot be used by a small number of people, quality of life improvements, etc.
Projects
None yet
Development

No branches or pull requests

7 participants