metro
metro copied to clipboard
Require cycle warnings should be opt-in when the source is node_modules
Do you want to request a feature or report a bug?
Feature
What is the current behavior?
Lots of warnings about require cycles from libraries in node_modules in the react-native ecosystem, coming from the following code: https://github.com/facebook/metro/blob/dc8d85911ff6bf6487b7e3aef6b004df4bdcf17f/packages/metro/src/lib/polyfills/require.js#L158-L174
What is the expected behavior?
Don't warn users about require cycles in libraries in node_modules unless the user opts-in. Warnings about code that you don't own, especially when the warnings are non-essential, create unnecessary noise.
Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.
React Native 0.57 default configuration and Metro version (0.47.1). Other information irrelevant.
Any workaround for this issue?
I get the warn as well. I've tried to ignore this but it didn't help me.
YellowBox.ignoreWarnings([
'Warning: isMounted(...) is deprecated', // works
'Module RCTImageLoader', // works
'Require cycle:', // doesn't work
])
I can't deal with these warnings right now in my app. I mute them via a npm postintall script including this mess:
const codeToObscure = /console.warn\([\s\S].*"Require cycle: "/;
const problemFilePath = './node_modules/metro-config/node_modules/metro/src/lib/polyfills/require.js';
const problemFileContent = fs.readFileSync(problemFilePath,'utf8');
fs.writeFileSync(problemFilePath,problemFileContent.replace(codeToObscure,'const noConsoleWarn = (""'),'utf8');
Would love to be able to opt-in to this warning. In the meantime, similar to @defualt, I've used patch-package to apply the below patch to ignore the warning only if its an external dependency:
Patch
patch-package
--- a/node_modules/metro/src/lib/polyfills/require.js
+++ b/node_modules/metro/src/lib/polyfills/require.js
@@ -111,21 +111,29 @@ function metroRequire(moduleId) {
var initializingIndex = initializingModuleIds.indexOf(
moduleIdReallyIsNumber
);
+
if (initializingIndex !== -1) {
var cycle = initializingModuleIds
.slice(initializingIndex)
.map(function(id) {
return modules[id].verboseName;
});
- // We want to show A -> B -> A:
- cycle.push(cycle[0]);
- console.warn(
- "Require cycle: " +
- cycle.join(" -> ") +
- "\n\n" +
- "Require cycles are allowed, but can result in uninitialized values. " +
- "Consider refactoring to remove the need for a cycle."
- );
+
+ var isExternalOnly = cycle.every(function(cycleWarning) {
+ return cycleWarning.includes("node_modules")
+ })
+
+ if (!isExternalOnly) {
+ // We want to show A -> B -> A:
+ cycle.push(cycle[0]);
+ console.warn(
+ "Require cycle: " +
+ cycle.join(" -> ") +
+ "\n\n" +
+ "Require cycles are allowed, but can result in uninitialized values. " +
+ "Consider refactoring to remove the need for a cycle."
+ );
+ }
}
}
@CodyBrouwers I have tried to use your patch but I received the following error from patch-package
**ERROR** Failed to apply patch for package metro
This error was caused because Git cannot apply the following patch file:
patches/metro+0.45.6.patch
This is usually caused by inconsistent whitespace in the patch file.
@toioski Ah yes, I've encountered that issue with patch-package as well. Better to just make the same changes and patch it yourself I think.
I'd like to add that require cycle may be intentional inside your app code and is fine in many cases if you know what you are doing and don't start calling cycle methods on initialization . I'd like to be able to disable those warnings even for my own code, is there a way?
@slorber In those cases the warning should be displayed. The problem like the OP said is:
Lots of warnings about require cycles from libraries in node_modules in the react-native ecosystem
Hi! We added this warning since we got many complains from developers at FB that it was hard to debug the errors caused by cyclic dependencies (since a cyclic dependency causes the returned value of a require
statement to be undefined
without hard throwing).
The YellowBox.ignoreWarnings
method should allow to mute these errors, @dakiesse are you adding it at the top of the entry point of your app?
YellowBox.ignoreWarnings([
'Require cycle:',
]);
@rafeca I added that in my entry point and it does not work. Like @dakiesse said, the other two warnings don't show up but this one does.
@rafeca yes, immediately after imports
in entry point
Today I updated versions to:
"react": "16.6.3",
"react-native": "0.57.5",
"metro-react-native-babel-preset": "0.49.1",
And I became to get new warning ListView is deprecated and will be removed in a future release. See https://fb.me/nolistview for more information
. I've tried to ignore it.
YellowBox.ignoreWarnings([
'Require cycle:',
'ListView is deprecated',
])
It doesn't work as well.
This is so annoying, any updates here?
Every time I load the app I get like a million require cycle warnings which I really don't care about and muting them as suggested doesn't work.
Is there any other way of silencing this?
@vrgimael the solution was suggested by @defualt
YellowBox.ignoreWarnings(["Require cycle:"]);
worked for me 👍
Here is my index.js:
/** @format */
import { AppRegistry, YellowBox } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";
// ignore specific yellowbox warnings
YellowBox.ignoreWarnings(["Require cycle:", "Remote debugger"]);
AppRegistry.registerComponent(appName, () => App);
YellowBox.ignoreWarnings
unfortunately does not hide them in the console :/
IMO this should be opt-in, not opt out. Many people also don't understand what it is and think they need to fix this warning even if nothing is wrong with the code. There are also third-party libs with the warning that you can do nothing about.
Also to find require cycles, you have to go through hundreds of warnings, doesn't seem very efficient to find an issue. Enabling/disabling all of the warnings don't seem ideal either, it'll probably be better to enable this per folder rather than for whole project.
Okaaaay, so if this warning is annoying the hell out of you, and you can't refactor your app because it's too much work, here's how I "suppressed" those warnings until a proper solution shows up :
- Add a
scripts
folder in your project - Create a
stfu.js
file with the following content (edited from @dakiesse) :
const fs = require('fs');
const codeToObscure = /console.warn\([\s\S].*"Require cycle: "/;
const problemFilePath = './node_modules/metro/src/lib/polyfills/require.js';
const problemFileContent = fs.readFileSync(problemFilePath,'utf8');
fs.writeFileSync(problemFilePath,problemFileContent.replace(codeToObscure,'const noConsoleWarn = (""'),'utf8');
- Add the following line to your
package.json
in yourscripts
:"postinstall": "node ./scripts/stfu.js",
When it's done, just rm -rf node_modules && yarn
to reinstall everything, and make sure these damn warnings are now gone.
This is really really tricky for us since we have LOTS of require cycles because of how we use redux in our app.
I hope this is helpful.
When i have a warning like that on my console, even if is not in node_modules
, my assets loading be very slow.
As a temporary fix to disable the warning and have assets load quicker, you can comment out line 109 in node_modules/metro/src/lib/polyfills/require.js.
Check it out temporary solution here: https://github.com/expo/expo/issues/2578#issuecomment-435713216
can someone please explain how to patch this? @Exilz answer is not working
Can always mute it by patching console.warn
. This is my index.js
file:
if (__DEV__) {
const IGNORED_WARNINGS = [
'Remote debugger is in a background tab which may cause apps to perform slowly',
'Require cycle:',
]
const oldConsoleWarn = console.warn
console.warn = (...args) => {
if (
typeof args[0] === 'string' &&
IGNORED_WARNINGS.some(ignoredWarning =>
args[0].startsWith(ignoredWarning),
)
) {
return
}
return oldConsoleWarn.apply(console, args)
}
}
module.exports = require('./src')
Note, if it isn't obvious, that this is a temporary fix until a more ideal solution is released. At which point you should delete this monkey patch!
IMO, YellowBox.ignoreWarnings
should result in a similar output than the above monkey patch.
@tazsingh Your solution works great! YellowBox.ignoreWarnings
can not mute the console logs. May need to use both ways to mute all.
Require cycles are perfectly fine. Well-organized code will undoubtedly have cycles. I don't understand the rationale to warn about them... Is the goal to put all the code in a single file?
How to mute this in a Typescript project? None of the suggested workarounds are working.
@i-schuetz I created the following patch file (in my case named metro+0.45.6.patch
) to apply with patch-package
and is working fine for me
patch-package
--- a/node_modules/metro/src/lib/polyfills/require.js
+++ b/node_modules/metro/src/lib/polyfills/require.js
@@ -106,7 +106,7 @@ function metroRequire(moduleId) {
});
// We want to show A -> B -> A:
cycle.push(cycle[0]);
- console.warn('Require cycle: ' + cycle.join(' -> ') + '\n\n' + 'Require cycles are allowed, but can result in uninitialized values. ' + 'Consider refactoring to remove the need for a cycle.');
+ // console.warn('Require cycle: ' + cycle.join(' -> ') + '\n\n' + 'Require cycles are allowed, but can result in uninitialized values. ' + 'Consider refactoring to remove the need for a cycle.');
}
}
Today I encountered the following require cycle node_modules/react-native/Libraries/Network/fetch.js -> node_modules/react-native/Libraries/vendor/core/whatwg-fetch.js -> node_modules/react-native/Libraries/Network/fetch.js
. I have a single fetch()
invocation in my whole codebase.
React Native Environment Info: System: OS: macOS 10.14.3 CPU: (4) x64 Intel(R) Core(TM) i5-5250U CPU @ 1.60GHz Memory: 54.78 MB / 8.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 8.12.0 - /usr/local/bin/node Watchman: 4.9.0 - /usr/local/bin/watchman SDKs: iOS SDK: Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1 Android SDK: API Levels: 27, 28 Build Tools: 27.0.3, 28.0.2, 28.0.3 System Images: android-28 | Google APIs Intel x86 Atom IDEs: Android Studio: 3.2 AI-181.5540.7.32.5056338 Xcode: 10.1/10B61 - /usr/bin/xcodebuild npmPackages: react: 16.6.3 => 16.6.3 react-native: 0.57.8 => 0.57.8
Okaaaay, so if this warning is annoying the hell out of you, and you can't refactor your app because it's too much work, here's how I "suppressed" those warnings until a proper solution shows up :
- Add a
scripts
folder in your project- Create a
stfu.js
file with the following content (edited from @dakiesse) :const fs = require('fs'); const codeToObscure = /console.warn\([\s\S].*"Require cycle: "/; const problemFilePath = './node_modules/metro/src/lib/polyfills/require.js'; const problemFileContent = fs.readFileSync(problemFilePath,'utf8'); fs.writeFileSync(problemFilePath,problemFileContent.replace(codeToObscure,'const noConsoleWarn = (""'),'utf8');
- Add the following line to your
package.json
in yourscripts
:"postinstall": "node ./scripts/stfu.js",
When it's done, just
rm -rf node_modules && yarn
to reinstall everything, and make sure these damn warnings are now gone.This is really really tricky for us since we have LOTS of require cycles because of how we use redux in our app.
I hope this is helpful.
Use
const codeToObscure = /console.warn\([\s]*`Require cycle[^;]*;/;
and
fs.writeFileSync(problemFilePath, problemFileContent.replace(codeToObscure, ''), { encoding: 'utf8' });
if the Regex mentioned above by @Exilz doesn't work, as in my case (Metro 0.49.2)
@leshanative
const codeToObscure = /console.warn\([\s]*`Require cycle[^;]*;/;
should be
const codeToObscure = /console.warn\([\s]*'Require cycle[^;]*;/;
(note the '
)
Honestly, would it be possible to remove all "Require cycle" warnings, put them in the bin, and throw the bin over the side (preferably when anchored over the nearest ocean trench)? I really don't see the need for them at all. Which programming languages can deal with cyclic dependencies? These days, pretty much all of them: from C to Python to JavaScript. Yes, it would be nice not to have cyclic dependencies, but it sounds unavoidable, especially in third-party code. By the sounds of it, "Require cycle" warning are less information and more noise, wasting the time of programmers.
For me, the "Require cycle" warnings occurs with existing Redux code that works on vanilla React (React original? React plain? The non-native React, I mean) and works quite well. There is a little bit of cyclic dependency between actions.js (the Redux actions code), and httpreq.js (Redux thunk code that sends HTTP requests and fires actions on responses), but I never got any warning on that platform. So why is there a warning on React Native?
This warning is making me do ugly acrobatics to suppress it when it's ostensibly for code quality. Really unfortunate decision to bury an optional warning deep inside a tool without a configuration option.
This might be showing my ignorance when it comes to bundlers, but why do we need this warning at that level instead of a linter like https://www.npmjs.com/package/tslint-no-circular-imports?