11ty / eleventy

A simpler site generator. Transforms a directory of templates (of varying types) into HTML.

Home Page:https://www.11ty.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

this.eleventy is not available in JavaScript template functions

j-f1 opened this issue · comments

Operating system

macOS Ventura 13.2 (22D49)

Eleventy

2.0.0-beta.3

Describe the bug

When creating a shortcode in any other template language, this.eleventy is available as described in the docs. However, for a function added with addJavaScriptFunction, the this property does not have an eleventy property.

Reproduction steps

  1. Clone https://gist.github.com/j-f1/8127173e227be4af465c1ad9063f95d0
  2. Run npm install; npm run build

Expected behavior

_site/example/index.html contains the useful content of this.eleventy

Actual behavior: the property is missing

Reproduction URL

https://gist.github.com/j-f1/8127173e227be4af465c1ad9063f95d0

Screenshots

No response

Switched my code to process.env.ELEVENTY_ROOT and it works now. Feel free to close if you don’t want to change this behavior!

Hmm, gonna milestone this into 2.0.1 for now!

commented

I have a probably related issue where this isn’t available anymore when mapping through a collection.

this is still available in the root of the createLegacyRedirects method, but not anymore when slugify is called and wrapJavascriptFunction tries to assign page to this.

const paths = new Map([['text', 'notes']])

module.exports = class Redirects {
  data() {
    return {
      layout: null,
      permalink: '_redirects',
      eleventyExcludeFromCollections: true,
    }
  }

  createLegacyRedirects(collection, currentBase) {
    const { slugify } = this

    return collection
      .map(function (item) {
        const { permalink, external } = item.data

        if (external) return ''

        const cleanedPermalink = permalink.replace(`/${currentBase}/`, '')

        const redirects = []

        if (item.data.oldTitles) {
          item.data.oldTitles.forEach(function (title) {
            redirects.push(
              `/${currentBase}/${slugify(title)}/ ${permalink} 301`,
            )
          })
        }

        if (paths.get(currentBase)) {
          redirects.push(
            `/${paths.get(currentBase)}/${cleanedPermalink} ${permalink} 301`,
          )
        }

        return redirects.join('\n')
      })
      .join('\n')
  }

  render({ collections }) {
    const { blog, notes, aroundTheWeb } = collections

    return `
https://11ty.owlish.dev/* /:splat 301
https://reading.ovl.design/* https://www.ovl.design/around-the-web/ 301
/atw /around-the-web/ 301
${this.createLegacyRedirects(blog, 'text')}
${this.createLegacyRedirects(notes, 'notes')}
`.trim()
  }
}

That’s not related to Eleventy, it’s the way JS works. If you use arrow functions for map and forEach you’ll still be able to access the this value as expected.

commented

Sorry, but I know «the way JS works». Those were arrow functions and it worked in v1 and broke after updating to v2. I just forgot to change it back before commenting.

For context, debugger screenshots. this is undefined in those functions no matter how I write them, and consequentially it’s undefined in wrapJavaScriptFunction.

I tried to bind this in the class constructor with this.createLegacyRedirects = this.createLegacyRedirects.bind(this) but that didn’t solve the problem.

Screenshot 2023-02-10 at 17 03 58

Screenshot 2023-02-10 at 17 04 30

[11ty] Problem writing Eleventy templates: (more in DEBUG output)
[11ty] 1. Having trouble rendering 11ty.js template ./_src/_redirects.11ty.js (via TemplateContentRenderError)
[11ty] 2. Cannot set properties of undefined (setting 'page') (via TypeError)
[11ty] 
[11ty] Original error stack trace: TypeError: Cannot set properties of undefined (setting 'page')
[11ty]     at /Users/owl/dev/ovl/www.ovl.design/node_modules/@11ty/eleventy/src/Engines/JavaScript.js:113:19
[11ty]     at /Users/owl/dev/ovl/www.ovl.design/_src/_redirects.11ty.js:37:34
[11ty]     at Array.forEach (<anonymous>)
[11ty]     at /Users/owl/dev/ovl/www.ovl.design/_src/_redirects.11ty.js:35:31
[11ty]     at Array.map (<anonymous>)
[11ty]     at Redirects.createLegacyRedirects (/Users/owl/dev/ovl/www.ovl.design/_src/_redirects.11ty.js:25:8)
[11ty]     at Redirects.render (/Users/owl/dev/ovl/www.ovl.design/_src/_redirects.11ty.js:60:8)
[11ty]     at JavaScript.<anonymous> (/Users/owl/dev/ovl/www.ovl.design/node_modules/@11ty/eleventy/src/Engines/JavaScript.js:144:43)

Appreciate any useful tips.

I see — that looks like a different issue where wrapJavaScriptFunction expects the this value to be a valid object but calling the function as-is (e.g. by doing const { slugify } = this; slugify()) gives it a this of undefined.

commented

But I can't do this.slugify as this is already undefined in the nested functions. Maybe binding this to slugify outside of the loops can be a workaround, even if it doesn't explain why it breaks after updating.

disregard this comment I had some reading comprehension problems 🫠

Shipping witih 2.0.1—thank you!