reactjsjsonbuildyamlbuild-script

Run a script to parse YAML when React app compiles


My Problem

I have a ReactJS website that parses a JSON file (stored in the src folder) to render content. I recently attempted to use a YAML file instead because of YAML's richer abilities (supporting Markdown, for example).

Because React must load and parse YAML asynchronously, this change complicated my codebase and degraded my app's performance (e.g., content flickers).

My Plan

Instead of rewriting my components and slowing down my app, I've written a script to convert my YAML file into a JSON file. This way, I can have the best of both worlds: the richer abilities of YAML and the simple implementation of JSON.

My Question

What's the best way to make React run this script when the app is built? My web host rebuilds my app every time I push a change, so hopefully this can be activated via package.json or similar.


Solution

  • My Solution

    I solved the problem using js-yaml. I even found a way to make it work with Fast Refresh.

    ./src/[PATH]/yaml-convert.js:

    const yaml = require('js-yaml');
    const fs = require('fs');
    
    const args = process.argv.slice(2);
    
    switch (args[0]) {
      case 'watch':
        watch();
        break;
      default:
        convert();
    }
    
    function watch() {
      fs.watch('./src/[PATH]/myData.yaml', function (event, filename) {
        require('child_process').fork('./src/[PATH]/yaml-convert.js');
      });
    }
    
    function convert() {
      try {
        const json = yaml.load(fs.readFileSync('./src/[PATH]/myData.yaml', 'utf8'));
        fs.writeFileSync('./src/[PATH]/myData.json', JSON.stringify(json));
      } catch (e) {
        console.log(e);
      }
    }
    

    package.json: (note the -- watch argument and the single & in the dev command)

    ...
    "scripts": {
      "start": "serve -s build",
      "dev": "npm run yaml-convert -- watch & react-scripts start",
      "build": "npm run yaml-convert && react-scripts build",
      "test": "react-scripts test",
      "eject": "react-scripts eject",
      "yaml-convert": "node ./src/[PATH]/yaml-convert.js"
    }
    ...
    

    And to keep git diff tidy...

    .gitattributes:

    /src/[PATH]/myData.json -diff