Saving any change to a native module in Visual Studio kills the React Native CLI in Visual Studio Code
Problem Description
I am running the native app via Visual Studio whilst running the React Native CLI in a terminal in Visual Studio Code.
Whenever I save changes to a header file in a native module via Visual Studio, it crashes the React Native CLI running in Visual Studio Code.
node:internal/fs/watchers:255
throw error;
^
Error: EPERM: operation not permitted, watch 'C:\Users\jbizz\git\banana_native\apps\banana\windows\.vs\banana\FileContentIndex\merges'
at FSWatcher.<computed> (node:internal/fs/watchers:247:19)
at Object.watch (node:fs:2491:36)
at NodeWatcher._watchdir (C:\Users\jbizz\git\banana_native\node_modules\metro-file-map\src\watchers\NodeWatcher.js:89:24)
at C:\Users\jbizz\git\banana_native\node_modules\metro-file-map\src\watchers\NodeWatcher.js:185:22
at Walker.<anonymous> (C:\Users\jbizz\git\banana_native\node_modules\metro-file-map\src\watchers\common.js:81:31)
at Walker.emit (node:events:519:28)
at C:\Users\jbizz\git\banana_native\node_modules\walker\lib\walker.js:69:16
at FSReqCallback.oncomplete (node:fs:187:23) {
errno: -4048,
syscall: 'watch',
code: 'EPERM',
path: 'C:\\Users\\jbizz\\git\\banana_native\\apps\\banana\\windows\\.vs\\banana\\FileContentIndex\\merges',
filename: 'C:\\Users\\jbizz\\git\\banana_native\\apps\\banana\\windows\\.vs\\banana\\FileContentIndex\\merges'
}
Node.js v20.17.0
ELIFECYCLE Command failed with exit code 1.
Steps To Reproduce
- Create a React Native Windows app (I am using RNW v0.73 with Fabric disabled).
- Add any native module to the project.
- Start the React Native CLI in Visual Studio Code via the terminal (I am using Git Bash, which is based on MinGW).
- Run the RNW app in Visual Studio.
- Inside Visual Studio, select the native module and save a change to any source file from that native module, such as
ReactNativeModule.h. - The React Native CLI will crash.
If it doesn't reproduce, try having ReactNativeModule.h open at the same time in Visual Studio Code.
Expected Results
The React Native CLI shouldn't crash.
CLI version
12.3.6
Environment
info Fetching system and libraries information...
System:
OS: Windows 11 10.0.22631
CPU: (12) x64 12th Gen Intel(R) Core(TM) i5-1235U
Memory: 1.71 GB / 15.68 GB
Binaries:
Node:
version: 20.17.0
path: ~\AppData\Local\Volta\tools\image\node\20.17.0\node.EXE
Yarn: Not Found
npm:
version: 10.8.2
path: ~\AppData\Local\Volta\tools\image\node\20.17.0\npm.CMD
Watchman: Not Found
SDKs:
Android SDK: Not Found
Windows SDK:
AllowDevelopmentWithoutDevLicense: Enabled
Versions:
- 10.0.19041.0
- 10.0.22621.0
- 10.0.26100.0
IDEs:
Android Studio: Not Found
Visual Studio:
- 17.11.35303.130 (Visual Studio Community 2022)
Languages:
Java: Not Found
Ruby: Not Found
npmPackages:
"@react-native-community/cli": Not Found
react: Not Found
react-native: Not Found
react-native-windows: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: false
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
info React Native v0.75.3 is now available (your project is running on v0.73.9).
info Changelog: https://github.com/facebook/react-native/releases/tag/v0.75.3
info Diff: https://react-native-community.github.io/upgrade-helper/?from=0.75.3
info For more info, check out "https://reactnative.dev/docs/upgrading?os=windows".
Community Modules
Custom module created with:
npx react-native@latest init-windows --logging --overwrite --template old/uwp-cpp-lib --name MyLibrary
Target Platform Version
10.0.19041
Target Device(s)
Desktop
Visual Studio Version
Visual Studio 2022
Build Configuration
Debug
Snack, code example, screenshot, or link to a repository
No response
The RNW metro config is supposed to be set up to avoid this set of problem of monitoring VS files. In case something wasn't applied correctly, can you share your metro config? Make sure to add these files to the block list in metro.
Ah, that might be the place to check!
It doesn't reproduce all the time - some days it's always doing it, and others it doesn't, so I'll have to check next time I'm in the error state.
I have a custom metro.config.js that adds some limited support for Expo (such that you can run expo start and the Metro bundler started up by that happily works together with a RNW app). It may be familiar from #13534, but since then I have incorporated @rnx-kit/[email protected]. Some of it may be redundant as a result, I just haven't have time to remove those redundant parts.
Here it is:
const path = require("node:path");
const { makeMetroConfig } = require("@rnx-kit/metro-config");
const { getDefaultConfig } = require("expo/metro-config");
const monorepoRoot = path.resolve(__dirname, "../..");
const reactNativeAppAuthJs = path.resolve(
monorepoRoot,
"packages/react-native-app-auth-js",
);
const defaultConfig = getDefaultConfig(__dirname);
const {
resolver: { sourceExts, assetExts },
} = defaultConfig;
/** @type {import("metro-config").MetroConfig} */
const config = {
...defaultConfig,
watchFolders: [
...defaultConfig.watchFolders,
reactNativeAppAuthJs,
// We add monorepoRoot to fix the following error which occurs with
// `react-native start` but not `expo start`:
// > Unable to resolve module @babel/runtime/helpers/interopRequireDefault
// It occurs because even though Metro traverses the monorepo root's
// node_modules, it seems to ignore the contents if it's not a watch folder.
// https://github.com/facebook/react-native/issues/27712#issuecomment-715780864
monorepoRoot,
],
resolver: {
...defaultConfig.resolver,
assetExts: assetExts.filter((ext) => ext !== "svg"),
sourceExts: [...sourceExts, "svg"],
resolveRequest: reactNativePlatformResolver({
macos: "react-native-macos",
windows: "react-native-windows",
}),
extraNodeModules: {
...defaultConfig.resolver.extraNodeModules,
"@scoville/react-native-app-auth-js": reactNativeAppAuthJs,
},
},
serializer: {
...defaultConfig.serializer,
getModulesRunBeforeMainModule() {
return [
require.resolve("react-native/Libraries/Core/InitializeCore"),
require.resolve("react-native-macos/Libraries/Core/InitializeCore"),
require.resolve("react-native-windows/Libraries/Core/InitializeCore"),
...defaultConfig.serializer.getModulesRunBeforeMainModule(),
];
},
},
transformer: {
...defaultConfig.transformer,
babelTransformerPath: require.resolve("react-native-svg-transformer"),
},
};
module.exports = makeMetroConfig(config);
/**
* This implementation is inlined from
* `@react-native/community-cli-plugin/dist/utils/metroPlatformResolver.js`,
* because it can't be imported directly (the ./utils subpath is not allowed by
* the package's exports map).
*
* This is an implementation of a metro resolveRequest option which will remap
* react-native imports to different npm packages based on the platform
* requested. This allows a single metro instance/config to produce bundles for
* multiple out-of-tree platforms at a time.
*
* @param platformImplementations
* A map of platform to npm package that implements that platform
*
* Ex:
* {
* windows: 'react-native-windows',
* macos: 'react-native-macos'
* }
*/
function reactNativePlatformResolver(platformImplementations) {
return (context, moduleName, platform) => {
let modifiedModuleName = moduleName;
if (platform != null && platformImplementations[platform]) {
if (moduleName === "react-native") {
modifiedModuleName = platformImplementations[platform];
} else if (moduleName.startsWith("react-native/")) {
modifiedModuleName = `${
platformImplementations[platform]
}/${modifiedModuleName.slice("react-native/".length)}`;
}
}
return context.resolveRequest(context, modifiedModuleName, platform);
};
}
I'm happy to either close this issue (and reopen it if I have problems again; or report back if the suggested issue solves it), or leave it open until I get a reproducing case to confirm a fix with. I don't mind either way!
RNW uses the following to make sure Metro ignores VS files (from https://github.com/microsoft/react-native-windows/blob/dde3461cb81c738d3b937af2a757617cd43e8742/vnext/templates/cpp-app/metro.config.js#L28C1-L37C8):
blockList: exclusionList([
// This stops "react-native run-windows" from causing the metro server to crash if its already running
new RegExp(
`${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
),
// This prevents "react-native run-windows" from hitting: EBUSY: resource busy or locked, open msbuild.ProjectImports.zip or other files produced by msbuild
new RegExp(`${rnwPath}/build/.*`),
new RegExp(`${rnwPath}/target/.*`),
/.*\.ProjectImports\.zip/,
]),
@shirakaba Could you publish to us your update version of metro.config.js?
I am having the same problem.
This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 7 days. It will be closed if no further activity occurs within 7 days of this comment.