lumeland / lume

🔥 Static site generator for Deno 🦕
https://lume.land
MIT License
1.83k stars 83 forks source link

Finer control over URLs #392

Closed thegedge closed 1 year ago

thegedge commented 1 year ago

Enter your suggestions in details:

New to Deno/Lume, coming from Node/Next.js, and loving Lume so far! It's the closest to what I've been looking for in an SSG, so thanks so much for all the effort you all have put into building :)

Given that I'm coming from Next.js, I want to avoid changing all of my URLs, but struggling to get Lume to do exactly what I want via exporting url from _data.ts. Here's what my folder structure looks like:g

The output files, respectively:

and the URLs, respectively:

So the few points I'll surface:

  1. Dates are not stripped from the URL.
  2. Dates and titles are separated by a hyphen, not an underscore.
  3. URLs don't need a trailing slash.
    • This one really only impacts dev mode, because production will know how to serve /subdir/file.html as /subdir/file. I've been using netlify dev + lume build --watch for now.
  4. /any/sub/directory/index.tsx becomes /any/sub/directory
  5. I want something like page.outputPath to be dir/file.html but page.data.url to be dir/file

Any thoughts on making some/all of these more configurable? It was hard to get right, but I was able to get it working by doing two things. First, this in my root _data.ts

export const url = (page: Page) => {
  if (page.src.asset) {
    return `${page.src.path}${page.src.ext ?? ""}`;
  }

  // Prefer "/blog/2020-01-01-slug" over "/blog/slug/"
  if (page.data.date) {
    const match = DATE_SLUG_REGEX.exec(page.src.path);
    if (match) {
      return `${match[1]}/${match[2]}-${match[3]}.html`;
    }
  }

  return `${page.src.path}/`;
};

I think it would be helpful if Lume would use the default URL if the url function returned undefined / null / some placeholder value.

Second, this is in my _config.ts:

site.use(
  modifyUrls({
    fn: (url) => url.replace(/.html$/, ""),
  })
)

I was super happy that all the things were there to get this working, but it was trickier than I anticipated. If Lume would like to stick with the current defaults, a migration guide for Next.js would be really great!

Let me know what ideas we'd be open to. I'm more than happy to send in some PRs to implement those.

oscarotero commented 1 year ago

Hi, @thegedge

Nice comments! To clarify:

Dates are not stripped from the URL.

As I can see, your files are named like yyyy-mm-dd-slug so that's not detected as a date, because Lume uses a underscore to separate dates and slugs (yyyy-mm-dd_slug). See code here.

In theory, the output files should keep the dates because they are not interpreted as dates so Lume doesn't remove it, and I assume that's what you want, right?

I think it would be helpful if Lume would use the default URL if the url function returned undefined / null / some placeholder value.

This is how it works already. See the code . But it only detect undefined, not null.

The use of modifyUrls plugin to remove the .html extensions is the right way to do that. Previously there was the no-html-extension option but it was very hacky and was removed in Lume 1.13.0. The Lume local server should support this kind of URLs (Here's the code) out of the box, so you don't need netlify dev for that. Let me know if this is not true.


PR are very welcome, but I want to understand better the changes that you want to implement.

thegedge commented 1 year ago

This is how it works already. See the code . But it only detect undefined, not null.

Oh, nice! It didn't look to be working for me, but that's likely my own mistake.

The Lume local server should support this kind of URLs (Here's the code) out of the box, so you don't need netlify dev for that. Let me know if this is not true.

I think I may have added the modifyUrl plugins after switching to netlify dev, and neglected to try out lume serve again, but you're totally right that this is working.

In theory, the output files should keep the dates because they are not interpreted as dates so Lume doesn't remove it, and I assume that's what you want, right?

It is, but let me clarify: My files are named yyyy-mm-dd_slug but I want my URL to be yyyy-mm-dd-slug. Ideally, I could name my files yyyy-mm-dd-slug and have the date parsed properly + remain in the URL. Here's what I'd propose:

  1. Support parsing the date from files named something like yyyy-mm-dd-slug.md. I suspect this won't be easy to generalize, so a lume option to provide a date parsing regex.
  2. Add a lume option to keep the date in the slug.

What do you think?

Either way, once I get my site completely migrated, I'd be happy to put together a "Next.js to lume" migration document on https://github.com/lumeland/lume.land :)

oscarotero commented 1 year ago

Understood.

An option to customize how the dates are parsed and how they affect to the final url would be nice, but it's a bit tricky right now because the code to parse the dates cannot access to the site configuration object.

I think your function to customize the url is the best way for now. Probably you can simplify it:

import { format } from "lume/deps/date.ts";

export const url = (page: Page) => {
  // Check if the original filename includes the date:
  if (!page.src.path.match(/^\d{4}-\d{2}-\d{2}-\d{2}_/)) {
    return;
  }

  const date = format(page.data.date, "yyyy-MM-dd");
  const slug = page.src.slug;

  return `./${date}-${slug}.html`;
};

In this example, the output is a relative url, so if the page is in a subdirectory, like /blog/, the path is automatically prepended. It returns the url including the .html extension. The modifyUrls plugin can be used to remove the extension in the links in the HTML code, but internally, the urls of the pages must include this extension to work properly. It's used to identify this page as HTML, so it can be detected by other plugins that work with HTML pages (for example to minify, apply some DOM modifications, etc).

Either way, once I get my site completely migrated, I'd be happy to put together a "Next.js to lume" migration document on https://github.com/lumeland/lume.land :)

That would be fantastic! Thank you!!

thegedge commented 1 year ago

That's significantly simpler than what I had. Much appreciated!

I'm happy to consider that the way forward in this case, so feel free to close unless you think providing an option is useful, just not high priority.

oscarotero commented 1 year ago

Nice! I close this, because the url function in _data.ts is the most flexible solution.