Skip to content

Instantly share code, notes, and snippets.

@huntie

huntie/metro.config.js

Last active Jul 18, 2021
Embed
What would you like to do?
Snippets accompanying my article "A concise guide to configuring React Native with Yarn Workspaces" on Medium
/**
* Metro Bundler configuration
* https://facebook.github.io/metro/docs/en/configuration
*
* eslint-env node, es6
*/
const blacklist = require('metro-config/src/defaults/blacklist');
const getWorkspaces = require('get-yarn-workspaces');
const path = require('path');
function getConfig(appDir, options = {}) {
const workspaces = getWorkspaces(appDir);
// Add additional Yarn workspace package roots to the module map
// https://bit.ly/2LHHTP0
const watchFolders = [
path.resolve(appDir, '..', 'node_modules'),
...workspaces.filter(
workspaceDir => !(workspaceDir === appDir),
),
];
return {
watchFolders,
resolver: {
blacklistRE: blacklist([
// Ignore other resolved react-native installations outside of
// myapp-native - this prevents a module naming collision when mapped.
/^((?!myapp-native).)+[\/\\]node_modules[/\\]react-native[/\\].*/,
// Ignore react-native-svg dependency in myapp-ui, mapped below.
// react-native-svg must only be included once due to a side-effect. It
// has not been hoisted as it requires native module linking here.
// http://bit.ly/2LJ7V4b
/myapp-ui[\/\\]node_modules[/\\]react-native-svg[/\\].*/,
]),
extraNodeModules: {
// Resolve all react-native module imports to the locally-installed version
'react-native': path.resolve(appDir, 'node_modules', 'react-native'),
// Resolve additional nohoist modules depended on by other packages
'react-native-svg': path.resolve(
appDir,
'node_modules',
'react-native-svg',
),
// Resolve core-js imports to the locally installed version
'core-js': path.resolve(appDir, 'node_modules', 'core-js'),
},
},
};
}
module.exports = getConfig(__dirname);
{
"name": "myapp-native",
"version": "1.0.0",
"private": true,
"scripts": {
"postinstall": "jetify",
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"pods": "cd ios; pod install"
},
"workspaces": {
"nohoist": [
"@react-native-community/async-storage",
"react-native",
"react-native/**",
"react-native-dev-menu",
"react-native-svg",
"jetifier"
]
},
"dependencies": {
"@react-native-community/async-storage": "^1.6.1",
"myapp-settings": "1.0.0",
"myapp-ui": "1.0.0",
"react": "16.9.0",
"react-native": "0.61.5",
"react-native-dev-menu": "^4.0.0",
"react-native-svg": "^9.12.0"
},
"devDependencies": {
"get-yarn-workspaces": "^1.0.2",
"metro-config": "^0.56.0"
}
}
@crutchcorn

This comment has been minimized.

Copy link

@crutchcorn crutchcorn commented Apr 24, 2020

Thanks so much for this article and Gist, Alex! Helped a lot! First result for me with "React Native Workspaces"!

@AdamGerthel

This comment has been minimized.

Copy link

@AdamGerthel AdamGerthel commented Nov 21, 2020

Is there a reason not to use a glob which includes additional react native packages? i.e something like:

// ...
 "nohoist": [
      "react-native",
      "react-native/**",
      "react-native-*",
      "react-native-*/**",
      "@react-native-*",
      "@react-native-*/**"
    ]
@AdamGerthel

This comment has been minimized.

Copy link

@AdamGerthel AdamGerthel commented Nov 21, 2020

@huntie I'm trying to wrap my head around the blacklistRE patterns (due to the react-native-svg issue). Are they paths relative to the project root? Could you list the folder structure (and package names) for the project that these patterns would work for? My project structure looks like this:

apps/
  app-one/
    package.json
  app-two/
    package.json
libs/
  icons/
    package.json
package.json

And I'm trying to figure out how to ignore a package from /libs/icons

@huntie

This comment has been minimized.

Copy link
Owner Author

@huntie huntie commented Nov 22, 2020

@AdamGerthel Yes, blacklistRE entries are relative to the project root.

  • Line 30 matches any react-native installation that is not the one under myapp-native/ (the app workspace). Instances of react-native from other workspaces are therefore excluded.
  • Line 36 matches a specific react-native-svg installation in another package, in this example myapp-ui/. Therefore this instance is excluded and the version of react-native-svg that exists in myapp-native/ is used.

(Line 36 could also have used the negative lookahead approach in line 30.)

Basically, both of these entries create a mapping where there is only one choice of which version of a dependency to bundle - in each case the one local to the app workspace.

Hope that helps 😄

@AdamGerthel

This comment has been minimized.

Copy link

@AdamGerthel AdamGerthel commented Nov 22, 2020

@huntie ok, so that's good because that means that I've understood it correctly :) The thing I'm not entirely getting is the structure of the regex and how to apply it in my project.

Line 30 works in my project, but line 36 doesn't. I'm still getting the Invariant Violation: Tried to register two views with the same name RNSVGSvgView error, meaning that I'm probably getting the regex for my folder structure wrong since it's apparently importing react-native-svg twice. So, for clarity, what would the equivalent of /myapp-ui[\/\\]node_modules[/\\]react-native-svg[/\\].*/ be in the folder structure example I listed in my previous comment? I would assume that this would work:

/libs[\/\\]icons[\/\\]node_modules[/\\]react-native-svg[/\\].*/

But I haven't be able to get working. I feel like I've tried every regex I can think of but nothing seems to exclude it. I've even tried absolute paths. I'm also not sure how (if) I can debug it other than: Reset metro cache, rebuild and hope for the best :D

Any ideas? The name of the package is not the same as the name of the folder, but that shouldn't matter since it's asking for a path, right?

@huntie

This comment has been minimized.

Copy link
Owner Author

@huntie huntie commented Nov 23, 2020

@AdamGerthel That regex looks right to me - another thing you might want to check is whether there is a react-native-svg conflict between app-one/ and app-two/ (your versions), plus whether there is a duplicate react-native-svg installation within dependencies app-one/.

Hopefully you can find from the debug output from what workspace the invariant violation is triggered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment