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

Pagination links break when using eleventyComputed to write permalinks in *.11ty.js templates #1555

Closed
reubenlillie opened this issue Dec 16, 2020 · 17 comments
Labels
bug feature: 📦 pagination Related to Eleventy’s pagination feature

Comments

@reubenlillie
Copy link

reubenlillie commented Dec 16, 2020

Describe the bug
Using eleventyComputed to write permalinks in *.11ty.js templates, as described in #1076, does not produce the expected pagination links.

To Reproduce
Steps to reproduce the behavior:

  1. 📋 Clone the eleventy-dot-js-blog starter project to a soon-to-be-bug-ridden project directory and install node packages locally:
git clone git@gitlab.com:reubenlillie/eleventy-dot-js-blog.git buggy-eleventy-dot-js-blog
cd buggy-eleventy-dot-js-blog
npm install 
  1. Test that the local development environment is working. Specifically, 👀 note the following paginated output from ./content/pages/archive.md:
npx eleventy --serve
…
Writing _site/blog/index.html from ./content/pages/archive.md.
Writing _site/blog/page-1/index.html from ./content/pages/archive.md.
…

Also, notice how these same pagination navigation links appear in the markup when browsing 🌎 http://localhost:8080/blog/. The Markdown/Liquid–Nunjucks front matter permalinks work. 👌

  1. 📝 Rename ./content/pages/archive.md from Markdown to a JavaScript template and translate its content:
mv content/pages/archive.md content/pages/archive.11ty.js
vim content/pages/archive.11ty.js

NB: code updated on January 19, 2021 since the starter kit now supports ES modules

// JavaScript-ified ./content/pages/archive.11ty.js
/**
 * @file Defines the chained layout for the archive page
 * @see {@link https://www.11ty.dev/docs/layouts/#layout-chaining Layout chaining in 11ty}
 */

/**
 * Acts as front matter in JavaScript templates
 * @see {@link https://www.11ty.dev/docs/languages/javascript/#optional-data-method Optional `data` in JavaScript templates in 11ty}
 */
export var data = {
  title: '📔 A Blog for the Ages',
  navTitle: '📔 Blog',
  tags: 'nav',
  weight: 3,
  layout: 'layouts/archive',
  templateEngineOverride: '11ty.js',
  pagination: {
    data: 'collections.posts',
    size: 3,
    alias: 'posts',
    reverse: true,
  },
  eleventyComputed: {
    permalink: data => `${data.site[data.locale].postsArchive.url }/${data.pagination.pageNumber > 0
      ? `page-${data.pagination.pageNumber}/` 
      : ''}index.html`
  }
}

/**
 * The archive page content
 * @method
 * @name render()
 * @param {Object} data 11ty’s data object
 * @return {String} The rendered template
 */
export function render(data) {
  return `<!-- ${data.page.inputPath} -->
This is your blog landing page. 🛬`
}
  1. Run 🧪 npx eleventy --serve again. This time, notice how the output files in the command line interface remain unchanged 😃. But, … also notice how in the browser, the pagination navigation links now render as http://localhost:8080/{{page.fileSlug}}/ 🐛. The proper routes are output by the new JavaScript template, but the pagination navigation is different.

  2. 🤔 These strange pagination navigation links resemble the permalink rules in ./content/pages/pages.11tydata.js. So, it would seem like the logical next step is to update those to eleventyComputed syntax too 🤷‍♂️:

// Updated ./content/pages/pages.11tydata.js
/**
 * @file Contains data common to all pages, to reduce repetition
 */

/**
 * Directory data module for pages
 * @module content/pages
 * @see {@link https://www.11ty.dev/docs/data-template-dir/ Template and directory data files in 11ty}
 * @see {@link  https://www.11ty.dev/docs/permalinks/ Permalinks in 11ty}
 */
module.exports = {
  layout: 'layouts/page',
  // Note: The permalink value uses Nunjucks/Liquid syntax;
  // a future version of 11ty may allow for JavaScript template literals
  // permalink: '/{{page.fileSlug}}/index.html',
  // Comment out this line ⬆️; add this basically equivalent eleventyComputed object ⬇️
  eleventyComputed: {
    permalink: data => `/${data.page.fileSlug}/index.html`
  },
  tags: [
    'pages'
  ]
}
  1. Except, this time, if you run npx eleventy --serve, notice how the output has changed 🪲:
…
Writing _site/blog/index.html from ./content/pages/archive.11ty.js. 🤤
…
Writing _site/blog/page-1/1/index.html from ./content/pages/archive.11ty.js. 🤨
…

And, in the markup, the pagination navigation links are now http://localhost:8080/content/pages/archive/ and http://localhost:8080/content/pages/archive/1/ accordingly, which look more like real pages, but they don’t exist in the output 🐜. That is, both the output and the pagination navigation links are broken after basically exchanging 💱 Markdown/Liquid–Nunjucks for Eleventy-topped vanilla JavaScript.

Expected behavior
The output and pagination navigation links should match, and eleventyComputed should continue to be unquestionably awesome.

Environment:

  • OS and Version: Ubuntu 20.04.1 LTS
  • Eleventy Version: v0.11.1

Additional context

The pagination navigation is generated from ./_includes/shortcodes/pagination-nav.js. It’s a built-out version of what I prepared for the Eleventy docs. If you console.log(data.pagination) somewhere in the return statement for any of steps 3–6 above, you can verify the mutations to that object. But I’ve got no clue why the permalinks are behaving this way with pagination.

@reubenlillie
Copy link
Author

So, this is hardly a solution, but a “working” set of pagination navigation links can be created to match those built by Eleventy:

// Modified data object in content/pages/blog.11ty.js
export var data {
  eleventyComputed: {
    permalink: data => `${data.site[data.locale].postsArchive.url}/index.html`
  }
}

I happened upon this wrench by accident. I was testing to see what would happen if I removed the ternary operator for the page- counter. It appears the /1/ in _site/blog/1/index.html is automatically created by Eleventy somehow. And it doesn’t appear possible to modify that behavior as expected to page-# or anything else, at least not with eleventyComputed in JS templates. But appearances can be deceiving.

@Ryuno-Ki
Copy link
Contributor

@reubenlillie I guess, you're right.
I'd need to double check, but I think the URL is built in

links.push("/" + outputLink);

The referenced outputLink is some indirection to

eleventy/src/Template.js

Lines 118 to 158 in 26bf047

async _getLink(data) {
if (!data) {
data = await this.getData();
}
let permalink = data[this.config.keys.permalink];
if (permalink) {
// render variables inside permalink front matter, bypass markdown
let permalinkValue;
if (!this.config.dynamicPermalinks || data.dynamicPermalink === false) {
debugDev("Not using dynamicPermalinks, using %o", permalink);
permalinkValue = permalink;
} else {
permalinkValue = await super.render(permalink, data, true);
debug(
"Rendering permalink for %o: %s becomes %o",
this.inputPath,
permalink,
permalinkValue
);
debugDev("Permalink rendered with data: %o", data);
}
let perm = new TemplatePermalink(
permalinkValue,
this.extraOutputSubdirectory
);
return perm;
} else if (permalink === false) {
return new TemplatePermalinkNoWrite();
}
return TemplatePermalink.generate(
this.getTemplateSubfolder(),
this.baseFile,
this.extraOutputSubdirectory,
this.htmlIOException ? this.config.htmlOutputSuffix : "",
this.engine.defaultTemplateFileExtension
);
}

@reubenlillie
Copy link
Author

@Ryuno-Ki, well, can you imagine a way to override this behavior in JS templates? I'm stumped.

@Ryuno-Ki
Copy link
Contributor

Hm, I'd first better understand what's going on. But I can't find log messages in the initial post containing the Dev:Eleventy:Template prefix (DEBUG=Eleventy* environment variable will turn them on. Filter for those via grep or similar)

@johnpuddephatt
Copy link

I think I'm coming up against the same problem. From the following:

class Page {
  data() {
    return {
      pagination: {
        data: 'categories',
        size: 1,
        alias: 'category'
      },
      eleventyComputed: {
        permalink: data => `/api/${data.category.slug}.json`
      }
    };
  }
  render(props) {
    return...
  }
}

module.exports = Page;

I'm getting the following files outputted:

Writing dist/api/category-slug-one.json from ./src/category.11ty.js.
Writing dist/api/1/category-slug-two.json from ./src/category.11ty.js.
Writing dist/api/2/category-slug-number-three.json from ./src/category.11ty.js.
Writing dist/api/3/category-slug-fourth.json from ./src/category.11ty.js.

@Ryuno-Ki
Copy link
Contributor

Could you turn on DEBUG mode, @johnpuddephatt?

@johnpuddephatt
Copy link

Sure – full output here: https://pastebin.com/YNSn7qJs

@johnpuddephatt
Copy link

johnpuddephatt commented Jan 21, 2021

Line 144 looks 'correct' – i.e. what I'd expect...

Eleventy:Template Rendering permalink for './src/category.11ty.js': /api/categories/category-number-two.json becomes '/api/categories/category-number-two.json' +1ms

Line 202 however has an unexpected /1/:

Eleventy:Template dist/api/categories/1/category-number-two.json written.. +0ms

@reubenlillie
Copy link
Author

@Ryuno-Ki and @johnpuddephatt,

I'm away from my computer now. I'll try to share some DEBUG ouput soon.

@Ryuno-Ki
Copy link
Contributor

I'm pasting the lines relevant to the Debug Log for the Template:

Eleventy:Template getMappedDate: using file created time for './src/category.11ty.js' of 2021-01-21T20:58:17.762Z (from 1611262697762.2888) +0ms
Eleventy:Template getMappedDate: using file created time for './src/build.njk' of 2020-12-05T19:40:52.187Z (from 1607197252187.3174) +6ms
Eleventy:Template getMappedDate: using file created time for './src/api/sheets.njk' of 2021-01-21T01:44:20.743Z (from 1611193460743.8162) +5ms
Eleventy:Template getMappedDate: using file created time for './src/index.njk' of 2020-07-22T17:12:25.719Z (from 1595437945719.0203) +1ms
Eleventy:Template getMappedDate: using file created time for './src/pages/about.njk' of 2020-08-16T15:23:03.248Z (from 1597591383248.606) +1ms
Eleventy:Template getMappedDate: using file created time for './src/category.11ty.js' of 2021-01-21T20:58:17.762Z (from 1611262697762.2888) +3ms
Eleventy:Template getMappedDate: using file created time for './src/category.11ty.js' of 2021-01-21T20:58:17.762Z (from 1611262697762.2888) +1ms
Eleventy:Template getMappedDate: using file created time for './src/category.11ty.js' of 2021-01-21T20:58:17.762Z (from 1611262697762.2888) +1ms
Eleventy:Template First round of computed data for './src/category.11ty.js' +1ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': (((((11ty(((((permalink)))))11ty))))) becomes '(((((11ty(((((permalink)))))11ty)))))' +1ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': (((((11ty(((((permalink)))))11ty))))) becomes '(((((11ty(((((permalink)))))11ty)))))' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': /api/categories/category-one.json becomes '/api/categories/category-one.json' +1ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': /api/categories/category-one.json becomes '/api/categories/category-one.json' +0ms
Eleventy:Template First round of computed data for './src/category.11ty.js' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': (((((11ty(((((permalink)))))11ty))))) becomes '(((((11ty(((((permalink)))))11ty)))))' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': (((((11ty(((((permalink)))))11ty))))) becomes '(((((11ty(((((permalink)))))11ty)))))' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': /api/categories/category-number-two.json becomes '/api/categories/category-number-two.json' +1ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': /api/categories/category-number-two.json becomes '/api/categories/category-number-two.json' +0ms
Eleventy:Template First round of computed data for './src/category.11ty.js' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': (((((11ty(((((permalink)))))11ty))))) becomes '(((((11ty(((((permalink)))))11ty)))))' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': (((((11ty(((((permalink)))))11ty))))) becomes '(((((11ty(((((permalink)))))11ty)))))' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': /api/categories/a-third-category.json becomes '/api/categories/a-third-category.json' +0ms
Eleventy:Template Rendering permalink for './src/category.11ty.js': /api/categories/a-third-category.json becomes '/api/categories/a-third-category.json' +1ms
Eleventy:Template First round of computed data for './src/api/sheets.njk' +0ms
Eleventy:Template Rendering permalink for './src/api/sheets.njk': /api/one.json becomes '/api/one.json' +2ms
Eleventy:Template Rendering permalink for './src/api/sheets.njk': /api/one.json becomes '/api/one.json' +0ms
Eleventy:Template First round of computed data for './src/index.njk' +0ms
Eleventy:Template First round of computed data for './src/pages/about.njk' +1ms
Eleventy:Template Rendering permalink for './src/pages/about.njk': /{{ title | slug }}/index.html becomes '/about/index.html' +3ms
Eleventy:Template Rendering permalink for './src/pages/about.njk': /{{ title | slug }}/index.html becomes '/about/index.html' +1ms
Eleventy:Template First round of computed data for './src/build.njk' +1ms
Eleventy:Template Rendering permalink for './src/build.njk': build.txt becomes 'build.txt' +0ms
Eleventy:Template Rendering permalink for './src/build.njk': build.txt becomes 'build.txt' +1ms
Eleventy:Template Second round of computed data for './src/category.11ty.js' +0ms
Eleventy:Template Second round of computed data for './src/category.11ty.js' +0ms
Eleventy:Template Second round of computed data for './src/category.11ty.js' +0ms
Eleventy:Template Second round of computed data for './src/build.njk' +0ms
Eleventy:Template Second round of computed data for './src/api/sheets.njk' +0ms
Eleventy:Template Second round of computed data for './src/index.njk' +0ms
Eleventy:Template Second round of computed data for './src/pages/about.njk' +0ms
Eleventy:Template Writing 'dist/api/categories/category-one.json' from './src/category.11ty.js'. +19ms
Eleventy:Template Writing 'dist/build.txt' from './src/build.njk'. +0ms
Eleventy:Template Writing 'dist/api/one.json' from './src/api/sheets.njk'. +0ms
Eleventy:Template Writing 'dist/api/categories/1/category-number-two.json' from './src/category.11ty.js'. +0ms
Eleventy:Template Writing 'dist/api/categories/2/a-third-category.json' from './src/category.11ty.js'. +0ms
Eleventy:Template Writing 'dist/index.html' from './src/index.njk'. +5ms
Eleventy:Template Writing 'dist/about/index.html' from './src/pages/about.njk'. +0ms
Eleventy:Template dist/api/one.json written.. +3ms
Eleventy:Template dist/api/categories/1/category-number-two.json written.. +0ms
Eleventy:Template dist/build.txt written.. +0ms
Eleventy:Template dist/api/categories/2/a-third-category.json written.. +0ms
Eleventy:Template dist/api/categories/category-one.json written.. +0ms
Eleventy:Template dist/index.html written.. +0ms
Eleventy:Template dist/about/index.html written.. +0ms
Eleventy:Template dist/api/one.json written.. +3ms
Eleventy:Template dist/api/categories/1/category-number-two.json written.. +0ms
Eleventy:Template dist/build.txt written.. +0ms
Eleventy:Template dist/api/categories/2/a-third-category.json written.. +0ms
Eleventy:Template dist/api/categories/category-one.json written.. +0ms
Eleventy:Template dist/index.html written.. +0ms
Eleventy:Template dist/about/index.html written.. +0ms

@Ryuno-Ki
Copy link
Contributor

@reubenlillie I'm off to bed anywhen soon now.

I'm wondering right now, whether a „nested pagination” like #1597 (comment) might work here, too.

The thinking goes in the lines of having a pagination of size - and each of those broken into „sets of pagination”, so that there wouldn't be „a second page”.

@johnpuddephatt
Copy link

@Ryuno-Ki thanks for your help. #1597 looked promising but I don't think it's practical for a site that will be built in production... it looks to me like the first step outputs the 11ty.js files into the output folder, so they wouldn't be processed?

@johnpuddephatt
Copy link

In my case I've realised I don't need to use eleventyComputed at all... just setting:

      permalink: data => `/api/${data.category.slug}.json`

works fine. The question is why I was using it in the first place. I think it came from googling and reading a recent issue on GitHub...

@reubenlillie
Copy link
Author

reubenlillie commented Jan 22, 2021

@Ryuno-Ki, I created a separate branch core-#1555 if you’d like to check it out. I also pushed the full DEBUG output to ./debug.txt on that branch.

@Ryuno-Ki
Copy link
Contributor

@reubenlillie Thanks. I have the tab open but have some other things cooking for this week.
Will come back to you once I have capacity again.

@monochromer
Copy link
Contributor

monochromer commented Sep 3, 2021

I think, problem is here:

// TODO maybe also move this permalink additions up into the pagination class
if (pageNumber > 0 && !this.data[this.config.keys.permalink]) {
cloned.setExtraOutputSubdirectory(pageNumber);
}

I found a hack:

  permalink: '/',

  eleventyComputed: {
    permalink: function(data) {
      return `/${data.article.fileSlug}/`
    }
  }

Possible fix:

if (pageNumber > 0 && !(this.data[this.config.keys.permalink] || this.data.eleventyComputed[this.config.keys.permalink])) { 
 cloned.setExtraOutputSubdirectory(pageNumber);
}

@zachleat zachleat added bug feature: 📦 pagination Related to Eleventy’s pagination feature and removed needs-triage labels Jan 3, 2022
zachleat added a commit that referenced this issue Jan 3, 2022
@zachleat zachleat added this to the Eleventy 1.0.0 milestone Jan 3, 2022
@zachleat
Copy link
Member

zachleat commented Jan 3, 2022

#1956 merged, which should fix this. I added a test in 34ace73

@zachleat zachleat closed this as completed Jan 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug feature: 📦 pagination Related to Eleventy’s pagination feature
Projects
None yet
Development

No branches or pull requests

5 participants