How to import a file into a react app that uses create react app as raw text?
Asked Answered
S

2

15

Goals

  1. I want to display some code for reference from the project itself.
  2. I want the display of the code to be updated with the implementation.
  3. I don't want to eject from create-react-app

This react project, created with create-react-app and typescript, is going to be used to display some custom components for re-use in other projects. My goal is to have the component be used right next to the code that is using it.

How can I load the file if I don't have access to the webpack config, and I can't use fs.readFile?

Swastika answered 9/4, 2020 at 19:41 Comment(0)
S
20

I managed to get this working after a bit of looking around. There are two major pieces that had to be in place to make it work.

Use the appropriate loader

In this case I wanted to use the raw-loader, so I installed it as a dev dependency. yarn add -D raw-loader.

In order to actually import the file I needed to then override the webpack configuration like this:

// eslint-disable-next-line import/no-webpack-loader-syntax
import toolbarItems from '!!raw-loader!../ToolbarItems';

This loads the entire file into the variable toolbarItems. By using the !! before the loader I prevent any other webpack loaders from processing it in this specific case. This might work on its own in a plain javascript project, but in typescript...

You must provide a module to typescript

I was running into the typescript error:

Failed to compile.

/Users/cory/Code/something/custom-theme/src/pages/NavigationDemo.tsx
TypeScript error in /Users/cory/Code/something/custom-theme/src/pages/NavigationDemo.tsx(9,26):
Cannot find module '!!raw-loader!../ToolbarItems'.  TS2307

     7 |
     8 | // eslint-disable-next-line import/no-webpack-loader-syntax
  >  9 | import toolbarItems from '!!raw-loader!../ToolbarItems';
       |                          ^
    10 |
    11 | const useStyles = makeStyles({
    12 |   root: {

Simply declaring a module for the loader in a file called ToolbarItems.ts.d.ts solved the issue for me:

declare module '!!raw-loader!*' {
  const content: string;
  export default content;
}

source

Swastika answered 9/4, 2020 at 19:41 Comment(6)
+1 yes, I do this too. But how to do you test the resulting react app with Jest? How can I teach Jest to understand the !!raw-loader! directive?Datnow
Sorry, I don't have an answer for you there. But be sure to report back if you figure it out!Swastika
@Swastika I believe you are missing an ! in the typing file. !!raw-loaderCondon
Thanks for the catch @Pooya, updated.Swastika
Doesn't work for me with CRA 5.0.1 it changes the content of the file, but the imported string is still a url from which you have to fetch the file content.Invitation
@SashaDavydenko I've abandoned CRA for vite, but if you come up with a solution that works, I'm happy to put a header at the top of the current answer and upvote you :)Swastika
I
6

Since you use create-react-app for your project, the best solution at the moment would be a babel plugin called Raw.Macro.

This plugin allows you to access content of your files without a need to create-react-app eject. Provides really elegant solution without any boilerplate code and declaring "d.ts" files as in previous answer.

Note: There is a small drawback that you have to re-start your webpack dev server when the file changes, because the content of a file is being embedded during the build process.

import raw from 'raw.macro';

function foo(){
    const jsonContent = raw('../utils/stops.json');
    console.log(jsonContent);
}
Idonah answered 16/9, 2021 at 12:38 Comment(1)
what about a solution for VITE?Emlin

© 2022 - 2024 — McMap. All rights reserved.