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

feat: Support other template engines via plugins #9526

Open
MatheusRich opened this issue Jan 13, 2024 · 0 comments
Open

feat: Support other template engines via plugins #9526

MatheusRich opened this issue Jan 13, 2024 · 0 comments
Labels

Comments

@MatheusRich
Copy link

MatheusRich commented Jan 13, 2024

Summary

Add a new hook that works with layouts, so custom template engines can be implemented as pre/post processors to files.

Motivation

GitHub has recently made it quite easy to deploy to GitHub pages via actions. With that in place, it's easier than ever to have a custom plugin in our Jekyll apps.

Me and several others have always wanted to write ERB (or other engines) instead of Liquid, but that wasn't possible due to security risks. I'd love to have ERB support by default, but I think that could not fit the "useful to 90% of users" philosophy, so I'd love to implement that behavior as a plugin.

Currently, we could sort of do that with :pre_render hooks, so ERB could work as a pre-processor for the files. The problem is that there is no :pre_render hook for layouts, so it would not be possible to use ERB on these files (which arguably are where ERB would be more useful).

We could add support to that via 2 different approaches:

  1. We add a new :pre_render hook that works with layouts too, so it's possible to write
   Jekyll::Hooks.register [:pages, :posts, :layouts], :pre_render do |doc|
     # render erb here
   end
  1. We could do a similar thing, but with a :post_render hook (with the payload being passed as well). The engines would act as post-processors in this case.
  2. Add a new hook. maybe :after_liquid or something like that, which I think is guaranteed to be called on layouts as well.

I have a hacky, monkey-patched version of an ERB post-processor working in this gist, for reference.

Guide-level explanation

Depending on the approach, this would behave differently. The first approach might be the easiest to work with, and I think there's no compatibility issues with it.

In case we went with one, basically, before Layout#render_liquid is called (or in the top of the method) we'd trigger a :pre_render hook, passing the content and payload as an argument.
We'd also need to add a new registry for :layout in Jekyll::Hooks.

Reference-level explanation

I think this feature could be quite natural to implement since we have other hooks in place already. Supposing we went with the first approach, we'd need to override Layout#render_liquid like so:

module Jekyll
  class Layout
    def render_liquid(content, payload, info, path)
      Jekyll::Hooks.trigger :layout, :pre_render, self, content, payload
      super
    end
  end
end

and update the Jekyll::Hooks registry to include :layout as well.

module Jekyll
  module Hooks
    @registry = {
      # ...
      :layouts        => {
        :pre_render   => [],
      },
    }
  end
end

Drawbacks

If we introduce a new hook, there's no concern with compatibility. If we modify
an existing hook, we'll have to make sure that we don't break any existing
plugins.

I don't think there are security concerns because the behavior will live in
external plugins, so it's up to the user to decide if they want to use it or
not.

If we go with something like after_liquid, we get more tied with Liquid. In
theory, it would be possible to write a whole blog with ERB instead of Liquid,
but the hook is still called after_liquid, so it might be confusing.

Unresolved Questions

First, we have to decide how we want to implement this. I'm okay with any of the
suggestions, as well as any other approach that might be better. I might have
missed something, as I'm not very familiar with the codebase.

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

No branches or pull requests

1 participant