eleventy icon indicating copy to clipboard operation
eleventy copied to clipboard

11ty errors with "link.slice is not a function"

Open rmschindler opened this issue 1 year ago • 7 comments

Operating system

macOS Sonoma 14.5

Eleventy

3.0.0

Describe the bug

having just upgraded to 3.0.0, my npx @11ty/eleventy --serve --port=8081 command produces the error:

[11ty] Problem writing Eleventy templates:
[11ty] link.slice is not a function (via TypeError)
[11ty]
[11ty] Original error stack trace: TypeError: link.slice is not a function
[11ty]     at TemplatePermalink._addDefaultLinkFilename (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplatePermalink.js:68:23)
[11ty]     at TemplatePermalink.toOutputPath (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplatePermalink.js:77:24)
[11ty]     at TemplatePermalink.toHref (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplatePermalink.js:120:30)
[11ty]     at Template.getOutputHref (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Template.js:310:15)
[11ty]     at async ComputedData._setupDataEntry (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Data/ComputedData.js:95:15)
[11ty]     at async ComputedData.processRemainingData (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Data/ComputedData.js:116:3)
[11ty]     at async ComputedData.setupData (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Data/ComputedData.js:106:3)
[11ty]     at async Template.addComputedData (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Template.js:563:4)
[11ty]     at async Template.getTemplates (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Template.js:733:4)
[11ty]     at async TemplateMap.initDependencyMap (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplateMap.js:376:18)
[11ty]     at async TemplateMap.cache (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplateMap.js:425:3)
[11ty]     at async TemplateWriter._createTemplateMap (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplateWriter.js:356:3)
[11ty]     at async TemplateWriter.generateTemplates (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplateWriter.js:386:3)
[11ty]     at async TemplateWriter.write (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/TemplateWriter.js:434:21)
[11ty]     at async Eleventy.executeBuild (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Eleventy.js:1345:19)
[11ty]     at async Eleventy.watch (file:///Users/rmschindler/Repos/notebook/node_modules/@11ty/eleventy/src/Eleventy.js:1155:3)
[11ty] Wrote 0 files in 1.24 seconds (v3.0.0)

Reproduction steps

reproduction: I don’t know how to reproduce this

Expected behavior

expected behaviour: well, no error

Reproduction URL

No response

Screenshots

No response

rmschindler avatar Oct 04 '24 13:10 rmschindler

I tried the different versions of 11ty, and found that with 3.0.0-alpha.12, it still worked; with 3.0.0-alpha.13 it stops working . (to be clear ‘worked’ means that the error isn’t produced)

rmschindler avatar Oct 04 '24 14:10 rmschindler

Happens for me too (fedora 40).

Seems to be related to JSX, as for me it only happens when I have eleventyConfig.addTemplateFormats("11ty.jsx,11ty.tsx"); in my config. Removing that line fixes it, but obviously isn't ideal.

tryoxiss avatar Oct 08 '24 04:10 tryoxiss

this could be an important clue, @tryoxiss, as I also add a template format in my config:

eleventyConfig.addTemplateFormats("adoc");

rmschindler avatar Oct 08 '24 23:10 rmschindler

Definitely a bad error messaging issue. This is almost certainly due to a permalink value. Can you provide more information about the permalink value that might be influencing this? Or access to the code?

zachleat avatar Oct 16 '24 16:10 zachleat

Definitely a bad error messaging issue. This is almost certainly due to a permalink value. Can you provide more information about the permalink value that might be influencing this? Or access to the code?

That would make sense, I do a few jank things with permalinks for backwards compatability. The most likely one is this:

// `_source/en/en.11tydata.js` (My input dir is `_source`)
export default {
	dir: "ltr",
	locale: "en-CA",
	tags: "en",

	// layout: "base.njk",

	// this is super complex and a bit spaghetti // (lol reading this after simplifying the code a lot makes this silly)
	// basically:
	//
	// 1. Remove /en/
	// 2. 11ty will complain when pagination is involved, since
	//	  it tries to output many pages to the same file location.
	//	  because we don't account for that
	//	  (its all just /posts/index/ for example)
	// 3. To make 11ty shut up we check if its paginated, and if
	//	  so add the page number to the URL
	// 4. but now /posts/ doesn't work, and I want it to. So now
	//	  we remove /0/ if it exists.
	//
	// Possible TODO: Move this to another file so we can use this for other things?
	permalink: function({ page, pagination }) {
		// am I EVER going to localize any of this??? Good to have it *i guess* but still.
		let newUrl = `${
			page.filePathStem
				// Make 'en' the default by excluding that segment
				.replace("/en/", "/")
				// If `index` shows anywhere, remove it.
				// Example:
				//   /design/code/index
				//   to
				//   /design/code/
				//
				// I believe this gets both ones with and without trailing
				// slashes properly
				.replace("/index", "")
		}/`;
		// fileSlug? ionstead of filePathStem?

		// Pagination handler moved to posts/index.webc

		// console.log(`[cel] newurl for ${page.filePathStem} is ${newUrl}`)

		return newUrl;
	}
}

I also set a permalink in JS frontmatter in _source/en/posts/index.webc. Its largely simillar, but I believe it has a bit more find-replace. (dang I should really clean up this code)

---javascript
{
	dir: "ltr",
	locale: "en-CA",
	tags: "en",

	testdata: [
		"item 1",
		"item 2",
		"item 3",
	],

	pagination: {
		data: 'testdata', // 'collections.post',
		size: 2,
		reverse: true,
		generatePageOnEmptyData: true
	},

	// this is super complex and a bit spaghetti
	// basically:
	//
	// 1. Remove /en/
	// 2. 11ty will complain when pagination is involved, since
	//	  it tries to output many pages to the same file location.
	//	  because we don't account for that
	//	  (its all just /posts/index/ for example)
	// 3. To make 11ty shut up we check if its paginated, and if
	//	  so add the page number to the URL
	// 4. but now /posts/ doesn't work, and I want it to. So now
	//	  we remove /0/ if it exists.
	//
	// Possible TODO: Move this to another file so we can use this for other things?
	permalink: function({ page, pagination }) {

		//let pageNumberString = if (pagination.pageNumber >= 0)

		//if (pagination.pageNumber == 0) { return false }
		//if (pagination.pageNumber >= 0) { return `/posts/` }

		//return `/posts/${pagination.pageNumber}/`

		let newUrl = `${page.filePathStem.replace("/en/", "/")}/`;
		
		if (pagination)
		{
			newUrl = `${
				page.filePathStem
				.replace("/en/", "/")
				.replace("index", pagination.pageNumber)
				.replace("/0/", "/")
				.replace("/1/", "/")
			}/index.html`
		}

		//console.log(`[cel] newurl for ${page.filePathStem} is ${newUrl}`)

		//console.log(`[cel] Implying default language for ${page.filePathStem}, its new url is ${newUrl}`)
		return newUrl;
	},
  eleventyExcludeFromCollections: true,
}
---

I hope this helps, let me know if you need anything else!

tryoxiss avatar Oct 16 '24 18:10 tryoxiss

Hmm—I don’t see errors when trying to reproduce using a function permalink (with or without a pagination template)—@rmschindler can you provide yours?

zachleat avatar Oct 16 '24 19:10 zachleat

I get the same error when trying to upgrade from v2 to v3. The root cause appears to be the permalink function in a folder data file , coupled with having JavaScript as a template format (via eleventyConfig.addTemplateFormats()).

I have a bunch of code demos on my website that are like codepens. This is the folder structure.

folders

I shorten the url of these pages using a hash function in demos.11tydata.js. For example, I want what would be https://www.roboleary.net/demos/title-sequences/north-by-northwest/ to be https://www.roboleary.net/demos/SqeWP-RX/. I have a check to prevent JavaScript files being processed in this case.

//  demos.11tydata.js

const path = require("path");
const fs = require("fs-extra");
const utilities = require("../config/utilities");

module.exports = {
  layout: "standalone.njk",
  stylesheet: "styles.css",
  permalink: (data) => {
    let parentFolder = path.normalize(path.dirname(data.page.inputPath));
    let id = utilities.generateId(parentFolder);
    let url = `demos/${id}/`;

    if (data.page.outputFileExtension !== "html") {
      // dont write other files
      url = false;
    }

    return url;
  },
 // yada yada
};

// eleventy.config.js
module.exports = function (config) 
  config.addTemplateFormats("js");

  //yada yada
};

When I get a chance I can see if I can create a minimum viable case for this...

robole avatar Oct 16 '24 20:10 robole

similar to the above message, i experience this same error on 3.0 when i both:

notes

it seems to be passing the function returned from the addGlobalData("permalink", ...) call into _addDefaultLinkFilename, even though the latter expects a string. specifically, it fails as the engine tries to process the first .scss file.

commenting out either the permalink addGlobalData call or the sass addTemplateFormats call allows the build to complete, though it doesn't compile the scss files.

workaround

i was able to workaround this issue by replacing the permalink entry in the template data for the scss extension:

config.addExtension("scss", {
  outputFileExtension: "css",
  // override the glabal "permalink" data function to output the expeceted css file path instead.
  async getData(inputPath) {
    const permalink = path.parse(inputPath)

    return {
      permalink: path.format({
        ...permalink,
        dir: "",
        base: permalink.base.replace("scss", this.outputFileExtension),
      }),
    }
  },

tycobbb avatar Oct 26 '24 18:10 tycobbb

Hi, similar issue on my side when i use

module.exports = {
	permalink: function ({ title }) {
		return `/notes/${this.slugify(title)}/`;
	},
};

in a 11tydata.js file (11ty 3.0.0 upgrade)

Hope it helps to find the source of the issue

laurent-d avatar Oct 30 '24 20:10 laurent-d

Running into this too.

Basically, I have an NJK file with this: permalink: "{{ post | getPostPermalink }}"

Filter code:

eleventyConfig.addNunjucksFilter("getPostPermalink", function(post)
{
    let permalink = post.link.slice(post.status === "publish" ? 38 : 41);
    return permalink.endsWith("/") ? permalink : permalink + "/";
});

I add a console.log right before the slice to get the value of link. It says: function link() { [native code] }

On v2.0.1 it correctly outputs the permalink string value - nothing like the above.

Unfortunately I had to downgrade back to v2.0.1 since this is a total blocker. Let me know if I can help narrow it down.

EatonZ avatar Nov 16 '24 07:11 EatonZ

When I get a chance I can see if I can create a minimum viable case for this...

I was not not able to create a minimal test case for this. When I reduced the size of the codebase to the problematic area, the problem went away. It is a deeper issue.

robole avatar Nov 17 '24 00:11 robole

Hello everyone,

I'm also having the same issue in my personal site project. I found out that this issue is happening when I add a JavaScript plugin to bundle JS assets with the esbuild package.

I created this repo with a minimal setup to reproduce the issue. Removing this specific line, the issue goes away.

I hope this helps to investigate the problem with permalink

tobiasbu avatar Dec 01 '24 23:12 tobiasbu

Hmm—I don’t see errors when trying to reproduce using a function permalink (with or without a pagination template)—@rmschindler can you provide yours?

my use of permalink is as follows:

// index.11tydata.js

// for matching a string such as "2024/12/25"
const date_regex = /(?<y>\d{4})\/(?<m>\d{2})\/(?<d>\d{2})$/;

function getYear(s) {
  if (s) {
    const match = s.match(date_regex);
    if (match) {
      return match.groups.y;
    }
  }
}

function getMonth(s) {
  if (s) {
    const match = s.match(date_regex);
    if (match) {
      return match.groups.m;
    }
  }
}

function getDay(s) {
  if (s) {
    const match = s.match(date_regex);
    if (match) {
      return match.groups.d;
    }
  }
}

function getId(s) {
  if (s) {
    const match = s.match(date_regex);
    if (match) {
      return match.groups.y + match.groups.m + match.groups.d;
    }
  }
}

module.exports = {
  layout: "entry.html",
  eleventyComputed: {
    year: (data) => getYear(data.page.filePathStem),
    month: (data) => getMonth(data.page.filePathStem),
    day: (data) => getDay(data.page.filePathStem),
    id: (data) => getId(data.page.filePathStem) // TODO: account for more than 1 note a day
  },
  permalink: function (data) {
    const stem = data.page.filePathStem;
    const y = getYear(stem);
    const m = getMonth(stem);
    const d = getDay(stem);
    return `/v1/${y}/${m}/${d}/`;
  }
}

rmschindler avatar Dec 08 '24 14:12 rmschindler

Hello everyone,

I'm also having the same issue in my personal site project. I found out that this issue is happening when I add a JavaScript plugin to bundle JS assets with the esbuild package.

I created this repo with a minimal setup to reproduce the issue. Removing this specific line, the issue goes away.

I hope this helps to investigate the problem with permalink

I also have an addPlugin:

eleventyConfig.addPlugin(eleventyAsciidoc);

and for me also, when I remove this line, the error goes away

rmschindler avatar Dec 08 '24 14:12 rmschindler

I see the issue now—thank you for the test case!

There was a bug with how we were handling a function permalink value from the data cascade on a Custom template engine in the default change from #2780.

Fix will be shipping with 3.0.1-alpha.1—thank you!

zachleat avatar Dec 09 '24 23:12 zachleat

@zachleat I'm still seeing this on v3.0.1-alpha.1:

[11ty] Problem writing Eleventy templates:
[11ty] 1. Error generating template page(s) for ./micro/1736368532101.md. (via EleventyMapPagesError)
[11ty] 2. link.slice is not a function (via TypeError)
[11ty] 
[11ty] Original error stack trace: TypeError: link.slice is not a function
[11ty]     at TemplatePermalink._addDefaultLinkFilename (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/TemplatePermalink.js:67:23)
[11ty]     at TemplatePermalink.toOutputPath (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/TemplatePermalink.js:76:24)
[11ty]     at TemplatePermalink.toPath (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/TemplatePermalink.js:139:18)
[11ty]     at Template.getOutputLocations (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/Template.js:293:16)
[11ty]     at async Template.addComputedData (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/Template.js:587:25)
[11ty]     at async Template.getTemplates (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/Template.js:739:4)
[11ty]     at async TemplateMap.initDependencyMap (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/TemplateMap.js:378:19)
[11ty]     at async TemplateMap.cache (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/TemplateMap.js:433:3)
[11ty]     at async TemplateWriter._createTemplateMap (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/TemplateWriter.js:358:3)
[11ty]     at async TemplateWriter.generateTemplates (file:///Users/caleb/.npm/_npx/4cacc1f1bcae12fd/node_modules/@11ty/eleventy/src/TemplateWriter.js:389:3)
[11ty] Wrote 0 files in 0.06 seconds (v3.0.1-alpha.1)

Using this 11tydata.js file:

export default {
  permalink: function (data) {
    console.log(data);
    // Check to see if `data.permalink` is a thing, and if so, return the raw value.
    if (Object.prototype.hasOwnProperty.call(data, "permalink")) {
      return data.permalink;
    }
    return `${data.page.filePathStem.replace('/micro/', '/')}.${data.page.outputFileExtension}`;
  },
};
❯ node --version
v23.6.0                                                                        
❯ npx @11ty/[email protected] --version
3.0.1-alpha.1

calebhearth avatar Jan 08 '25 23:01 calebhearth

@calebhearth your data file is basically doing this:

export default {
  permalink: function (data) {
    return data.permalink; // returning itself (function)
  },
};

I will add some additional error reporting for the above if you attempt to return a function in permalink so at least the error message is better!

But a small subtle thing: if you want to use an upstream data.permalink value from the data cascade, you need to use eleventyComputed:

export default {
  eleventyComputed: {
    permalink: function (data) {
      return data.permalink;
    },
  }
};

zachleat avatar Mar 12 '25 14:03 zachleat