lumeland / lume

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

Reflect base subdirectory when serving site through lume server #381

Closed bglw closed 1 year ago

bglw commented 1 year ago

Enter your suggestions in details:

With a configuration along the lines of:

const site = lume({
    location: new URL("https://example.com/documentation/"),
});

Then templating {{ "/" | url }} in a build will output /documentation/, and when serving will output /.

I would love a mode where Lume's dev server bakes this subdirectory in, thus serving the above site at http://localhost:3000/documentation/ and matching the subdirectory that would be used in production.

Happy to dig in and have a poke at this one myself, but some initial pointers would be appreciated if so 🙂

oscarotero commented 1 year ago

I think it's easy to implement, but why do you want this? I want to understand the use case for this behavior.

bglw commented 1 year ago

Mainly consistency. If I have the following template:

<a href="{{ '/' | url }}">Home</a>
<!-- later -->
<a href="{{ '/' }}">Home</a>

When serving in dev mode, both will render as / and it won't be obvious that the | url filter was missing in the second case. Only when building the final site will they render as /documentation/ and / and cause an issue. In general my desire is to setup dev mode as close to the final build as possible

oscarotero commented 1 year ago

The best way to handle subfolders is by using the base_path plugin so you don't have to remember to use the url filter everywhere. The url filter should be used only for cases in which the base_path plugin don't work.

The location setting is overrided here: https://github.com/lumeland/lume/blob/master/mod.ts#L84 if the --serve or -s flags are defined in the CLI command. It's possible override it in your _config.ts file. For example:

const site = lume({
    location: new URL("https://example.com/documentation/"),
});

if (Deno.args.includes("-s") || Deno.args.includes("--serve")) {
    site.options.location = new URL("http://localhost:3000/documentation/");
}

Probably an option inside server to configure the local server location would be useful. I imagine something like this:

const site = lume({
  location: new URL("https://example.com/documentation/"),
  server: {
    location: new URL("http://localhost.com:3000/documentation/"),
  }
});
bglw commented 1 year ago

The best way to handle subfolders is by using the base_path plugin

Good tip, I'll look at using that more. The url filter still holds true for loading assets though, which I would also like to be consistent between dev/prod.

It's possible override it in your _config.ts file

That does override the location for the purposes of the url filter and such, but the Lume server continues to serve requests without that location taken into account. (i.e. I would like my index.mdx file to be at http://localhost.com:3000/documentation/, but it is still at http://localhost.com:3000/)

oscarotero commented 1 year ago

Mmm, ok. I have to think about this. As a workaround, perhaps this can work:

site.preprocess("*", (page) => {
  page.data.url = `/documentation${page.data.url}`;
});

This prepend the /documentation path to all urls, so all pages would be saved inside this directory. Something similar could be done for files copied statically.

I have to think in the best way to implement this.

bglw commented 1 year ago

Thanks, this process works for me. Current full snippet:

if (Deno.args.includes("-s") || Deno.args.includes("--serve")) {
    site.options.location = new URL("http://localhost:3000/documentation/");

    site.preprocess("*", (page) => {
        page.data.url = `/documentation${page.data.url}`;
    });

    site.copy("images", "documentation/images");
} else {
    site.copy("images");
}

I might wind up removing the conditional there though and always running this, as another request I had queued up was an option to reflect the location in the output directory (i.e. output _site/documentation/* rather than _site/*. This makes it easier to mount a site on top of another (our subpath process)

site.preprocess is a nice solution to this, so I'm happy with that for now 🙂 The only quirk it introduces is that search.page("url^=/article/" + article) now has to be search.page("url^=/documentation/article" + article), but I can just keep that in mind (or use *=)

Thanks!

oscarotero commented 1 year ago

Yeah, I think Eleventy does what you are requesting, but to me it isn't very practical and portable.

bglw commented 1 year ago

Yeah definitely pros/cons, and I don't know what is a better default, I just like to have the option :) (and with preprocess, I effectively do 🎉)

oscarotero commented 1 year ago

After thinking of this a bit more, I decided to not implement this option, because it's a edge case and would complicate the internal code of Lume to take all cases into account (it would affect to some plugins, urls, etc).

For now, the preprocessor solution works fine. If there are more people requesting this feature, I can change my mind :)