React Native: Unable to resolve module fs - npm

Unable to resolve module fs from /...mypath
I got this error when trying to import a node module into my react-native app.
The module used 'fs' in this way:
var fs = require('fs');
var list = JSON.parse(fs.readFileSync(__dirname + '/list.json', 'utf8'));

I ended up using 'rn-nodeify' to include fs into React Native. You can use most of the node core modules this method. Install it with npm:
npm install rn-nodeify
Then in package.json file, add the following line in "scripts" to specify which modules you want to include in your RN project. For example, I used fs, crypto and https, and the line goes
"postinstall": "node_modules/.bin/rn-nodeify --install crypto,fs,https --hack"

React Native applications do not run in the Node.js environment (it is only used by the packager to actually serve and compile your application bundle).
Since your app is running inside JS VM on either iPhone or Android, the only way to access filesystem is to use react-native-fs or any other 3rd party module that utilises bridge connection to talk to the platform specific native APIs.

it took me a while to find the issue, I'm sharing it as it might be useful for future reference (using react native with Expo):
One of my coworkers accidentally imported in one of our react components app.config.js in the project root to read some configuration rather than using expo-constants.
it was causing it to read the .env file from the react native wrapper that obviously doesn't have the fs lib.. this is the first line of our app.config.js:
import 'dotenv/config';
the correct way for reading settings inside app.config is:
import Constants from 'expo-constants';
const appConfig = Constants.manifest;

Install react-native-fs (follow the instructions at de link), so weather the error persist, enter at the directory ('./node_modules/tfjs-image-recognition-base/build/commonjs/env/) search by the file: (creatFileSystem.js) and edit:
fs = require('fs')
to:
fs = require('react-native-fs')
I don't know if this is recommended way, but was the only that worked for me.

If you want to import a json list just call it direct.
Example:
import subscriptionData from './assets/dataSource/subscriptionData.json';
or
var subscriptionData = require('./assets/dataSource/subscriptionData.json');
You don't need to convert it, and you can use to import your data or the way you want.
function installJson() {
console.log("Iniciando Importação");
subscriptionData.forEach(item => {
firestore().collection('subscription').add(item);
});
}
subscriptionData.json
[{
"code": 325,
"name": "bla bla bla"
},
{
"code": 356,
"name": "ble ble ble"
}]

Instead of:
const fs = require('fs');
Try:
const fs = require('react-native-fs');
worked in my case.

Related

How would you get JOSE working in an Expo app?

I wrote a small PoC for JOSE which works on Expo web but fails on iOS because it's looking for crypto and it's showing can't find variable: crypto
A few other packages need to be installed
npx expo install expo-random text-encoding buffer expo-standard-web-crypto
Then add file that would initialize the polyfills that are needed.
// initializePolyfills.ts
global.Buffer = require("buffer").Buffer;
import { polyfillWebCrypto } from "expo-standard-web-crypto";
polyfillWebCrypto();
const TextEncodingPolyfill = require("text-encoding");
Object.assign(global, {
TextEncoder: TextEncodingPolyfill.TextEncoder,
TextDecoder: TextEncodingPolyfill.TextDecoder,
});
In app.tsx, import the file as the first line
import './importPolyfills'
...

How to set up environment variables in react native

I'm making a react native app that makes a request to my server hosted on heroku.
Should I be hiding the URL of my server and if so how can I add an environment variable to a react native project?
I have made a .env file and then have done this:
console.log(process.env.URL)
Which is returning undefined - I am also using expo if that makes a difference.
If you use Expo, there is an easy way to create environment variables.
In your app.json file
{
"expo": {
"extra": {
"URL": "https://..."
}
}
}
After that, you will need to install the expo-constant package.
expo install expo-constants
And, to get the info in your app:
import Constants from "expo-constants";
console.log(Constants.manifest.extra.URL);
One library that I like to use that works for bare react native and expo is react-native-dotenv
Install it npm i react-native-dotenv
Add a .env file with your variables
MY_ENV_VARIABLE=SECRET_PASSWORD
Add the babel plugin to .babelrc file.
{
"plugins": [
["module:react-native-dotenv"]
]
}
Import and use it
import { MY_ENV_VARIABLE } from "react-native-dotenv";
function doSomething() {
console.log(MY_ENV_VARIABLE);
}

Typescript annotation error for default React Native app?

When creating a fresh React Native project and opening the default app.js file in VSCode, this line;
const App: () => React$Node = () => {
returns
Type annotations can only be used in TypeScript files.
as a VSCode problem.
Am I suppose to have typescript installed with React Native, or is this some kind of other issue with VSCode or something? Surely React Native isn't releasing their default app.js file with an error.
Here's the contents of the problem.
{
"resource": "/d:/App/sw_lbi_app/App.js",
"owner": "typescript",
"code": "8010",
"severity": 8,
"message": "Type annotations can only be used in TypeScript files.",
"source": "ts",
"startLineNumber": 27,
"startColumn": 12,
"endLineNumber": 27,
"endColumn": 28
}
const App: () => React$Node = () => {
Type annotations can only be used in TypeScript files.
In case you want to leave this line of Facebook's code to stay peacefully in Microsoft's VS Code, there is a Setting switch to turn off the TypeScript-style validation in a .js file.
Open Preferences => Settings, search javascript.validate, and locate
Uncheck it, and re-open App.js file. The validation will be gone.
PS: There is an option to make this setting change in User scope or Workspace scope.
That's Flow, not TypeScript. Simply remove the types and your code will run without problem.
It is Flow not TypeScript as mentioned Yanick.
VSC doesn't support it by default, so if you want to keep it the way it is, you can just install
Flow Language Support extension in your IDE.

Bundle size is big, how to reduce size of app.js?

I am using Vue.js and have only 4 components in my project.
I imported only bootstrap, jquery and lodash:
import { map } from 'lodash';
import 'bootstrap/js/dist/modal';
import $ from "jquery";
But npm run production creates
bundle of 400kb size.
npm run production is configured as shown below.
cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js
Is it possible to reduce bundle size to ~100KB ? If yes how?
You should add bundle analyzer to your webpack config.
That tool will help you to understand what is going on with your final bundle for example:
you have imported something accidentally and didn't noticed that
one of your dependencies is really big and you should avoid using it
you accidentally imported whole library when you just wanted to import single function from that library (that is common with lodash)
Here is an example of how you can add bundle analyzer to your webpack config:
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const isBundleAnalyze = true; // turn it too true only when you want to analyze your bundle, should be false by default
module.exports = {
// ... rest webpack config here
plugins: [
// ... rest webpack plugins here
...isBundleAnalyze ? [ new BundleAnalyzerPlugin() ] : []
]
};
Also check your final js file.
It should be a single line of code with simple variables. Something like this: !function(e){function t(t){for(var n,r,o=t[0],i=t[1],s=0,l=[];s<o.length;s++) if it doesn't looks like that it means that you configured your production webpack build incorrectly.
It's pretty obvious why your bundle is over 400kb, you are importing lodash and jquery, you are just missing moment.js (a little joke), but one thing that you can do is use only what you need.
First, if you are using Vue, or React, or any of those jQuery UI libraries you shouldn't be using jQuery unless is necessary.
Another thing that you can do is import only what you need, instead of:
import { map } from 'lodash';
try
import map from 'lodash/map';
or even better
import map from 'lodash.map';
https://www.npmjs.com/package/lodash.map
Lazy imports, read more here. This will allow splitting your bundle into pieces that can be called at execution time, reducing considerably your app size.
const Foo = () => import('./Foo.vue')
There is also SSR (Server Side Rendering), which is basically generating the initial HTML code of your app at build time and rendering outputting that, to show the users that something is on the site, but you also need to understand that, this won't do much, since the browser needs to parse the Javascript code (the hydration process) in order to make the site functional.
If you are using React as of April 2021, the React team announced React Server Components, which seems like a big thing coming up, I supposed that many other libraries will be moving components to the server (and I hope Vue does).
Again as of today don't use it on production.
Other answers mentioned the use of webpack-bundle-analyzer, here is a trick how to use it:
webpack.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const analyzing = process.env.NODE_ENV === 'analyze';
module.exports = {
plugin: [
...(analyzing ? [new BundleAnalyzerPlugin()] : [])
]
}
on your package.json
{
"scripts": {
"analyze": "NODE_ENV=analyze webpack build"
}
}
use CompressionWebpackPlugin and try gzip

Map object in React Native

I am new in React Native. Right now, I am studying Props and State. I wanted to try the FlatList Component in this doc https://facebook.github.io/react-native/docs/flatlist. However, I am getting this error.
You're using typed JavaScript known as Type script.
If you want to use TypeScript (I highly encourage it, then you can do so by following below tutorial):
Migrating to TypeScript:
https://facebook.github.io/react-native/blog/2018/05/07/using-typescript-with-react-native
To just get rid of the error!
state = {selected : (new Map())};
TypeScript Migration Continued...
Adding TypeScript
The next step is to add TypeScript to your project. The following commands will:
add TypeScript to your project
add React Native TypeScript Transformer to your project
initialize an empty TypeScript config file, which we'll configure next
add an empty React Native TypeScript Transformer config file, which we'll - configure next
adds typings for React and React Native
Okay, let's go ahead and run these.
yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react
touch rn-cli.config.js
yarn add --dev #types/react #types/react-native
The tsconfig.json file contains all the settings for the TypeScript compiler. The defaults created by the command above are mostly fine, but open the file and uncomment the following line:
{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}
The rn-cli.config.js contains the settings for the React Native TypeScript Transformer. Open it and add the following:
module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};
Migrating to TypeScript
Rename the generated App.js and __tests_/App.js files to App.tsx. index.js needs to use the .js extension. All new files should use the .tsx extension (or .ts if the file doesn't contain any JSX).
If you tried to run the app now, you'd get an error like object prototype may only be an object or null. This is caused by a failure to import the default export from React as well as a named export on the same line. Open App.tsx and modify the import at the top of the file:
-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';
Some of this has to do with differences in how Babel and TypeScript interoperate with CommonJS modules. In the future, the two will stabilize on the same behaviour.
At this point, you should be able to run the React Native app.