Skip to content

Instantly share code, notes, and snippets.

@huntie
Last active July 10, 2023 01:53
Show Gist options
  • Save huntie/85ea491763b444bfa1bdc8e997fc2765 to your computer and use it in GitHub Desktop.
Save huntie/85ea491763b444bfa1bdc8e997fc2765 to your computer and use it in GitHub Desktop.
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 exclusionList = require('metro-config/src/defaults/exclusionList');
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: {
blockList: exclusionList([
// 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
Copy link

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

@AdamGerthel
Copy link

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
Copy link

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
Copy link
Author

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
Copy link

@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
Copy link
Author

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.

@steveluscher
Copy link

steveluscher commented Jun 29, 2022

This needs updating for the new metro-config/src/defaults/exclusionList module and the blocklist property in Metro's config.

@huntie
Copy link
Author

huntie commented Jun 30, 2022

Thanks for pointing this out @steveluscher, now updated. Funnily enough I now work on Metro 😄

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