Search code examples
reactjswebpackmoduleembed

Import a file as a string (or source asset) in Gatsby / React


I want to import .ts, .tsx, .js, and .jsx files into a react component and render them within a PrismJS highlighting block. For example, let's say I have a TypeScript file with functionA in it that I want to highlight in my actual website:

functionA.ts:

export function functionA() {
    console.log("I am function A!");
}

I want to include this in a different component. The problem is, when I import it, I am obviously importing the webpack module version of it. My weak attempt at trying to get my function render in a react component looks like this:

MyComponent.tsx:

import * as React from "react"
import { functionA } from "./functionA"

export function MyComponent() {
    return (
        <>
            <h1>Here is your code block:</h1>
            <pre>
                <code>
                    {functionA.toString()}
                </code>
            </pre>
        </>
    )
}

and what will actually render on the page where the code block is will look something like this:

Here is your code block:

WEBPACK__IMPORT.functionA() {
    console.log("I am function A!")
}

I can't exactly remember what the .toString() function output looked like, but the point is it is NOT just the contents of the file how it appears in a code edit for example - it has been modulized by WebPack.

So, in a Gatsby project, how can i get these various code snippets to be imported directly as a string, purely as they are written, without WebPack enacting its import stuff on it? Is there a plugin or some way to tell Webpack to use the imported file as its asset/source module type? I know for MD or MDX files there is the gatsby-remark-embed-snippet, but I am building a component based HTML page and can't use MD or MDX files!

It's very late, and perhaps I just can't see the forest from the trees, I know there must be a way to do this...


Solution

  • You need to require the file using webpack's raw-loader, i.e:

    const functionA = require("!!raw-loader!./functionA");
    

    This works for create-react-app, as in the solution discussed here, and this works for Gatsby as well!

    After using require on such a file, the file contents can be rendered in the component as:

    <pre>{functionA.default.toString()}</pre>
    

    It's then up to you to add syntax highlighting using a tool like prism or similar.

    Note this solution will only work as long as Gatsby V3 continues to use WebPack v4, as raw-loader is deprecated in WebPack v5 and will be phased out for asset/source type modules.