Uncaught typeerror fs.readfilesync is not a function

Good day,
I get the above error in the browser console after I:

  1. meteor create mapboxgl2
  2. cd mapboxgl2
  3. meteor npm install --save gl meteor-node-stubs mapbox-gl
  4. Add the following line to client/main.js (outside any functions): import mapboxgl from ‘mapbox-gl’;

How can I get the npm package “mapbox-gl” to see the function fs.readfilesync?

1 Like

Hi. Is this function included in the new meteor 1.3 or do i need to install an additional package?
Any advice would be greatly appreciated.

meteor-node-stubs will give you node native library stubs on the client, but it won’t give you fs.readFileSync capabilities (which the mapbox-gl-js library expects when installed via npm). In this case you’re probably better off using the provided standalone js/css files (unless of course you want to expand the fs client stub …):

<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.16.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.16.0/mapbox-gl.css' rel='stylesheet' />

Thank you hwillson.
That worked easily.

Will the MDG eventually re-write these node functions or will they wrap them in future?

I don’t believe they currently have any plans to; MDG has left this fairly open intentionally. I’ll quote @benjamn (from issue 6550):

The official recommendation is that you npm install meteor-node-stubs in you application, which will give you all the usual native library stubs at once. This makes the stubs available to packages as well as your application code. Only the stubs you use will be bundled into your app.

As to why: client-side stubs are fake, partial implementations of the built-in modules found in Node, so you should have the option of installing a custom version that implements your desired behavior. Making that choice automatically for you might seem convenient… unless it isn’t what you need, which is why we let you install your own stubs (while providing meteor-node-stubs if you want to use that).

Hi @hwillson,

Can you recommend a way of using Mapbox gl together with Uber’s React wrapper for this library in a Meteor app? I still can’t figure out how to get this working.

Adding mapbox-gl to the app using and old good <script> does not work as this method does not provide a link between the library and the wrapper. Any example will be much appreciated.

@ggerber, have you got a solution to a problem? I’ve been trying to get through it for two days but no luck so far.

I also opened an issue in meteor/meteor repo before finding this thread.

Since you can’t use the <script> approach, maybe try some good old fashioned monkey patching. Try the following:

const fs = require('fs');
fs.readFileSync = () => {
  console.log('fs.readFileSync stub called');
};
const MapGL = require('react-map-gl');
...
<MapGL ... />
...

So instead of using import we’re using require to load the react-map-gl package, then storing a mocked out readFileSync function in the require cached fs object.

1 Like

Thanks for your suggestion @hwillson. No luck with this workaround unfortunately. I tried hacking fs in various places including the very first row of /client/index.js, but it did not work. Seems like meteor goes through the packages in its own order.

I’m drilling down the problem and have shared my further thoughts in the github issue: meteor/meteor#7384 (comment).

@kachkaev - Interesting; I created a new Meteor project that included only react-map-gl, replicated the fs.readfilesync error, then added the monkey-patch code I mentioned. The error was resolved. Make sure you’re using require and not import since playing with the require cache here directly. Can you share some code that isn’t working? Quick snippet from my side:

/client/main.js

import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import React from 'react';

const fs = require('fs');
fs.readFileSync = () => {
  console.log('fs.readFileSync stub called');
};
const MapGL = require('react-map-gl');

Meteor.startup(() => {
  const test = (
    <MapGL width={400} height={400} latitude={37.7577} longitude={-122.4376}
      zoom={8} onChangeViewport={(viewport) => {
        const {latitude, longitude, zoom} = viewport;
      }}
    />
  );
  render(test, document.getElementById('app'));
});

Here’s my console before the require cache tweak:

Here’s my console after (I don’t have an access token setup, but this shows you should now be able to get further):

Ah, now fs.readFileSync ‘works!’ I was using ES6 import instead of require thinking there is no difference. But there is this https://github.com/meteor/meteor/issues/6389#issuecomment-232124707 :smile: