sanctuary-js / sanctuary-def

Run-time type system for JavaScript
MIT License
294 stars 23 forks source link

react-native build error on import #296

Closed llaenowyd closed 3 years ago

llaenowyd commented 3 years ago

I reproduced this from a new npx react-native init reproProj. Note that android studio, sdk and emulator are prerequisite to the init command and then launching reproProj with npm run android.

I'm not too familiar with the build environment for react-native but anyhow taking the following steps with reproProj

  1. npm i -S --no-optional sanctuary
  2. add import * as S from 'sanctuary' to the generated App.js
  3. npm run android

I get:

    at ModuleResolver.resolveDependency (D:\src\reproProj\node_modules\metro\src\node-haste\DependencyGraph\ModuleResolution.js:186:15)
    at ResolutionRequest.resolveDependency (D:\src\reproProj\node_modules\metro\src\node-haste\DependencyGraph\ResolutionRequest.js:52:18)
    at DependencyGraph.resolveDependency (D:\src\reproProj\node_modules\metro\src\node-haste\DependencyGraph.js:287:16)
    at Object.resolve (D:\src\reproProj\node_modules\metro\src\lib\transformHelpers.js:267:42)
    at D:\src\reproProj\node_modules\metro\src\DeltaBundler\traverseDependencies.js:434:31
    at Array.map (<anonymous>)
    at resolveDependencies (D:\src\reproProj\node_modules\metro\src\DeltaBundler\traverseDependencies.js:431:18)
    at D:\src\reproProj\node_modules\metro\src\DeltaBundler\traverseDependencies.js:275:33
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (D:\src\reproProj\node_modules\metro\src\DeltaBundler\traverseDependencies.js:87:24)
[Wed Oct 07 2020 19:04:00.925]  BUNDLE  ./index.js

error: Error: Unable to resolve module `util` from `node_modules\sanctuary-def\index.js`: util could not be found within the project.

The above workflow works fine for other npm libs such as ramda or redux.

npx react-native --version is 4.13.0 metro: 0.58.0, metro-core at 0.58.0, sanctuary at 3.1.0 sanctuary-def at 0.22.0

I'm not familiar with the usage of require where util is set up but I gather that it is not specifying that a js file be resolved. Perhaps "metro node-haste" misinterprets the require usage in a similar way.

Edit - I tried updating metro to their latest release 0.63.0 but that seems to have broken something in the otherwise as generated app/build.

davidchambers commented 3 years ago

Thanks for reporting this issue, @llaenowyd.

I imagine the fix is to fall back to the dummy util object if requiring the module fails:

module.exports = f (
  (function() {
     try {
       return require ('util');
     } catch (err) {
       return util;
     }
   } ()),
  require ('sanctuary-either'),
  require ('sanctuary-show'),
  require ('sanctuary-type-classes'),
  require ('sanctuary-type-identifiers')
);

Are you able to test this change in your environment?

llaenowyd commented 3 years ago

It gets further, past the bundler, to arrive at an error on the frontend, Requiring unknown module "9"

The stack trace isn't very good since it's relative to the bundle and I haven't gotten source maps working as yet in this environment.

But the last 4 frames are in loadModuleImplementation, I think from here in metro runtime require polyfill

davidchambers commented 3 years ago

Does making the same change to your sanctuary-either dependency resolve the issue?

llaenowyd commented 3 years ago

Some progress but some bad news. I'm not sure how I reached the error for module ID 9 yesterday. But I streamlined the process of trying this, because it doesn't want to try to rebuild anything from node_modules, without a change to packages or if it were deleted. I'm not sure I successfully tested the change yesterday.

So, changing to the function written above doesn't seem to do anything. I think the problem is in metro, and let's bear in mind the target is a Java SDK, and as well during or after Metro, another tool Hermes produces Java bytecode.

Now that I'm getting pretty good at clearing the build caches of these layers, which try to retain the results of processing node_modules, I see that if I replace the require('util'):

However, I had to make that change (the 2nd one) to: sanctuary-def, sanctuary-either, sanctuary-maybe, and sanctuary-pair.

I should also say that it's well known react-native doesn't have good compatibility with react/dom and although I would have thought that's due to differences between the mobile sdk and the browser, I'm not surprised to find some incompatibility around module resolution, that's barely compatible between node and anything else as it is.

davidchambers commented 3 years ago

It's not clear to me whether there is something I could change to make Sanctuary work better for you, @llaenowyd. Let me know if there is. :)

llaenowyd commented 3 years ago

Not at this time! Thanks for your contributions to the development of functional techniques in Javascript!