calvinmetcalf / shapefile-js

Convert a Shapefile to GeoJSON. Not many caveats.
http://calvinmetcalf.github.io/shapefile-js/
734 stars 229 forks source link

Error: nodebuffer is not supported by this platform #196

Closed XW-Liron closed 1 year ago

XW-Liron commented 1 year ago

Hey there. I'm attempting to convert a shape zip file into geo JSON using your tool. inside my React App. I get the file, and then get its array buffer but upon passing that data to shp(arrayBuffer) I get the titular error:

Uncaught (in promise) Error: nodebuffer is not supported by this platform
    at a.checkSupport (jszip.min.js:13:1)
    at new f (jszip.min.js:13:1)
    at n.internalStream (jszip.min.js:13:1)
    at n.async (jszip.min.js:13:1)
    at unzip.js:12:1
    at Array.map (<anonymous>)
    at module.exports (unzip.js:9:1)
    at async shp.parseZip (index.js:74:1)
    at async fileReader.onload (App.tsx:23:1)

My Code:

async viewFileData(files: any) {

    const file = files[0]

    let fileReader = new FileReader()

    fileReader.onload = async () => {
      let buffer = fileReader.result
      console.log(buffer)

      let arrayBuffer = new Uint8Array(buffer as ArrayBuffer)
      console.log(arrayBuffer)

      let geojson = await shp(arrayBuffer)
      console.log(geojson)
    }
    fileReader.readAsArrayBuffer(file);
  }

Looks like jzip is having some sort of incompatibility with node buffer from within the package. Really not too sure what to do in order to resolve this. Any help would be greatly appreciated.

P.S. I've already attempted to use react-app-rewired to address this. I installed node-polyfill-webpack-plugin and created a config-overrides.js file. here is what it looks like:

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');

module.exports = function override(config, env) {
   //do stuff with the webpack config...
   config.plugins.push(new NodePolyfillPlugin())
   return config
}
timndichu commented 1 year ago

Did you manage to solve this?

XW-Liron commented 1 year ago

@timndichu I worked on this a little while ago but I think I had to extensively modify my config-override.js in order to get this working. Here is what it looks like now:

const webpack = require("webpack");

module.exports = function override(config, env) {

    config.resolve.fallback = {
        buffer: require.resolve("buffer"),
    };

    config.plugins = (config.plugins || []).concat([
        new webpack.ProvidePlugin({
            process: "process/browser",
            Buffer: ["buffer", "Buffer"],
        }),
        new webpack.NormalModuleReplacementPlugin(/node:/, (resource) => {
            const mod = resource.request.replace(/^node:/, "");
            switch (mod) {
                case "buffer":
                    resource.request = "buffer";
                    break;
                default:
                    throw new Error(`Not found ${mod}`);
            }
        })
    ]);

    config.module.rules.unshift({
        test: /\.m?js$/,
        resolve: {
            fullySpecified: false, // disable the behavior
        },
    });

    return config;

}
XW-Liron commented 1 year ago

Forgot I logged this issue actually. Considering I found a way around it, I can probably close this now.

yeminxuan commented 4 months ago

I try to import shp.js file to solve this at the vite project:

//vite.config.ts
return defineConfig({
    optimizeDeps: {
        include: ['shpjs/dist/shp.js']
    },
})

install type from '@types/shpjs'

yarn add @types/shpjs

defined *..d.ts with shpjs module

declare module "shpjs/dist/shp.js" {
  import shp from "@types/shpjs";
  export default shp;
}
lymine1996 commented 2 months ago

This is the simplest solution that worked for me:

Install npm i node-polyfill-webpack-plugin react-app-rewired

then create in root project file with name config-overrides.js

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');

module.exports = function override(config, env) {
  config.plugins.push(new NodePolyfillPlugin());
  return config;
}

And update scripts in package.json

"scripts": {
  "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test",
  "eject": "react-scripts eject"
},