electrode-io / electrode-native

A platform to ease integration&delivery of React Native apps in existing mobile applications
https://native.electrode.io
Other
723 stars 113 forks source link

ern run-ios failing with mkdirp error #1891

Open fhkarczeski opened 1 year ago

fhkarczeski commented 1 year ago

Hello everyone,

Starting last Monday April 10 we noticed that existing apps can no longer run locally on iOS. Running the ern run-ios command gives this error:

✔ Booting iOS Simulator 0s
✖ Building iOS Runner project 36s
✖ An error occurred: iOS Runner build failed [xcbuild exit code 65].
✖ To troubleshoot this build failure, we recommend building the Runner iOS project from Xcode.
✖ You can open the Runner project in Xcode manually or by running 'open ios/ErnRunner.xcodeproj'.
✖ Building the Runner from Xcode will provide more meaningful error reporting that can be of help
✖ to pinpoint the cause of the build failure.

I tried to build the .xcworkspace on Xcode and I got this error:

/.ern/containergen/out/ios/node_modules/react-native/scripts/generate-specs-cli.js:47
  mkdirp.sync(outputDirectory);
         ^

TypeError: mkdirp.sync is not a function
    at generateSpec (/.ern/containergen/out/ios/node_modules/react-native/scripts/generate-specs-cli.js:47:10)
    at main (/.ern/containergen/out/ios/node_modules/react-native/scripts/generate-specs-cli.js:91:3)
    at Object.<anonymous> (/.ern/containergen/out/ios/node_modules/react-native/scripts/generate-specs-cli.js:94:1)
    at Module._compile (node:internal/modules/cjs/loader:1126:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1180:10)
    at Module.load (node:internal/modules/cjs/loader:1004:32)
    at Function.Module._load (node:internal/modules/cjs/loader:839:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47
Command PhaseScriptExecution failed with a nonzero exit code

Looking at the generate-specs-cli.js file, I see that it is requiring mkdirp, this is the line requiring the library: const mkdirp = require('mkdirp');

Looking into the mkdirp library it is loading, I see that it is exporting this:

export const mkdirp = Object.assign(async (path, opts) => {
    path = pathArg(path);
    const resolved = optsArg(opts);
    return useNative(resolved)
        ? mkdirpNative(path, resolved)
        : mkdirpManual(path, resolved);
}, {
    mkdirpSync,
    mkdirpNative,
    mkdirpNativeSync,
    mkdirpManual,
    mkdirpManualSync,
    sync: mkdirpSync,
    native: mkdirpNative,
    nativeSync: mkdirpNativeSync,
    manual: mkdirpManual,
    manualSync: mkdirpManualSync,
    useNative,
    useNativeSync,
});
//# sourceMappingURL=index.js.map

So the mkdirp object being imported is actually mkdirp.mkdirp.sync, I can fix it either by fixing the sync call or the require like const { mkdirp } = require('mkdirp');. If I make either change above and rebuild it with Xcode, it runs the application correctly. But if I run the ern run-ios command again, it overrides the changes and breaks again. This miniapp was running correctly last Friday, April 7, and all of our miniapps stopped working on the following Monday. I haven't seen any change on Electrode that could've caused this error, and we haven't changed our apps either. This has happened to multiple devs, so it's does not seem like a local machine issue.

Does anyone have any ideas of what could be happening? ern version: v0.50.1 miniapp react native version: 0.66.5 node: v16.17.0 npm: 8.15.0

fhkarczeski commented 1 year ago

I seem to have found the issue, but I am still tracing why it is happening. When the iOS container is generated, it is not installing the correct dependencies from the package.json file. The file /.ern/containergen/out/ios/yarn.lock actually says that mkdirp is a dependency of metro:

metro@0.66.2, metro@^0.66.1:
  version "0.66.2"
  resolved "https://registry.yarnpkg.com/metro/-/metro-0.66.2.tgz#f21759bf00995470e7577b5b88a5277963f24492"
  integrity sha512-uNsISfcQ3iKKSHoN5Q+LAh0l3jeeg7ZcNZ/4BAHGsk02erA0OP+l2m+b5qYVoPptHz9Oc3KyG5oGJoTu41pWjg==
  dependencies:
    ...
    **mkdirp "^0.5.1"**
    ...

The metro-cache package specifies the same dependency. And the yarn.lock file actually shows the correctly resolved dependency:

mkdirp@^0.5.1:
  version "0.5.6"
  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
  integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
  dependencies:
    minimist "^1.2.6"

However, when the container generation finishes, the actually installed version of mkdirp is 3.0.0, which removed the default exports. So at some point the container generation for iOS is installing the wrong dependency, and that is what is breaking everything. If we run yarn install after the initial creation of the container, and then start the iOS emulator, it also works without a problem. I will keep debugging to see where the mismatch is happening.

@Karthiccc23 @friederbluemle any ideas on where to look?

fhkarczeski commented 1 year ago

Seems like the correct version of mkdirp (0.5.6) gets installed briefly, then it gets overwritten by the pod install command:

✔ Running pod install --verbose 7s

The pod install command is removing the existing one and installing the latest version.

fhkarczeski commented 1 year ago

The issue is happening on the IosGenerator.ts file. For our version of RN (0.66.5), it is using the code react-native-codegen. After the pod install command runs, the generator is removing all libraries that are not RN related. This removes the correct mkdirp module.

Later during the react-native-codegen function, it manually adds the mkdirp dependency again without checking the required version on the main packages.json file. At this point the latest version of the mkdirp library that contains breaking changes is added and then merged into the node_modules folder.

Would it be better to not remove the mkdirp library from the initial node_modules or to ensure we check for a particular version on the package.json file to install the correct version (if one exists)? @friederbluemle @belemaire @Karthiccc23