deno_std icon indicating copy to clipboard operation
deno_std copied to clipboard

proposal(http): add `cleanUrls` option to `serveDir`

Open lowlighter opened this issue 1 year ago • 5 comments

Is your feature request related to a problem? Please describe.

Nowadays it's pretty common to trim html page extensions from urls to make them nice and rememberable. (e.g. deno.com/blog, github.com/denoland/std, ..., some hosters such as Vercel also propose a similar feature)

The reason for why I'd like it to be natively in the std function is:

  • it avoids to implementing routing for simple use-cases (SSG websites)
    • serveDir is often also used as a fallback for route(), but it makes it kind of ugly to use it as-is if you want the clean urls behavior (see workaround below)
  • workaround exists but not practical
    • change your file structure (can cause interoperability issues with other modules) to use directories instead, rename all your file as index.html and use the index option
    • serveDir once, check if response status is 404, then rewrite the request (but kind of troublesome since Request are immutable, and also may already have been consumed) and retry with the extension. while it works, feels hacky and probably poorly memory efficient as you need to create multiple up to 4 instances of objects to serve a single file

The patch is pretty small to implement, as you only need to add a second resolution check if the option is enabled, so the footprint would be pretty low

I feel like the use-case is common enough, and makes it easier to deploy smaller-scales app / docs website / SSG without having to code anything, as you'd be able to directly deno run -A jsr:@std/http/file_server , which will be a nice QOL

Describe the solution you'd like

If this get agreed on, #6231 can be reopened, here's the reference:

-  const fsPath = join(target, normalizedPath);
+  // Resolve path
+  // If cleanUrls is enabled, automatically append ".html" if not present
+  // and it does not shadow another existing file or directory
+  let fsPath = join(target, normalizedPath);
+  if (
+    cleanUrls && !fsPath.endsWith(".html") &&
+    !(await Deno.stat(fsPath).then(() => true).catch(() => false))
+  ) {
+    fsPath += ".html";
+  }
  const fileInfo = await Deno.stat(fsPath);

Describe alternatives you've considered

One of the workaround listed above

lowlighter avatar Dec 04 '24 06:12 lowlighter

I'm interested in this to. I use @std/http/file-server in smallweb, and multiple users have been asking for this exact feature.

Example frameworks using cleanurls by default:

  • https://vitepress.dev/
  • https://quartz.jzhao.xyz/
  • https://observablehq.com/framework/

pomdtr avatar Dec 11 '24 16:12 pomdtr

I just published an SSG website on Deno Deploy and encountered this issue. I decided to create a simple file server for SSG that supports clean URLs by default. Please check it out at https://jsr.io/@kin/file-server.

jolleekin avatar May 22 '25 08:05 jolleekin

Some popular static file servers in npm seem supporting this feature by default (e.g. npm:http-server and npm:serve)

I'm in favor of this proposal.

kt3k avatar May 23 '25 07:05 kt3k

@kt3k Should I reopen my previous pr then ?

lowlighter avatar May 26 '25 20:05 lowlighter

Yes, please, but can you also create unstable_file_server.ts which only exports serveDir with cleanUrls option exposed? (We can modify existing serveDir like #6231, but let's not expose cleanUrls option from stable serveDir)

kt3k avatar May 27 '25 01:05 kt3k