Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieve file contents during Gatsby build

Tags:

node.js

gatsby

I need to pull in the contents of a program source file for display in a page generated by Gatsby. I've got everything wired up to the point where I should be able to call

// my-fancy-template.tsx
import { readFileSync } from "fs";
// ...
const fileContents = readFileSync("./my/relative/file/path.cs");

However, on running either gatsby develop or gatsby build, I'm getting the following error

This dependency was not found: ⠀ * fs in ./src/templates/my-fancy-template.tsx ⠀ To install it, you can run: npm install --save fs

However, all the documentation would suggest that this module is native to Node unless it is being run on the browser. I'm not overly familiar with Node yet, but given that gatsby build also fails (this command does not even start a local server), I'd be a little surprised if this was the problem.

I even tried this from a new test site (gatsby new test) to the same effect.

like image 298
Sean Allred Avatar asked Mar 04 '23 09:03

Sean Allred


1 Answers

I found this in the sidebar and gave that a shot, but it appears it just declared that fs was available; it didn't actually provide fs.

It then struck me that while Gatsby creates the pages at build-time, it may not render those pages until they're needed. This may be a faulty assessment, but it ultimately led to the solution I needed:

  1. You'll need to add the file contents to a field on File (assuming you're using gatsby-source-filesystem) during exports.onCreateNode in gatsby-node.js. You can do this via the usual means:

    if (node.internal.type === `File`) {
        fs.readFile(node.absolutePath, undefined, (_err, buf) => {
            createNodeField({ node, name: `contents`, value: buf.toString()});
        });
    }
    
  2. You can then access this field in your query inside my-fancy-template.tsx:

    { 
      allFile {
        nodes {
          fields { content }
        }
      }
    }
    

From there, you're free to use fields.content inside each element of allFile.nodes. (This of course also applies to file query methods.)

Naturally, I'd be ecstatic if someone has a more elegant solution :-)

like image 174
Sean Allred Avatar answered Apr 30 '23 06:04

Sean Allred