React Native - `require()` statement exception handling - javascript

TL;DR: I want to be able to require a module in react-native and handle the exception myself in case the module does not exist (instead of displaying the RedBox).
I am using moment.js's logic to choose the most suitable locale from its library of presets (https://github.com/moment/moment/tree/develop/locale), when given a requested locale.
For example, if asked for en-us, and it was not found, it will fall back to en and so forth. The code for this logic (chooseLocale, loadLocale) can be found here: https://github.com/moment/moment/blob/develop/src/lib/locale/locales.js
Basically, it tries to require the given preset. If it does not exist, it gets en exception from the require statement, catches it and moves on to the next option.
Now, my issue is trying to use this logic with react-native. The require statement is actually implemented with react-native's guardedLoadModule which handles the exception (displays red screen). In my opinion, moment's logic is not hurt by this logic, hence I would like for the RedBox to not display.
Any thoughts?

This is now possible (link to discussion):
Optional dependency is released in metro 0.59
Simply surround your code with try catch:
let module;
try {
module = require('module');
} catch {
...
}

React-native's require is different from node.js's require in the sense that the app is bundled and packaged before the application runs. As a consequence it is not possible to perform dynamic require statements. See also this github issue.
Check the following github issue on react-native, as it includes a "solution" to your problem. https://github.com/facebook/react-native/issues/1629
In other words: you will have to implement the fallback mechanism yourself, and explictely tell moment which locale to use.
switch deviceLocale:
case 'es':
require('moment/locale/es');
break;
case 'he':
require('moment/locale/he');
break;

Related

NodeJS - Dynamically import built in modules

I'd like to get a built in module (for example Math or path or fs), whether from the global object or require, I thought about doing something like this:
function getModuleByName(name) {
return global[name] || require(name);
}
Is there a way to check that it is indeed a module and not something else? Would this make a security problem?
Is there a way to check that it is indeed a module and not something else?
Other methods but here's an example:
function getModuleByName(name)
{
let module = null;
try {
module = require(name);
} catch (e) {
// Recommend Logging e Somewhere
}
return module;
}
This will graciously fail as null where the module does not exist, or return it.
Would this make a security problem?
Quite possibly, it depends on how it's used. I'd argue it is more of a general design issue however and would blanket say avoid doing it (without any context, you may have a very good reason).
You, like anyone, obviously have a finite amount of modules you could be loading. These modules have all been selected by yourself for your application for specific reasons, or are bundled into your node version natively and are expected parts of your environment.
What you are doing by introducing this functionality is adding the addition of unexpected elements in your environment. If you are using getModuleByName to access a third party library- you should know outright that library is available and as such there's no reason why you can't just require it directly.
--
If you do think your use case warrants this, please let me know what it is as I may never have encountered it before. I have used dynamic imports like the following:
https://javascript.info/modules-dynamic-imports
But that hasn't been for global packages/libraries, but for dynamic reference to modules built internally to the application (i.e. routing to different views, invokation of internal scripts).
These I have protected by ensuring filepaths can't be altered by whitelisting the target directories, making sure each script follows a strict interface per use case and graciously failing where a module doesn't exist (error output "this script does not exist" for the script usage and a 404 view for the routing example).

How can I enable references in WebAssembly with SpiderMonkey?

I try to use the experimental AnyRef in WebAssembly with the JavaScript engine SpiderMonkey. I receive the follow error:
CompileError: wasm validation error: at offset 40: reference types not enabled
I try to enable it with the command line parameter --wasm-gc but without luck. Any idea how I can do it?
I call it like:
js --wasm-gc test.js
Using anyref is a little tricky at the moment because the feature is in an inbetween state; it'll "just work" once we land some of the missing pieces.
Currently you need not only the command line switch but also an explicit opt-in in the module itself.
In the text mode (if you're using the built-in wasmTextToBinary function in the SpiderMonkey shell) you must have a custom section at the beginning of the module that looks like this:
(gc_feature_opt_in 1)
If you're generating binary code, the encoding is documented here: https://github.com/lars-t-hansen/moz-gc-experiments/blob/master/version1.md

How to resolve Flowtype error with React Native out of the box?

I am preparing to use React Native for a company project. However, flowtype is giving me error out of the box, and the errors come from react-native library (and some other libraries), so I have little to no control over. The errors are about some type definitions not accessible, and there are about 200 of them.
I only use the standard .flowconfig as follow
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "#providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
.*/Libraries/react-native/ReactNative.js
and it already includes some ignore modules.
I also notice that flow is very unstable, i.e. initially it reports no errors, and then, without no to little code change, it reports hundreds of errors from elsewhere where the code change does not happen (no extra libraries installed or imported).
The first question is, how can I avoid these errors and make flow output more meaningful for development.
The second and more general question is what is the convention for using flow.
If you find this question too general or misleading, please comment so I can make it better, because I am just as confused.
I am using
- React Native 0.44
- React 16.0.0-alpha-6
- Flow 0.46.0

When using ES6 import statement, is there a way to protect against items being undefined?

import {
foobar1,
foobar2,
foobor3, //typo! this key doesn't exist in the module.
} from './module_file.js'
console.log(foobar1, foobar2, foobar3) //EXPLODES
One of the most frequent silly mistakes I make when using the new ES6 style import statement is that I'll have a typo in one of the keys in object destructuring. I can't think of a single instance where I'd ever want a value in a destructuring assignment to be undefined. Is there any way to force the import statement to fail-fast if one of the items I'm trying to import is undefined?
ie:
import {
doesntExistInModule //EXPLODE NOW! 🔥🔥🔥
} from './module_file.js'
There is no hook allowing a module to run some code before its dependencies load. This means that modules have no control over how
their dependencies are loaded.
There is no error recovery for import errors. An app may have hundreds of modules in it, and if anything fails to load or link,
nothing runs. You can’t import in a try/catch block. (The upside here
is that because the system is so static, webpack can detect those
errors for you at compile time.)
For more details, read it out
The module stuff in the spec is pretty gnarly, but I believe a real implementation will throw a SyntaxError at 15.2.1.16.4 ModuleDeclarationInstantiation( ) Concrete Method step 12.d.iii in that case. Since there are no legit implementations I don't know if you're talking about a way to do it in transpiled code in the meantime, or if you don't realize that's the case and will be satisfied to know it'll work that way eventually. There's been talk before of trying to implement that kind of check in Babel, but as far as I know nothing's actually been done to that effect. Babel compiles each module in isolation.
Also, this is not object destructuring, it just has similar syntax.

What does the "!" character do in nodejs module names?

I've started using the intern library to write functional tests in js, and I realized that I couldn't understand this syntax:
var assert = require('intern/chai!assert');
var registerSuite = require('intern!object');
What is the purpose of the ! character in the argument of the require() method?
Short answer
It identifies a resource that is part of a plugin.
The structure of the identifier is: [plugin]![resource].
Long answer
In the documentation, you can find that:
Intern is built on top of a standard amd loader, which means that its modules are also normally written in the AMD module format.
That's why and how the require function is actually injected, so it's clear that you are not using the require module provided along with Node.JS.
It states also that:
[AMD format] Allows modules and other assets to be asynchronously or conditionally resolved by writing simple loader plugins
If you follow the link provided with the documentation when it cites the loaders, you find that:
Loader plugins extend an AMD implementation by allowing loading of resources that are not traditional JavaScript dependencies.
In particular, you can find that a dependency has the following form:
[Plugin Module ID]![resource ID]
It goes without saying that the default implementation of the loader you get by using intern adheres to the above mentioned standard.
That said, it follows that, if we consider:
intern/chai!assert
You can read it as inter/chai as plugin module and assert as actually required resource.
The purpose of the ! character in the argument of the require() method is to satisfy the requirements of the syntax used to identify a resource that is itself part of a plugin.
I got this answer for you extracted from this similiar question and very well explained by explunit:
The exclamation point syntax is reserved for plugins. Typically there would be something else following the exclamation point which indicates the resource that the plugin would load, e.g. text!myTemplate.html, but in the case of domReady! the plugin exists just as a way to wait until DOM loaded before invoking your callback function, so nothing needs to follow the exclamation point.

Categories

Resources