Having issues utilizing the fetch hook in a plugin


#1

I’m building an opentype font loader for the purpose rendering text within a canvas based game. My plugin works within the browser, however fails during builds. For server side rendering I had been just using @empty mapping, but doing so within a build envs mapping will result in the file being omitted.

The problem I’m running into is how to fetch as an array buffer. Generally this would be done using fs, as is what opentype.js does internally, but doing so doesn’t appear to be working, and the require fails. I did so using opentype’s internal node loader, which definitely works in an actually node env.

Being as it seems like in this scenario, neither XMLHttpRequest nor fs work, any ideas on other viable approaches? Is there a way to avoid this dilemma altogether?

I’d like to avoid loading it as a string and then converting the string to an array buffer.

var opentype = require('opentype.js'),
  loader = require("@loader");

exports.fetch = function( load ) {
  return new Promise(function( resolve, reject ) {
    var request = new XMLHttpRequest();
    request.open('get', load.address, true);
    request.responseType = 'arraybuffer';
    request.onload = function() {
      if (request.status !== 200) {
        reject('Font could not be loaded: ' + request.statusText);
      } else {
        resolve(request.response);
      }
    };

    request.send();
  });
};

var translate = loader.translate;

loader.translate = function( load ) {
  if (load.source instanceof ArrayBuffer) {
    load.metadata.deps = [];

    load.metadata.execute = function() {
      return opentype.parse(load.source);
    };
    load.metadata.format = 'otf';
  } else {
    return translate.apply(this, arguments);
  }
};

#2

Ended up using this approach. For the sake of knowledge sharing:

var opentype = require('opentype.js'),
  loader = require('@loader');

function fetchAsBuffer( address ) {
  return new Promise(function( resolve, reject ) {
    var request = new XMLHttpRequest();
    request.open('get', address, true);
    request.responseType = 'arraybuffer';

    request.onload = function() {
      resolve(request.response);
    };

    request.send();
  });
}

if (loader.isPlatform('window')) {
  exports.fetch = function( load ) {
    load.metadata.format = 'otf';

    return fetchAsBuffer(load.address);
  }

  var translate = loader.translate;

  loader.translate = function( load ) {
    if (load.metadata.format === 'otf') {
      load.metadata.deps = [];

      load.metadata.execute = function() {
        return opentype.parse(load.source);
      };

    } else {
      return translate.apply(this, arguments);
    }
  }
} else {
  exports.fetch = function( load ) {
    load.metadata.format = 'otf';
    load.metadata.build = false;
    return loader.fetch(load);
  };
  exports.build = false;
  exports.includeInBuild = true;
}

Rather than try to fetch on the server as an array buffer, which is seemingly a non-starter, I’m instead skipping the build in non-windowed environments. Being as this is used canvas animations anyway, no SSR isn’t an issue.

var translate = loader.translate;

loader.translate = function( load ) {
  if (load.metadata.format === 'otf') {
    load.metadata.deps = [];

    load.metadata.execute = function() {
      return opentype.parse(load.source);
    };

  } else {
    return translate.apply(this, arguments);
  }
}

Translate hook breaks if it encounters an ArrayBuffer instance, and simply using exports.translate would throw an uncaught exception as a result. Ergo, had to replace loader.translate.

function fetchAsBuffer( address ) {
  return new Promise(function( resolve, reject ) {
    var request = new XMLHttpRequest();
    request.open('get', address, true);
    request.responseType = 'arraybuffer';

    request.onload = function() {
      resolve(request.response);
    };

    request.send();
  });
}

This part was really painful. Neither isomorphic-fetch nor fs load in steal, regardless of env. Probably a bug.

Cordvoa also doesn’t set request.status as 200.