How can I read and write files when hosting from a Github repo?

Hello everyone,
I am trying to host an Eleventy and Netlify CMS app. In my .eleventy.js file I have some fs reading and writing files with the help of the eleventy-plugin-injector plugin that helps you inject arbitrary code into the site build process.

eleventyConfig.addPlugin(pluginInjector, {
    watch: './_site/categories/**.md',
    inject: (eleventyInstance, options, file) => {
      const categoryName = path.basename(file).split('.')[0];
      const filetext = fs.readFileSync(file, 'utf-8');      
      if (!filetext.includes('pagination')) {
        let paginationText = `\npagination:\n`
          + ` data: collections.${categoryName}\n`
          + ` size: 5\n`
          + `permalink: /category/{{name}}/{{pagination.pageNumber+1}}/index.html\n`;                 
        let content = `\n{% include "paginateproducts.njk" %}`;
        let newtext = filetext.replace('\n', paginationText);
        newtext += content;
        try {
          fs.writeFileSync(`./_site/categories/${categoryName}.md`, newtext);
        } catch(e) {
          console.log('error writing', e.message)
        }        
      }
    }
  });

This piece of code reads the category files in categories/**.md and it adds pagination objects to them in their front matter. If you are wondering why I am doing that instead of doing them manually is because the Admin of website can add a new category at anytime so I have to add the pagination object based on the name of the new category (for more info about the problem I had you can read my issue here: https://github.com/11ty/eleventy/issues/1338).

I figured out this workaround and the eleventy app works fine in my local server, but when I pushed it to github I was already afraid it won’t work as the files comes from the repo etc and not from some folder, and indeed it didn’t work. The build shell gives me this error:

$ npx eleventy
12:58:16 PM: > ENOENT: no such file or directory, open './_site/categories/**.md'
12:58:16 PM: `Error` was thrown:
12:58:16 PM:     Error: ENOENT: no such file or directory, open './_site/categories/**.md'
12:58:16 PM:         at Object.openSync (fs.js:458:3)
12:58:16 PM:         at Object.readFileSync (fs.js:360:35)
12:58:16 PM:         at Object.inject (/opt/build/repo/.eleventy.js:13:27)
12:58:16 PM:         at Eleventy.write (/opt/build/repo/node_modules/@infinity-interactive/eleventy-plugin-injector/index.js:121:23)
12:58:16 PM:         at Eleventy.wrapper (/opt/build/repo/node_modules/@infinity-interactive/eleventy-plugin-injector/index.js:28:41)
12:58:16 PM:         at /opt/build/repo/node_modules/@11ty/eleventy/cmd.js:77:14

Should I just give up on this solution, or there is a workaround for this? I hope my problem is understandable and thank you in advance.

1 Like

Hi @dinodev!

Have you looked at Eleventy’s computed data feature yet? It’s new in 1.11.0 and if I’ve understood your goal, it should accomplish what you want without injecting custom plugin code that relies on fs

With computed data, you can use categories/categories.11tydata.js to test each file’s front matter for pagination, then conditionally add pagination data for the Eleventy compiler without reading/writing any files.

Thank you for your reply but pagination object in the computed data as it’s noted at the top of the eleventyComputed docs: https://www.11ty.dev/docs/data-computed/

It is important to note that Computed Data is computed right before templates are rendered. Therefore Computed Data cannot be used to modify the special data properties used to configure templates (e.g. layout , pagination , tags etc.). These restrictions may be relaxed over time.

I’m not an eleventy or CMS expert, but I’d like to revisit the error message you saw:

 > ENOENT: no such file or directory, open './_site/categories/**.md'
12:58:16 PM: `Error` was thrown:
12:58:16 PM:     Error: ENOENT: no such file or directory, open './_site/categories/**.md'

This seems to me that “something” (node) is trying to open a file literally called **.md rather than actually finding all your md files. Perhaps there is some trouble in parsing the filenames as you think you are doing, and node is trying instead to open a file called star-star dot md?

1 Like

In my localhost node parses it normally, but not on Netlify.

Anyway I solved it by doing the searching of files for him by passing an array of path links instead of one generic link:

let listFiles = []
fs.readdirSync(path.resolve(__dirname, './_site/categories/')).forEach(file => {
  if (file.split('.').pop() !== 'md')
    return;
  listFiles.push(path.resolve(__dirname, './_site/categories/', file))
});

eleventyConfig.addPlugin(pluginInjector, {
  watch: listFiles,
  inject: (eleventyInstance, options, file) => {
    ...

Usual reason for local<->netlify differences is you use different node/npm versions. Have you set ours correctly to match your local, as explained here?