How to make Metro (React Native packager) ignore certain directories - react-native

Problem:
My project has a #providesModule naming collision when trying to run react-native run-ios from the command line. It is conflicting with autogenerated dir dist/ which is created by another npm package, esdoc. I would like to be able to keep this autogenerated dir and just make the react native packager ignore the dist/ dir.
Error Message:
[01/23/2017, 13:17:07] <START> Building Haste Map
Failed to build DependencyGraph: #providesModule naming collision:
Duplicate module name: ann
Paths: /Users/thurt/projects/example/package.json collides with /Users/thurt/projects/example/dist/esdoc/package.json
This error is caused by a #providesModule declaration with the same name across two different files.
Error: #providesModule naming collision:
Duplicate module name: ann
Paths: /Users/thurt/projects/example/package.json collides with /Users/thurt/projects/example/dist/esdoc/package.json
This error is caused by a #providesModule declaration with the same name across two different files.
at HasteMap._updateHasteMap (/Users/thurt/projects/example/node_modules/react-native/packager/react-packager/src/node-haste/DependencyGraph/HasteMap.js:158:13)
at p.getName.then.name (/Users/thurt/projects/example/node_modules/react-native/packager/react-packager/src/node-haste/DependencyGraph/HasteMap.js:133:31)

The configuration for this has a habit of changing between RN versions. See below for version-specific instructions on creating a config file, loading the config file and clearing the cache.
For React Native >= 0.64 to 0.71(+?)
A rename of the helper function from blacklist to exclusionList was made in Metro 0.60, and the config entry blacklistRE -> blockList in Metro 0.61. These both landed in RN in 0.64.0.
In your project root create metro.config.js with the contents:
const exclusionList = require('metro-config/src/defaults/exclusionList');
// exclusionList is a function that takes an array of regexes and combines
// them with the default exclusions to return a single regex.
module.exports = {
resolver: {
blockList: exclusionList([/dist\/.*/])
}
};
For React Native >= 0.59, < 0.64
In your project root create metro.config.js with the contents:
const blacklist = require('metro-config/src/defaults/blacklist');
// blacklist is a function that takes an array of regexes and combines
// them with the default blacklist to return a single regex.
module.exports = {
resolver: {
blacklistRE: blacklist([/dist\/.*/])
}
};
For React Native >= 0.57, < 0.59
In your project root create rn-cli.config.js with the contents:
const blacklist = require('metro-config/src/defaults/blacklist');
// blacklist is a function that takes an array of regexes and combines
// them with the default blacklist to return a single regex.
module.exports = {
resolver: {
blacklistRE: blacklist([/dist\/.*/])
}
};
For React Native >= 0.52, < 0.57
In your project root create rn-cli.config.js with the contents:
const blacklist = require('metro').createBlacklist;
module.exports = {
getBlacklistRE: function() {
return blacklist([/dist\/.*/]);
}
};
For React Native >= 0.46, < 0.52.
In your project root create rn-cli.config.js with the contents:
const blacklist = require('metro-bundler').createBlacklist;
module.exports = {
getBlacklistRE: function() {
return blacklist([/dist\/.*/]);
}
};
For React Native < 0.46.
In your project root create rn-cli.config.js with the contents:
const blacklist = require('react-native/packager/blacklist');
module.exports = {
getBlacklistRE: function() {
return blacklist([/dist\/.*/]);
}
};
All versions < 0.59
Have your CLI command use this config by passing the --config option:
react-native run-ios --config=rn-cli.config.js
(The config file should be automatically picked up by RN >= 0.59, ever since it was renamed metro.config.js)
All versions: Note on caching
Be aware that your blacklisted items may have already been included in the cache by the packager in which case the first time you run the packager with the blacklist you may need to reset the cache with --reset-cache

Related

React-Native Expo Export Web Receiving Error 'Invalid Project Root' While Building Production App

Hi I am receiving the error that the project root is invalid. I will also add that I am using expo alongside my project.
This happens when executing the command npx expo export:web
Also happens when executing the command npx expo build
webpack.config.js
module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: ["react-native-reanimated/plugin"],
};
};
metro.config.js
(Not sure if metro is relevant as I believe it is more for development purposes...)
const { getDefaultConfig } = require("#expo/metro-config");
const defaultConfig = getDefaultConfig(__dirname);
defaultConfig.resolver.assetExts.push("cjs");
module.exports = defaultConfig;
react-native.config.js
module.exports = {
project: {
ios: {},
android: {}, // grouped into "project"
web: {},
},
assets: ["./assets/fonts"], // stays the same
};
npm start works fine and everything works accordingly in the browser. The goal is to build this for production and begin hosting on a web server.
I am hoping that I am simply missing a location to a directory in a config file but any insight is appreciated.
First, just run it with expo start, after it started press w.

Import yaml file in React Native results in number 1 instead of actual content

I'm trying to import a yaml file in React Native. I can see in the Metro defaults.js file that yaml is listed as an asset extension already.
The imported value is always the number 1 though and not the actual contents of the yaml file.
import enYaml from '../i18n/locale/en.yaml';
That is because you're loading it as a resource. So it's the resource ID. What you'd need is an answer for What is the equivalent of a webpack loader when using the metro bundler in React Native?
To do this in Expo which uses babel.config.js which Metro uses you need to add the babel-plugin-content-transformer as a dev dependency and configure it as follows
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
[
'content-transformer',
{
transformers: [
{
file: /\.ya?ml$/,
format: 'yaml',
},
],
},
],
...

Can I get a webpack resolve alias working on android with expo?

I'm trying to get a preact library to work with expo/react-native
It works find on web using this alias in webpack:
// webpack.config.js
const createExpoWebpackConfigAsync = require('#expo/webpack-config');
module.exports = async function(env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
config.resolve.alias = {
...config.resolve.alias,
'preact': 'react'
}
return config;
};
But on android I get an error: Unable to resolve "preact" from "node_modules/.../....
Does anyone know how to get the same kind of alias working outside of web?
I was unable to find a solution where webpack's alias was usable outside of Web on Android. I needed it on account of the typical invalid Hook call caused by duplicate React modules being used.
Supposedly Yarn workspaces might fix this as well but I couldn't get that working.
The solution I found and was mildly painless was to update my local libraries' devDependencies so they all use the same React module being used in the main project's dependencies.
- app
|
|-- package.json dependency: "react":"18.1.0"
- local_library
|
|-- package.json devDependency:
"react": "file:../../../node_modules/react",

How can I build my React Native Storybook to web?

I am running React Native Storybook which runs Storybook in the Native emulator.
In addition to the how React Native Storybook works currently, I would also like to build an instance of it for web as a reference companion to our app.
I am using "#storybook/react-native": "5.3.14". My stories are located at ./storybook.
Install react-native-web, #storybook/react and babel-plugin-react-native-web from npm in your project root.
Add a new configuration directory for Storybook, say ./.storybook-website. Inside this directory, add main.js. This creation would otherwise be done by the Storybook installation wizard.
my-app
├── .storybook-website
│   └── main.js
└── // .... rest of your app
Add the following content to main.js:
module.exports = {
stories: ['../storybook/stories/index.js'],
webpackFinal: async (config) => {
config.resolve.alias = {
...(config.resolve.alias || {}),
// Transform all direct `react-native` imports to `react-native-web`
'react-native$': 'react-native-web',
// make sure we're rendering output using **web** Storybook not react-native
'#storybook/react-native': '#storybook/react',
// plugin-level react-native-web extensions
'react-native-svg': 'react-native-svg/lib/commonjs/ReactNativeSVG.web',
// ...
};
// mutate babel-loader
config.module.rules[0].use[0].options.plugins.push(['react-native-web', { commonjs: true }]);
// console.dir(config, { depth: null });
return config;
},
};
Update the stories path in main.js to the location of your existing root story.
Finally add run scripts to your package.json:
"storybook:web": "start-storybook -p 6006 --config-dir ./.storybook-website",
"storybook-build:web": "build-storybook --config-dir ./.storybook-website --output-dir dist-storybook-website --quiet"
Presto! Run using yarn storybook:web. This will run storybook dev server, opening a browser showing what you usually would see in the device emulator.

How to extend default React Native webpack config?

I would like to add aliases to my React Native project started from the scratch with default react-native cli tools.
I created a webpack.config.js in the app root folder hoping that this will be enough for webpack to catch in on the fly. But its never happened.
Are any workarounds available?
Currently my webpack.config.js looks like that:
var path = require('path');
const alias = {
'~': __dirname,
'assets': path.resolve('./app/assets/'),
'native-styles': path.resolve('./app/native/styles')
}
module.exports = {
resolve: {
alias: alias,
}
}