Search code examples
javascriptnode.jsapinodesgatsby

Gatsby Node API onPostBuild in gatsby-node.js unable to execute


module.exports = {
  parseXML: function(file_path, callback) {
    callback("test 1")
    readFile(file_path.toString(), "utf-8", function(err, data) {
      if (err) callback(err);

      parseString(data, function(err, result) {
        if (err) callback(err);
        callback("test 2")

        var json = result;
        delete json.sitemapindex.sitemap[1].lastmod;

        var builder = new xml2js.Builder();
        var xml = builder.buildObject(json);

        write2File(file_path.toString(), xml, function(err, data) {
          if (err) callback(err);
          callback("test 3")
          callback("successfully written our update xml to ",file_path.toString());
        });
      });
    });
    callback("test 4")
  }
}

This is a function to parse XML to JSON and modify the JSON and write back to XML. I called this function in gatsby-node.js in onPostBuild like this

exports.onPostBuild = async () => {sitemap_mod.parseXML("filename")}

However, in the gatsby build, it only printed out test:1 and test:4, which means it failed to execute anything in the readFile function. I suppose this is because the onPostBuild is an async function and I need to add some await state in my code. I applied this function in other node API such as onPostBootstrap and onCreateDevServer and they were both working properly, able to execute readFile and write2File function. So I think there's something wrong about my usage of onPostBuild. Thanks for your help!


Solution

  • Yes, you should indeed make sure to wait for the function to finish.

    You need to wait for the three asynchronous calls you have inside parseXML. I usually use promisify to turn them into async functions:

    const { promisify } = require("util");
    const asyncParseString = promisify(parseString);
    const asyncReadFile = promisify(readFile);
    const asyncWrite2File = promisify(write2File);
    
    function transformJsonToXml(json) {
      ...
    } 
    
    async function parseXML(file_path) {
      const data = await asyncReadFile(file_path.toString(), "utf-8");
      const json = await asyncParseString(data);
    
      await asyncWrite2File(file_path.toString(), transformJsonToXml(json));
    }
    

    Your onPostBuild then needs to wait for parseXML to finish. So either put an await before the parseXML call or just use

    exports.onPostBuild = () => sitemap_mod.parseXML("filename")