Skip to content

Add Slot Feature Support for posthtml-include #101

@mosaleh-dev

Description

@mosaleh-dev

Hi!

First off, thanks for your work on this project — it's been really helpful!

While working on my current project, I wanted to use posthtml-include to include HTML partials with a slot-like feature. After digging into the source code, I noticed that the plugin uses posthtml-expressions, which supports the {{{ }}} triple-brace syntax to embed raw HTML.

This gave me an idea: I wanted to pass HTML directly inside the <include> tag and inject it into the partial using a {{{ defaultSlot }}} placeholder. To accomplish this, I created the following patch using patch-package:

diff --git a/node_modules/@vituum/vite-plugin-posthtml/node_modules/posthtml-include/lib/index.js b/node_modules/@vituum/vite-plugin-posthtml/node_modules/posthtml-include/lib/index.js
index ad5320a..3e18659 100644
--- a/node_modules/@vituum/vite-plugin-posthtml/node_modules/posthtml-include/lib/index.js
+++ b/node_modules/@vituum/vite-plugin-posthtml/node_modules/posthtml-include/lib/index.js
@@ -30,13 +30,17 @@ module.exports = (options = {}) => {
         source = fs.readFileSync(src, options.encoding);
 
         try {
-          const localsRaw = node.attrs.locals || (node.content ? node.content.join().replace(/\n/g, '') : false);
+          const localsRaw = node.attrs.locals || "{}";
           const localsJson = JSON.parse(localsRaw);
+          localsJson["defaultSlot"] = generateHtmlString(node.content)
+
           posthtmlExpressionsOptions = {
             ...posthtmlExpressionsOptions,
             locals: posthtmlExpressionsOptions.locals ? Object.assign(posthtmlExpressionsOptions.locals, localsJson) : localsJson
           };
-        } catch {}
+        } catch(e) {
+          console.log(e)
+        }
 
         if (posthtmlExpressionsOptions.locals) {
           const result = posthtml()
@@ -68,3 +72,24 @@ module.exports = (options = {}) => {
     return tree;
   };
 };
+
+function generateHtmlString(element) {
+  if (typeof element === 'string') {
+    return element;
+  }
+
+  if (Array.isArray(element)) {
+    return element.map(generateHtmlString).join('');
+  }
+
+  if (typeof element === 'object' && element !== null) {
+    const { tag, attrs, content } = element;
+    const attributes = attrs ? Object.entries(attrs).map(([key, value]) => `${key}="${value}"`).join(' ') : '';
+    const openTag = `<${tag}${attributes ? ' ' + attributes : ''}>`;
+    const closeTag = `</${tag}>`;
+    const innerContent = content ? generateHtmlString(content) : '';
+    return `${openTag}${innerContent}${closeTag}`;
+  }
+
+  return '';
+}

Proposal

I'm happy to contribute to this project in one of two ways:

  1. Documentation-only — I can update the documentation to show how to use the {{{ defaultSlot }}} syntax in posthtml-include via posthtml-expressions.

  2. Feature Addition — I'd love to help implement a more official "slot" feature, similar to how it's done in Vue/React/Web Components. If this route sounds good, I’d appreciate a bit of guidance on the preferred API shape, and I’ll take care of the implementation.

Let me know which direction you'd prefer. Either way, I’d love to help make this more usable for others. 😊

Thanks again!

This issue body was [partially generated by patch-package](ds300/patch-package#296).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions