11ty / eleventy-plugin-webc

Adds support for WebC *.webc files to Eleventy
https://www.11ty.dev/docs/languages/webc/
119 stars 10 forks source link

Dynamic Permalinks Silently Ignored #87

Open stevenwoodson opened 1 year ago

stevenwoodson commented 1 year ago

(Originally posted in help on Discord @ https://discord.com/channels/741017160297611315/1129393478963568702)

Scenario

I'm running 11ty 2.0.1 and WebC 0.11.1.

I'm attempting to create a paginated WebC page template based on data (like https://www.11ty.dev/docs/pages-from-data/). The paginated data is being generated in a custom JS file in my _data folder such that I have access to data called components.components. My front matter in the WebC page template is:

---
pagination:
  data: components.components
  size: 1
  alias: component
permalink: "'design-system/components/full/' + component.slug + '/'"
layout: layouts/design-system.webc
---

Problem

Currently, that page template is completely ignored, no errors but also no pages generated. When I remove permalink I start to get pages but they're in the dist folder as dist/design-system/components-full-pages/1/index.html, dist/design-system/components-full-pages/2/index.html, etc.

So I know the data is working and the pages are getting generated, there's just something wrong with the permalink syntax. I've also tried many other formats I found in the Github issues comments from https://github.com/11ty/eleventy-plugin-webc/issues/42#issuecomment-1374152043 and https://github.com/11ty/eleventy-plugin-webc/issues/36#issuecomment-1355594799 to no avail. Including:

permalink: '`/design-system/components/full/${component.slug}/`'

and even

permalink: 'design-system/components/<template webc:nokeep @html="slugify(component.slug)"></template>/'

Everything I've tried either silently fails or gives me the duplicate output conflict error like this one

Output conflict: multiple input files are writing to `dist/design-system/components/full/index.html`. Use distinct `permalink` values to resolve this conflict.

Debugging

After stepping away for a bit and coming back to try again, I tried to dig in a little deeper by debugging (both with IDE debugger and the 11ty debugger mode on). I converted my template from WebC to Nunjucks so I could compare the same thing with two different template languages. Results below

Nunjucks successful template debug output

  Eleventy:Template Rendering permalink for './src/design-system/components-full-pages.njk': design-system/components/full/{{ component.slug }}/ becomes 'design-system/components/full/card/' +15ms
  Eleventy:Template Rendering permalink for './src/design-system/components-full-pages.njk': design-system/components/full/{{ component.slug }}/ becomes 'design-system/components/full/card-headline-first/' +1ms
  Eleventy:Template Rendering permalink for './src/design-system/components-full-pages.njk': design-system/components/full/{{ component.slug }}/ becomes 'design-system/components/full/card-photo-last/' +1ms

WebC failed template debug output

  Eleventy:Template Rendering permalink for './src/design-system/components-full-pages.webc': 'design-system/components/full/' + component.slug + '/' becomes { returns: 'design-system/components/full/card/', context: { slug: [Function (anonymous)], slugify: [Function (anonymous)], url: [Function (anonymous)], log: [Function (anonymous)], ... } } +3s
  Eleventy:Template Rendering permalink for './src/design-system/components-full-pages.webc': 'design-system/components/full/' + component.slug + '/' becomes { returns: 'design-system/components/full/card-headline-first/', context: { slug: [Function (anonymous)], slugify: [Function (anonymous)], url: [Function (anonymous)], log: [Function (anonymous)], serverlessUrl: [Function (anonymous)], getCollectionItemIndex: [Function (anonymous)], getCollectionItem: [Function (anonymous)], getPreviousCollectionItem: [Function (anonymous)], getNextCollectionItem: [Function (anonymous)], prettify: [Function (anonymous)], brace: [Function (anonymous)], md: [Function (anonymous)], console: [Function (anonymous)], renderTemplate: [Function (anonymous)], renderFile: [Function (anonymous)], css: [Function (anonymous)], js: [Function (anonymous)], html: [Function (anonymous)], getBundle: [Function (anonymous)], getBundleFileUrl: [Function (anonymous)], webcGetCss: [Function (anonymous)], webcGetJs: [Function (anonymous)], highlight: [Function (anonymous)], pagination: { items: [Array], page: [Object], pageNumber: 1 }, page: {}, component: { title: 'Card - Headline First', context: [Object], preview: 'wrapper', path: 'card', name: 'card', variant: true, originalTitle: 'Headline First', slug: 'card-headline-first' }, site: { name: 'WCC Base Eleventy', url: 'https://stevenwoodson.com', authorName: 'Steve Woodson', authorEmail: 'me@stevenwoodson.com' }, designTokens: { colors: [Object], fonts: [Object], sizes: [Object], spacing: [Object], viewports: [Object] }, components: { components: [Array], menu: [Array] }, global: { random: [Function: random] }, helpers: { getLinkActiveState: [Function: getLinkActiveState], getSiblingContent: [Function: getSiblingContent], filterCollectionByKeys: [Function: filterCollectionByKeys] }, eleventy: { version: '2.0.1', generator: 'Eleventy v2.0.1', env: [Object] }, pkg: { name: 'wcc-base-eleventy', version: '1.0.0', description: 'A base project of best practices for use on Walnut Creek Creative projects', main: 'index.js', scripts: [Object], keywords: [], author: 'Steve Woodson', license: 'MIT', devDependencies: [Object] }, permalink: "'design-system/components/full/' + component.slug + '/'", title: 'Components', renderData: { title: '{{ component.title }}' }, collections: {} } } +1s
  Eleventy:Template Rendering permalink for './src/design-system/components-full-pages.webc': 'design-system/components/full/' + component.slug + '/' becomes { returns: 'design-system/components/full/card-photo-last/', context: { slug: [Function (anonymous)], slugify: [Function (anonymous)], url: [Function (anonymous)], log: [Function (anonymous)], serverlessUrl: [Function (anonymous)], getCollectionItemIndex: [Function (anonymous)], getCollectionItem: [Function (anonymous)], getPreviousCollectionItem: [Function (anonymous)], getNextCollectionItem: [Function (anonymous)], prettify: [Function (anonymous)], brace: [Function (anonymous)], md: [Function (anonymous)], console: [Function (anonymous)], renderTemplate: [Function (anonymous)], renderFile: [Function (anonymous)], css: [Function (anonymous)], js: [Function (anonymous)], html: [Function (anonymous)], getBundle: [Function (anonymous)], getBundleFileUrl: [Function (anonymous)], webcGetCss: [Function (anonymous)], webcGetJs: [Function (anonymous)], highlight: [Function (anonymous)], pagination: { items: [Array], page: [Object], pageNumber: 2 }, page: {}, component: { title: 'Card - Photo Last', context: [Object], preview: 'wrapper', path: 'card', name: 'card', variant: true, originalTitle: 'Photo Last', slug: 'card-photo-last' }, site: { name: 'WCC Base Eleventy', url: 'https://stevenwoodson.com', authorName: 'Steve Woodson', authorEmail: 'me@stevenwoodson.com' }, designTokens: { colors: [Object], fonts: [Object], sizes: [Object], spacing: [Object], viewports: [Object] }, components: { components: [Array], menu: [Array] }, global: { random: [Function: random] }, helpers: { getLinkActiveState: [Function: getLinkActiveState], getSiblingContent: [Function: getSiblingContent], filterCollectionByKeys: [Function: filterCollectionByKeys] }, eleventy: { version: '2.0.1', generator: 'Eleventy v2.0.1', env: [Object] }, pkg: { name: 'wcc-base-eleventy', version: '1.0.0', description: 'A base project of best practices for use on Walnut Creek Creative projects', main: 'index.js', scripts: [Object], keywords: [], author: 'Steve Woodson', license: 'MIT', devDependencies: [Object] }, permalink: "'design-system/components/full/' + component.slug + '/'", title: 'Components', renderData: { title: '{{ component.title }}' }, collections: {} } } +418ms

Theory

I don't have enough context of all the internals but my theory is that evaluatedString linked below should be returning just the permalink string but is returning an object with the string under returns as well as another context object. https://github.com/11ty/eleventy-plugin-webc/blob/47bfcd1f000502fb47a3b481472a964e89eaedb0/src/eleventyWebcTemplate.js#L87

So the parser doesn't know what to do with it and moves on silently with a final debug output of

  Eleventy:Template Template not written false from './src/design-system/components-full-pages.webc' (via serverless permalink). +104ms
  Eleventy:Template Template not written false from './src/design-system/components-full-pages.webc' (via serverless permalink). +0ms
  Eleventy:Template Template not written false from './src/design-system/components-full-pages.webc' (via serverless permalink). +0ms
johannesrave commented 9 months ago

@stevenwoodson i think you are right - i dug around more and after some superficial testing and logging i used pnpm patch to only return the nested prop evaluatedString.returns there and now all of my files are being written. nothing broke as far as i can tell. since the whole package is apparently being pulled into @11ty/eleventy (and also i don't know about further repercussions) i didn't create a PR.

derron1 commented 9 months ago

I discovered a workaround that has worked for me, which involves utilizing JavaScript-rendered front matter. hope this helps.

---js 
{
  pagination: { 
    data: "pages", 
    size: 1,
    alias: "static_page" 
  }, 
  permalink: function(args) { 
    const { static_page } = args; 
    return `/${static_page.slug.current}/`; 
  } 
} 
---
zachleat commented 6 months ago

When you use a string we do attempt to parse this as a dynamic script: https://github.com/11ty/eleventy-plugin-webc/blob/b5d39d55b330990280a9fea34dbf4fcd3d3d25a6/src/eleventyWebcTemplate.js#L75-L92

It’s may be more straightforward though to use ---js as @derron1 suggested (or ---node in 3.0 canaries) to use a permalink function instead.

e.g. this WebC template:

---node
function permalink(data) {
}
---