metro: `SHA-1 for file ... is not computed` when using `resolver.resolveRequest`
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
I am using a custom resolver.resolveRequest function in rn-cli.config.js. See https://facebook.github.io/metro/docs/en/configuration#resolver-options.
The error message is being printed from metro/src/node-haste/DependencyGraph.js#getSha1, which is being called by metro/src/Bundler.js#transformFile:
metro/src/node-haste/DependencyGraph.js#getSha1
getSha1(filename: string): string {
const resolvedPath = fs.realpathSync(filename);
const sha1 = this._hasteFS.getSha1(resolvedPath);
if (!sha1) {
throw new ReferenceError(`SHA-1 for file ${filename} is not computed`);
}
return sha1;
}
The issue is that the file won’t exist in the haste map if you are resolving it in the resolveRequest hook.
If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can yarn install and yarn test.
https://github.com/vjpr/expo-v2-test-pnpm/tree/broken
You need to run pnpm install (the reason for the custom resolver is because symlinks are not supported by metro and hence cause problems for pnpm).
What is the expected behavior?
getSha1 should compute hash if not in haste map.
Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.
metro@0.45.6 node@8.9.0 pnpm@2.21.1
Workaround
Add to metro/src/node-haste/DependencyGraph.js#getSha1:
if (!sha1) {
return getFileHash(resolvedPath)
function getFileHash(file) {
return require('crypto')
.createHash('sha1')
.update(fs.readFileSync(file))
.digest('hex')
}
}
I have released a patched version here: Use metro-pnpm@0.45.6-vjpr.2
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 107
- Comments: 78
Commits related to this issue
- chore: initial work to add more proper error handling In this commit I wanted to use `require` to import the `.github/ISSUE_TEMPLATE` in order to include the file contents. However, despite doing a ... — committed to oceanbit/GitShark by crutchcorn 3 years ago
- chore: initial work to add more proper error handling In this commit I wanted to use `require` to import the `.github/ISSUE_TEMPLATE` in order to include the file contents. However, despite doing a ... — committed to oceanbit/GitShark by crutchcorn 3 years ago
- Update DependencyGraph.js as suggested on https://github.com/facebook/metro/issues/330#issue-389608574 — committed to budiadiono/metro by budiadiono 2 years ago
I solved this issue by using
yarn startinstead of starting project withreact-native start(it uses npm start). I have been adding dependencies in project usingYarn add {dependencyName}and starting project via npm. which created error of SHA-1.I fixed it by install correct
react-native-cli:0.61.5 indeed works. I also did
npm i -g react-native-cli- it updated cli to 2.0.1 version and bundling worked.I make it work for this:
npx react-native bundle --platform ...but not work when I use like this:react-native bundle --platformdidn’t know why!
Just an update on why this happens.
Here is the function that is generating the message:
https://github.com/facebook/metro/blob/master/packages/metro/src/node-haste/DependencyGraph.js#L208
Here is the function that gets the sha1 from the haste map:
jest-haste-map/build/worker.js
When
metroresolves a file it looks for the file in ajest-haste-mapwhich also watches for changes to these files. There are two implementations for building a haste map (crawling the file tree from the project roots):watchmannative (c++, rust, etc.) library. jest-haste-map/build/crawlers/watchman.jsBoth don’t support following symlinks…so if you have any symlinks in your project root that point to files outside of the project root, then they will never make it into the haste map which also means they will never be watched. It was the first feature request for
metro5 years ago and its unresolved. You can see the issue here: https://github.com/facebook/metro/issues/1#issuecomment-641633646So there are two situations here.
a. Your symlink points to a file that is inside your project root.
b. Your symlink points to a file outside of your project root. E.g. If you are using a pnpm-based monorepo, all your symlinks resolve to the monorepo root. So if
expois nested inside the monorepo, then you symlinks will always point outside the project root.For
a, yoursha-1will actually be found, because your file’s realpath will be in the haste map. Forb, yoursha-1will not be found because your file’s realpath is not in the haste map.When
metrorequires a file it needs to transform it. It first checks if its transformation is cached in ametro-cache. Thesha-1of the file is used as part of the cache key.If its not in the cache, the file contents is actually read not from the haste map but from the file system. So if your file was symlinked to outside of a project root, it won’t be in the haste map at all, and the sha1 can’t be accessed…but it will still be able to be loaded fine.
https://github.com/facebook/metro/blob/7814c2840c49c16788041284fd65df25aa997d8c/packages/metro/src/DeltaBundler/Transformer.js#L141-L147
Re:
extraNodeModulesIf you look inside
metro-resolver#resolveyou can see thatextraNodeModules[packageName]is added to the list of search paths.https://github.com/facebook/metro/blob/7814c2840c49c16788041284fd65df25aa997d8c/packages/metro-resolver/src/resolve.js#L108-L134
allDirPathslooks like this:Note how the last path comes from the
extraPaths.NOTE: These paths are candidate paths, not dirs to search for packages in.
The
extraNodeModulesproxy hack is clever, as it allows you to take the packageName and resolve it how you would like. Similar could be done withresolveRequestbut its more complicated.A downside though is you do not get access to where the require is being made from…so it is only really viable if your package is hoisted in yarn. This is unreliable though! If you have two packages of same version, then only one is hoisted and the other is not which could cause crazy bugs.
Overriding
resolveRequestis the much safer option.One spanner in the works though is that inside the resolver
context.doesFileExistis called to check if the logical file path exists - not the realpath.In pnpm:
So for a monorepo in a pnpm setup, this will prevent files being found, even if you add the monorepo root to the
watchFolders.https://github.com/facebook/metro/blob/7814c2840c49c16788041284fd65df25aa997d8c/packages/metro-resolver/src/resolve.js#L423-L433
Including the entirety of the monorepo as a
watchFoldermay slow down the app startup. Expo will actually work without needing to include everynode_module, but then you need to make the sha1 patch anddoesFileExistpatch.We can modify
ctx.doesFileExistin theresolver#resolveRequestmetro config setting. I’m not sure if this will cause problems if resolve a logical path rather than a real path.LATER: Maybe we could use
hasteImplModulePathoption to provide a custom haste map that supports symlinks too.In terms of a clean solution, I think it is best to ensure that all the files that you would possibly require make their way into the haste map, which I think is possible by setting
watchFoldersin the metro config.Summary
I’m leaving this long explanation here because I had completely forgotten it since I last looked at it, and was hoping there was a fix by now but it seems not.
Symlinks will not be followed, so you will need to make sure the folders they point to are added to the haste map by including them as
watchFolders.extraNodeModulesdoesn’t add files to the haste map, it will only provide additional candidate resolve paths…but they will still need to be in the haste map.getSha1function, and you might need to patch themetro-resolve#resolvefunction.I’m thinking there might be a way to monkey-patch the library without needing a patch.
Just need to intercept the require of
node_modules/metro/src/node-haste/DependencyGraph.jsand override itsgetSha1method. Could probably add the require hook whenmetro.config.jsis called…I had tried all the methods above but still not work for me. OS:mac Catalina node:13.3.0 watchman:4.9.0 react-native:0.61.5
the error log like this
Metro Bundler has encountered an error: SHA-1 for file /Users/.../Downloads/AwesomeProject/node_modules/metro/src/lib/polyfills/require.js (/Users/.../Downloads/AwesomeProject/node_modules/metro/src/lib/polyfills/require.js) is not computedput all files inside assets name of folder something like this
…/…/assets/beach.jpg
npm cache clean --force cd ios/ && rm -rf build/ && xcodebuild clean npm start – --reset-cache
Worked for me
Works for me!!! 😄
I am experiencing this on RN 0.60.5
I just ran into this issue while enjoying the fun task of upgrading from
0.59.1to0.61.5withreact-native-cli.My error made me realize I was running the bundler via a copy of
react-nativethat was installed tonvm(Node Version Manager). Runningwhich react-nativeconfirmed this:/Users/XXXXXX/.nvm/versions/node/v10.16.2/bin/react-nativeI made sure to remove all ‘global’ installs of react-native:
Until
which react-nativeresponded withreact-native not foundThen in my project,
npx react-native run-iosworked.–
Mac OS X 10.14.6 RN 0.61.5
npx react-native --version3.0.4Seeing the same issue as described on
0.60.5. The workaround provided by @vjpr works - thank you! Looks like #455 should fix this. I’m curious why doesn’t seem to be a bigger problem for everyone 😄I made the change in
~/.config/yarn/global/node_modules/metro/src/node-haste/DependencyGraph.jsjust use npx Ex: npx react-native bundle --dev false --platform android --entry-file index.js --bundle-output ./android/app/src/main/assets/index.android.bundle --assets-dest ./android/app/src/main/res
I found it was an issue with me accessing the project on a second drive via a symlink on C: rather than navigating to the D: drive
Works for me,
0.61.5For anyone seeing this error when using
expo-yarn-workspaces, I got this and fixed it by simply deleting the auto-generated file (the file that the error points to) and deleting all the node modules and then just runningyarnagain to re-install node modules and re-generate the file.@donholly I am not sure why no one is flagging this issue more. I have just run in to this issue after I have setup a new terminal and cleaned up all my old node modules.
Thanks to @vjpr workaround it worked after rebuilding the app. Is this a miss on our part ? or is this being actively looked into ?
This is still a problem today with “react-native”: “^0.59.2”. Will there be real fix or do we need to copy/paste the workaround?
If anyone else having issue when archiving ios. I had to install react-native-cli and use it.
yarn add react-native-clithen override CLI_PATHnpm i -g react-native-cli It is solution of this issue.
Just an FYI: was having this issue when running codepush and fixed it by restarting my machine.
This one works for me! Thanks!
Try
yarn startinstead ofyarn react-native....Thanks @vjpr, you saved me hours. I can’t believe Github doesn’t offer some sort of donation button.
@dusan-dragon I needed the @vjpr fix to get RN 0.61 to work.
Just an addition, I ran into this issue today; at first I thought it was due to having pages and routers of my app spread across different libraries using NX, which uses a symlink to
node_modulesin every app project.However, the issue was that I already had Metro running in another terminal tab, and kept trying to remove
node_modulesand restart the app (and Metro) in another tab.TL;DR make sure there are no other Metro processes running when you try anything described in this thread.
I am getting this issue on rn-tester app on android. None of the above is working for me
this did it for me as well. i was running project directly
react-native startjust didyarn startI think I found a simple explanation for this problem. See https://github.com/facebook/jest/issues/10063#issuecomment-642356808.
When
metrotalks towatchmanit sends aquerywith agloboption. When aglobis used it prevents files and folders starting with a dot from being returned by the watchman query. There is an option to pass calledglob_includedotfileswhich includes dot files.Depending on whether the clock is available, if
globis not used, then you are not going to get any dotfiles or dot dirs included.So this explains the sporadic behaviour.
This explains why @SeanHayes was having a problem until his MacBook restarted.
And it also explains why
pnpmdoesn’t work because all its deps are found innode_modules/.pnpmwhich includes a dir starting with a dot.Its a one line fix that is in the pipeline but I feel like I went to the ends of the earth to track it down.
Hello, I have this problem and then fixed it by using directly the
node_modules/react-native/scripts/launchPackager.commandinstead ofreact-native startIf you have any further investigation on this please let me know
Finally got what went wrong here, folder name has 1 upper case character in require. eg.
require(../../../assets/marketPlace/banner.png). Here “p” was upper case here but folder was with lower case p. After changing require path it was working again.currently my project is on 0.61.5 but it showing the same error
I’ve got the same issue when I tried to upgrade react-native to 0.57.0. I followed the steps mentioned the change log (https://github.com/react-native-community/react-native-releases/blob/master/CHANGELOG.md#057), but had no luck.