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

Support export default objects for pages #708

Open
bartlomieju opened this issue Dec 21, 2024 · 5 comments
Open

Support export default objects for pages #708

bartlomieju opened this issue Dec 21, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@bartlomieju
Copy link

Enter your suggestions in details:

In deno-docs we have a good amount of pages both hand-written and generated ones.

I often find myself confused because the data for a page is scattered among numerous exports:

export const sectionTitle = "Lint rules";

export const layout = "lintRule.tsx";

export const toc = [];

export default function* (_data: Lume.Data, helpers: Lume.Helpers) {
  ...
}

I'd like to request (and I'm happy to work on it) to force using object notation for a page. So the above would become:

export default {
  sectionTitle: "Lint rules",
  layout: "lintRule.tsx",
  toc: [],
  component: function*(...) { // probably a wrong name
    ...
  }
}

It would be great if this could be forced in the lume() config like so:

import lume from "lume/mod.ts"

const site = lume(
  requirePageIsADefaultExport: true // open to bike shedding, effectively if it's specified throw an error if the default export is not an object containing all the configuration
  ...
);
@bartlomieju bartlomieju added the enhancement New feature or request label Dec 21, 2024
@oscarotero
Copy link
Member

Yeah, this behavior is supported (although not documented, I should do it).
Any page or _data file returning a plain object as the default value, is interpreted as the Data object.

So you can do:

export default {
  sectionTitle: "Lint rules",
  layout: "lintRule.tsx",
  toc: [],
  content: function*(...) {
  }
}

@bartlomieju
Copy link
Author

Thanks @oscarotero, that sounds good. Is there any chance we could force this behavior? I'm glad to migrate to this object notation, but I'd like to enforce it so I don't find myself in the same spot 6 months from now.

@oscarotero
Copy link
Member

What do you mean with "force this behavior"?
This is already supported. Just use a plain object as the default export and that's all.

Here you can see the code implementing it: https://github.com/lumeland/lume/blob/main/core/loaders/module.ts#L24

@bartlomieju
Copy link
Author

I mean that I'd like a project to only allow using the object notation - ie. this is allowed:

export default {
  sectionTitle: "Lint rules",
  layout: "lintRule.tsx",
  toc: [],
  content: function*(...) {
  }
}

but this results in an error:

export const  sectionTitle = "Lint rules";
export const layout = "lintRule.tsx";
export const toc = [];
export default function*(...) {
}

This corresponds to the:

const site = lume(
  requirePageIsADefaultExport: true // open to bike shedding, effectively if it's specified throw an error if the default export is not an object containing all the configuration
  ...
);

from the original comment (#708 (comment)).

@oscarotero
Copy link
Member

oscarotero commented Dec 21, 2024

Ah, got it.

I'm not sure this should be a Lume option, because it's responsibility of the loader, that doesn't have access to Lume config.

Maybe a solution is to create a custom loader for tsx files using the code of the original loader with some modification.

Solution 1

The easier solution: Create your module loader and use the import map to load it.

{
  "imports": {
    // ...
    "lume/core/loader/module.ts": "./_plugins/module-loader.ts"
  }
{

Solution 2

Because only the toData function need to be changed, the original loader could be modified to better reuse the existing code:

 // Modify the original loader code to export this function, that loads the content but without modifying it:
import { load } from "lume/core/loaders/module.ts";

// Now we create our custom data transformer:
function toData(mod: Record<string, unknown>): RawData {
  for (const [name, value] of Object.entries(mod)) {
    if (name !== "default") {
      throw new Error("Only the default export is allowed");
    }

    if (isPlainObject(value)) {
      return value as RawData;
    }
      
    return { content: value }
}

// And export the new loader:
export default async function load(path: string) {
  const data = await load(path);
  return toData(data);
}

Then, we can change the Lume plugin to load modules, adding a new option to customize the loader.

Finally, we can configure this new loader in the _config.ts file:

import lume from "lume/mod.ts";
import moduleLoader from "./_plugins/module_loader.ts";

const site = lume({
  // lume config
  },
  { modules: { loader: moduleLoader } },
);

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants