hildjj / node-cbor

Encode and decode CBOR documents, with both easy mode, streaming mode, and SAX-style evented mode.
MIT License
357 stars 73 forks source link

cbor fails to import in expo/metro bundle (expo go IOS) #136

Closed 2bdkid closed 3 years ago

2bdkid commented 3 years ago

I'm developing a React Native application and I cannot get this library to work under expo/metro. Simply adding import cbor from 'cbor'; causes the bundle to error out with Unhandled JS Exception: Invalid regular expression: invalid group specifier name no stack.

To reproduce:

expo init dummy  # minimal template
cd dummy
npm install cbor
npm install node-inspect-extracted
npm install stream
# Add "import cbor from 'cbor';" to App.js
expo start
# open bundle with expo go
hildjj commented 3 years ago

I can't reproduce the error. What version of nodejs are you using?

hildjj commented 3 years ago

I made it happen in the iPhone simulator. I'm in no way versed in Expo, and am not sure how to debug this without a stack trace.

2bdkid commented 3 years ago

What version of nodejs are you using?

v14.16.0

It is a weird one. I'm not familiar with metro or how to debug its bundles. The error could be through the Expo go app itself, I'm going to try my code in an android simulator and if it works fine then I'll close this issue as it's probably a expo go bug.

hildjj commented 3 years ago

I've tracked this down by running the cbor-web examples in Safari, seeing the same error, doing a development build, etc. This is actually a node-inspect-extracted bug, from what I can tell. Filed https://github.com/hildjj/node-inspect-extracted/issues/7 and I'll work on it there.

2bdkid commented 3 years ago

Awesome, I was able to reproduce it under android too.

hildjj commented 3 years ago

I've worked around Safari not supporting BigInt64Array and BigUInt64Array, and I have the web bits all running in Safari. Just published 7.04. That may or may not fix your issue, but it should move us on to the next problem at least.

2bdkid commented 3 years ago

Still having same issue with 7.0.4

hildjj commented 3 years ago

Hm. I started a new project and don't see the error anymore. I see expo issues that are unrelated, but I can't help with those.

2bdkid commented 3 years ago

Ya it appears to work with a new project but my code still has the issue. hmmm.

hildjj commented 3 years ago

I think my current issue is that the stream package isn't what you want. You want stream-browserify, but you want it aliased to stream by the loader. I can't figure out how to get babel to do that, but maybe that will get you started?

hildjj commented 3 years ago

try adding stream-browserify and babel-plugin-module-resolver, then making your babel.config.js look like this:

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        require.resolve('babel-plugin-module-resolver'), {
          alias: {
            stream: 'stream-browserify'
          }
        }]
    ]
  };
};

I added some other modules from https://github.com/hildjj/node-cbor/blob/main/packages/cbor-web/package.json#L26 upgraded all of the other dependencies to their latest versions, and it looks like I'm more-or-less up and running. Make sure you clear your expo cache with expo start -c or by pressing shift-R while expo is running.

2bdkid commented 3 years ago

Looks like cbor loads now, but there's another error coming from cbor.decode

process.nextTick is not a function. (In 'process.nextTick(emitReadable_, stream)', 'process.nextTick' is undefined)
at node_modules/stream-browserify/node_modules/readable-stream/lib/_stream_readable.js:528:10 in emitReadable
at node_modules/stream-browserify/node_modules/readable-stream/lib/_stream_readable.js:302:20 in addChunk
at node_modules/stream-browserify/node_modules/readable-stream/lib/_stream_readable.js:279:15 in readableAddChunk
at http://192.168.1.17:19000/index.bundle?platform=ios&dev=true&hot=false&minify=false:145101:17 in _transform
at http://192.168.1.17:19000/index.bundle?platform=ios&dev=true&hot=false&minify=false:144524:21 in <unknown>
at node_modules/stream-browserify/node_modules/readable-stream/lib/_stream_transform.js:163:4 in Transform.prototype._write
at node_modules/stream-browserify/node_modules/readable-stream/lib/_stream_writable.js:408:2 in doWrite
at node_modules/stream-browserify/node_modules/readable-stream/lib/_stream_writable.js:397:9 in writeOrBuffer
at node_modules/stream-browserify/node_modules/readable-stream/lib/_stream_writable.js:306:4 in Writable.prototype.write
at http://192.168.1.17:19000/index.bundle?platform=ios&dev=true&hot=false&minify=false:143598:57 in <unknown>
at node_modules/nofilter/lib/index.js:122:15 in NoFilter#constructor
at node_modules/cbor/lib/utils.js:287:11 in guessEncoding
at node_modules/cbor/lib/decoder.js:220:4 in Decoder.decodeFirstSync
at CanaryMobile.js:12:32 in ws.onmessage
at node_modules/react-native/Libraries/WebSocket/WebSocket.js:231:8 in _eventEmitter.addListener$argument_1
at node_modules/react-native/Libraries/vendor/emitter/EventEmitter.js:189:10 in emit
at [native code]:null in callFunctionReturnFlushedQueue

Everything is still working in expo web thing, it's just on native platforms this happens.

hildjj commented 3 years ago

Did you add process to your list of dependencies?

2bdkid commented 3 years ago

Same error with it installed

2bdkid commented 3 years ago

Without the stream workaround I also get this, maybe it helps?

Error: Requiring module "node_modules/cbor/lib/cbor.js", which threw an exception: TypeError: Super expression must either be null or a function
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:104:6 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:171:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
at node_modules/expo-error-recovery/build/ErrorRecovery.fx.js:9:32 in ErrorUtils.setGlobalHandler$argument_0
at node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
at node_modules/regenerator-runtime/runtime.js:293:29 in invoke
at node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
at node_modules/regenerator-runtime/runtime.js:154:27 in invoke
at node_modules/regenerator-runtime/runtime.js:164:18 in PromiseImpl.resolve.then$argument_0
at node_modules/react-native/node_modules/promise/setimmediate/core.js:37:13 in tryCallOne
at node_modules/react-native/node_modules/promise/setimmediate/core.js:123:24 in setImmediate$argument_0
at [native code]:null in flushedQueue
at [native code]:null in invokeCallbackAndReturnFlushedQueue
hildjj commented 3 years ago

That is the error you would get if you had stream but not stream-browserify. I'd suggest updating your package.json and *.lock files, removing the node_modules directory, and re-installing everything with the package manager of your choice (I like pnpm this week). Here is my current dependency list:

{
  "dependencies": {
    "base64-js": "^1.5.1",
    "bignumber.js": "^9.0.1",
    "buffer": "^6.0.3",
    "cbor": "^7.0.4",
    "emitter-component": "^1.1.1",
    "events": "^3.3.0",
    "expo": "~40.0.1",
    "expo-splash-screen": "~0.9.0",
    "expo-status-bar": "^1.0.3",
    "expo-updates": "~0.4.0",
    "ieee754": "^1.2.1",
    "inherits": "^2.0.4",
    "node-inspect-extracted": "^1.0.4",
    "nofilter": "^2.0.3",
    "process": "^0.11.10",
    "react": "16.13.1",
    "react-dom": "17.0.1",
    "react-native": "~0.63.4",
    "react-native-gesture-handler": "~1.10.3",
    "react-native-reanimated": "~2.0.0",
    "react-native-screens": "~2.18.1",
    "react-native-unimodules": "~0.12.0",
    "react-native-web": "~0.15.0",
    "readable-stream": "^3.6.0",
    "safe-buffer": "^5.2.1",
    "stream-browserify": "^3.0.0",
    "string_decoder": "^1.3.0"
  },
  "devDependencies": {
    "babel-plugin-module-resolver": "^4.1.0",
    "@babel/core": "~7.13.10",
    "babel-jest": "~26.6.3",
    "jest": "~26.6.3",
    "react-test-renderer": "~17.0.1"
  }
}

Here is the work-around that I found for process.nextTick. I'm sure there's a better way, but this at least works. In App.js:

import process from 'process';
global.process = process;
import cbor from 'cbor';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Hello, Expo: {cbor.encodeOne('Hello, Expo')}</Text>
      <StatusBar style="auto" />
    </View>
  );
}

And a screenshot to prove it's working here:

simulator_screenshot_3C3D39E6-ED0A-4040-8278-A49B3D1849EA

hildjj commented 3 years ago

with cbor.encodeOne('Hello, Expo').toString('hex') you'll see 6b48656c6c6f2c204578706f, which looks more correct.

hildjj commented 3 years ago

For anyone looking at this in the future, we could have instead used https://github.com/annie-elequin/node-libs-expo which would have done the same thing, but imported a ton more dependencies that are un-needed. However, we would have been up and running in a few minutes, which might have been better.

hildjj commented 3 years ago

Understanding their code let me simplify a few things. Current set of packages required:

No changes to babel.config.js necessary. Change metro.config.js to:

module.exports = {
  transformer: {
    assetPlugins: ['expo-asset/tools/hashAssetFiles'],
  },
  resolver: {
    extraNodeModules: {
      stream: require.resolve('stream-browserify'),
    },
  },
};
2bdkid commented 3 years ago

Would you be able to provide the project files you're working with? I want to see if I can run them.

2bdkid commented 3 years ago

Ok never mind. I copied your package versions and it works now... Not sure which one was causing the issue.

hildjj commented 3 years ago

In case you need it I put mine into a repo. To try:

git clone https://github.com/hildjj/node-cbor-expo-example.git
cd node-cbor-expo-example
yarn install
npx expo start -c

then hit i or click the "Run on iOS Simulator" button in the web interface.

hildjj commented 3 years ago

Is this working enough that we can close the issue?