eleventy icon indicating copy to clipboard operation
eleventy copied to clipboard

How to create a page from multiple .md, .html, .js files

Open justinfagnani opened this issue 5 years ago • 4 comments

I'm trying to create a set of example pages where each page might consist of a .md, .html, and .js file. The .html and .js files are the example content and need to be both included into the content of the page and included into the source of the page. These are runnable examples.

docs/
└─examples/
  ├─ example-1.md
  ├─ example-1.html
  ├─ example-1.js
  └─ example-2...

And this should generate one .html file per example:

_site/
└─examples/
  ├─ example-1.html
  └─ example-2.html

So far, I can include the .html and .js files with a template system include, and I can prevent the entire directory from being output with a examples.json file that sets permalink to false, but I can't figure out how to set permalink to false only for the .html files and use the default for the .md file.

I might be able to do something here with collections and pagination, where I set permalink to false for the entire directory, but create a examples.11ty.js file that then outputs one file per .md file, but that feels a bit convoluted.

Any recommendations here?

justinfagnani avatar Jan 28 '20 19:01 justinfagnani

What about if you have:

docs/
└─examples/
  ├─ examples.json # sets directory-wide `permalink: false`, like you said.
  |
  ├─ example-1.md # overrides template w/ `permalink: "examples/example-1.html"` or ...
  ├─ example-1.html
  ├─ example-1.js
  |
  ├─ example-2.md # same `permalink: "examples/example-2.html"` override as above.
  ├─ example-2.html
  ├─ example-2.js
  |
  └─ example-3...

Was trying to figure out if it'd be easier to move all the *.html and *.js files into your _includes/ directory and manage them there, but then I guess that might split up the files and maybe you didn't want that.

pdehaan avatar Jan 28 '20 20:01 pdehaan

My first thought is to change the extensions. But I'm not clear what your full requirements are. I haven't tested it, but something like:

docs/
└─examples/
  ├─ example-1.md
  ├─ example-1.html.ins
  ├─ example-1.js.ins
  └─ example-2...

So, "ins" as in "insert". Theoretically they won't be handled as template or data files, and the outputs should be based on the *.md files. I'm assuming the md uses a layout file.

Again, this is all just a wild guess.

rphunt avatar Jan 28 '20 22:01 rphunt

I posted my hacky example at https://github.com/pdehaan/11ty-includes-test

Not sure if I needed the permalink: false in the ./docs/examples/examples.11tydata.js file, or if I could just get away with setting the templateFormats: ["md", "njk"] in the root .eleventy.js config file, but it seems to build like expected. Depending on the number of examples and includes you have, it might be easier to add one more level of nesting so it's ./docs/examples/example-1/ and then that directory includes as many .html, .js, .css, .png files as you need for a specific example (versus potentially one directory with dozens/hundreds of files).

pdehaan avatar Jan 29 '20 00:01 pdehaan

Based on your description, here is a solution I tested. It adds an extra step of adding an extension to the files being inserted, so that they are not rendered as templates, and setting permalinks to false is not needed. It also uses a Nunjucks layout file.

Create a new Eleventy project.

Create the .eleventy.js file :

module.exports = {
    templateFormats: ["njk", "md", "html", "js"]
};

Create two MD files :

test01.md

---
title: test01
layout: layout.njk
htmlinsert: test01.html.ins
jsinsert: test01.js.ins
---
# Test 01

Test for insertion 01

test02.md

---
title: test02
layout: layout.njk
htmlinsert: test02.html.ins
jsinsert: test02.js.ins
---
# Test 02

Test for insertion 02

Create the HTML files (for insertion) :

test01.html.ins

<button>test button 01</button>
<p>
test 01
</p>

test02.html.ins

<button>test button 02</button>
<p>
test 02
</p>

Create the JS files (for insertion) :

test01.js.ins

console.log('test 01');

test02.js.ins

console.log('test 02');

Create the layout file that is called for in the MD files' front matter :

_includes/layout.njk

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>{{ title }}</title>
</head>
<body>

  {{ content | safe }}

  <h3>
    {{ htmlinsert }}
  </h3>

  {% include htmlinsert -%}

  <h3>
    {{ jsinsert }}
  </h3>

  <pre><code>
    {% include jsinsert -%}
  </code></pre>

</body>
</html>

What is going on here is the MD files supply the unique paths for the HTML and JS files to be inserted into each resulting page. Nunjucks can use those values in the include statements.

And since Eleventy is only looking for NJK, MD, HTML, and JS files as templates, it is ignoring the .INS files. The advantage of using .INS is that it doesn't interfere with using HTML or JS files elsewhere, and it makes it clear what the roles of those file are.

The resulting folder structure should be :

_site/
    ├test01
    │   └index.html
    └test02
        └index.html

And _site/test01/index.html should contain :

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>test01</title>
</head>
<body>

  <h1>Test 01</h1>
<p>Test for insertion 01</p>


  <h3>
    test01.html.ins
  </h3>

  <button>test button 01</button>
<p>
test 01
</p>
<h3>
    test01.js.ins
  </h3>

  <pre><code>
    console.log('test 01');
</code></pre>

</body>
</html>

Note of course that for the HTML samples in the index.html page to display as code, you'll probably need to add a filter that converts it to character entities. But that's a separate question.

rphunt avatar Jan 29 '20 14:01 rphunt

Some overlap with enhancement requests at https://github.com/11ty/eleventy/discussions/4116 and https://github.com/11ty/eleventy/discussions/3980

I’d acknowledge that we don’t have a super smooth option currently, but those are the best ideas to improve things moving forward!

zachleat avatar Nov 21 '25 17:11 zachleat