Require , how to do a fallback when module does not exist - javascript

I have an application where I need to require a file that may or may not be available. If the file is not available, I need to check for another file. and the third option will be default. So far I have this
const file = require('./locales/${test1}') || require('./locales/${test2}') || require('./locales/default')
But it gives me error saying cannot find module. How do I do it optimally?
I did try https://www.npmjs.com/package/node-require-fallback but it does not seem to work in spite of my node version being OK
const messages = require('./locales/${test1}') works well but
const messages = requireIfExists('./locales/${test1}', './locales/${test2}') FAILS

In a vanilla node app, you can use a try-catch block:
var module;
try {
module = require(`./locales/${test1}`);
} catch(error) {
// Do something as a fallback. For example:
module = require('./locales/default');
}
}

Using try/except, you can implement a function that replicates requireIfExists on your own.
function requireIfExists(...modules) {
for (let module of modules) {
try {
return require(module);
} catch (error) {
// pass and try next file
}
}
throw('None of the provided modules exist.')
}
Also, make sure you are using the ` character instead of quotes when using template strings.

Related

TypeError [EMOJI_TYPE]: Emoji must be a string or GuildEmoji/ReactionEmoji

so in my module.js, I put
function emoji(e) {
return client.emojis.cache.find(emoji => emoji.name === e)
}
module.exports = {
emoji
}
and in index,js, I put
const module = require("./module.js")
msg.react(module.emoji('check'))
So what I'm making is that I want the bot to react with a custom emoji I uploaded named 'check'. In case I could use this in the future, I decided to make a function so that the bot(client) can find emoji easily without me copy/pasting "client.emojis.find(emoji => emoji.name === blabla)" everytime when needed.
But when I run it, the console says
TypeError [EMOJI_TYPE]: Emoji must be a string or GuildEmoji/ReactionEmoji
The reason why I'm posting this is because when I put that function block into index.js, it works perfectly. But when I put it into module.js and use it by module exporting, the error occurs as I mentioned.
Can anyone tell me what I missed?
I havent tested this, but i have a few things I think you should try:
What Elitezen suggested, which is specifically requiring the emoji function from the module:
const { emoji } = require("./module")
what would also probably work is just to do
module.exports = emoji //instead of module.exports = { emoji }
^^ this means it only exports the emoji function, instead of exporting a dictionary containing the function.
After my edits, your full code would look like this:
function emoji(e, client) {
return client.emojis.cache.find(emoji => emoji.name === e)
}
module.exports = emoji
const module = require("./module.js")
msg.react(module('check', client))

How to use multiple js files with Duktape?

I'm using Duktape in embedded MCU. For test case i have:
main.js file:
(function(){
test();
})();
test.js file:
(function test(){
print("func");
})
Both compiled as global default code and main.js is executed with duk_call(ctx, 0);
The problem is it throws error when calling a test() function.
I've also tried using just
function test() {
print("test");
}
in test.js code, but it does not work either.
What I understand is that both files have separate execution context. That is why function is inaccessible.
But what is the right way to split code into multiple files for Duktape?
P.S. I am aiming to avoid using global context, because in documentation it is said that accessing variables is slow this way, that's why main.js looks that way.
P.P.S. I'm sure that test() function is unreachable, but I don't know how to write js code so that everything works.
P.P.P.S print() is a C function that outputs to serial port of esp32 and it works. even main.js works without a test() function call.
Basically, what you want is file import functionality. You can implement that in two ways:
Provide a function in your backend and export that to JS, to allow loading a file dynamically at runtime.
Implement module handling like in Node.js (which essentially also boils down to an import function).
The second idea is what is used most and implements a well defined approach to include other files in your JS application. Duktape comes with an extra file that implements the require command, just like in Node.js. You only have to provide your own functions for resolving a module and to load it from disk (as duktape has not file I/O support).
I implemented this approach in the MGA tool in MySQL Workbench. The duktape file for implementing node module handling is here. The function to resolve modules (which includes handling of nested node_modules folders etc.) is implemented in the ScriptingContext class. The relevant part of it is this:
/**
* Part of the module loading machinery. JS interfacing is done by the duk_module_node code.
* But we have to do the file work here. On the stack we get the value passed to `require()` as a "module ID" and
* the ID of the calling script (which is empty for the main script).
*/
duk_ret_t ScriptingContext::resolveModule(duk_context *ctx) {
// stack: [ requested_id parent_id ]
std::string requestedID = duk_get_string(ctx, 0);
std::string callingID = duk_get_string(ctx, 1);
std::string parentPath = FS::isDir(callingID) ? callingID : Path::dirname(callingID);
// Module resolution strategy in Node.js style: https://nodejs.org/api/modules.html#modules_all_together
auto modules = getInternalModules();
if (modules.find(requestedID) != modules.end()) {
duk_push_string(ctx, requestedID.c_str());
return 1;
}
ScriptingContext *context = ScriptingContext::fromDuktapeContext(ctx);
std::string resolvedID;
std::string cwd = Process::cwd();
try {
if (Path::isAbsolute(requestedID) || Utilities::hasPrefix(requestedID, ".")) {
std::string temp;
if (Path::isAbsolute(requestedID)) {
temp = Path::relative(cwd, requestedID);
} else
temp = Path::join({ parentPath, requestedID });
resolvedID = resolveFile(temp);
if (resolvedID.empty())
resolvedID = resolveFolder(context, temp);
}
} catch (std::runtime_error &e) {
// Triggered for parse errors in package.json.
context->throwScriptingError(ScriptingError::Syntax, e.what());
return 0;
}
// No files found so far. Check node modules.
if (resolvedID.empty()) {
for (auto &folder : moduleFolders(parentPath)) {
std::string path = Path::join({ folder, requestedID });
std::string temp = resolveFile(path);
if (!temp.empty()) {
resolvedID = temp;
break;
}
temp = resolveFolder(context, path);
if (!temp.empty()) {
resolvedID = temp;
break;
}
}
}
if (resolvedID.empty()) {
context->throwScriptingError(ScriptingError::Error, Utilities::format("Cannot resolve module %s", requestedID.c_str()));
return 0;
}
duk_push_string(ctx, resolvedID.c_str());
return 1; // Use result on stack.
}

Hijacking node require even when spawning another script

I am trying to replace a specific package using
import Module from 'module';
const {require: oldRequire} = Module.prototype;
Module.prototype.require = function twilioRequire(file) {
if (file === 'the-package-of-interest) {
// return something else
}
return oldRequire.apply(this, arguments);
};
const p = require('the-package-of-interest');
// this gives me the replacement
This would work fine, but if this was placed inside a script that spawns another script, this does not work in the other script, i.e
// main.js
import Module from 'module';
import spawn from 'cross-spawn';
const {require: oldRequire} = Module.prototype;
Module.prototype.require = function twilioRequire(file) {
if (file === 'the-package-of-interest) {
// return something else
}
return oldRequire.apply(this, arguments);
};
spawn.sync('node', ['/path/to/another/script.js'], { stdio: "inherit" });
// another/script.js
require('the-package-of-interest');
// gives the original package, not the replacement
I don't suppose there is a way to spawn another script, but keep the hijacked require scope the same?
Even though mocking libraries are usually used in tests, this might be a good situation to stub another library or file you wrote with another one based on a configuration.
There are a lot of mocking libraries for node, and there's a good article which covers some of them.
The library it recommends is pretty good but you can use whatever you want to do this
Create a mock definitions file that replaces that import with the second file
First - define your mocks. You can do it in any place, this is just a setup.
Easiest way is to do this in the same file, but you can create a mock defitions file if you like
import rewiremock from 'rewiremock';
...
// by mocking the module library, you actually replace it everywhere
rewiremock('module')
.with(otherModule);
your other module need to have the same export for this to work and act with the same interface.
Replace the library based on a variable
To use, you need some sort of condition that will select if to use the original library or the second one
// This is only needed if you put the mock definitions in another file
// Just put the rest of the code under the previous snippter
// if everything is in the same file
require('<your_rewiremock_definitions_file>');
if (replaceImport) {
rewiremock.enable();
}
// run the code here
if (replaceImport) {
rewiremock.disabled();
}
Your module should be replaced everywhere by the second module.
You can use any other mocking library to do this. there's a short section at the start of the readme with different options if you want a different style or another library.
rewiremock works by replacing the node.js cache so it should change the dependency everywhere.

Check if a dependency exists with webpack

Often I need to check if a dependency exists in webpack. For example, I have a bunch of ids like [0,1,3,4,5,6,7,8,...] and some of them have an image I should load while others don't.
How I check that an image should be loaded is by creating an array that contains the values that have an image and just do an array.contains when checking that the image should be loaded. Like [1,5,7,...].
This is starting to be quite problematic because I need to change this array every time I add or remove images.
Is there a way to check if the module I want to require exists or not?
As far as I see there was a way in Webpack 1 but that go closed.
https://github.com/webpack/webpack/issues/526
I found that it should still work like this according to the documentation (https://webpack.js.org/api/module-methods/#require-resolveweak) but I do get Error: Cannot find module.
This is what I'm doing exactly:
$scope.getExplorationImage = function (imageId) {
if(__webpack_modules__[require.resolveWeak('image/exploration/' + imageId + '.png')]) {
console.log("Image exists for: "+imageId)
return require('image/exploration/' + imageId + '.png');
} else {
console.log("Image doesn't exists: "+imageId)
}
};
I'm using Webpack 3.5.5. I want to avoid the try/catch solution if possible.
I know the question states
I want to avoid the try/catch solution if possible.
However, if someone comes by here trying to get webpack not to crash while testing if module exists, here is what works:
// try if module exists
try {
var module = require('../path/to/module');
}
// fallback if does not exists
catch(err) {
var module = require('../path/to/fallback/module');
}
You will still get an error printed in the console, but webpack won't crash the application and correctly fallback to module provided in the catch{};
what you did is the way but it only checks if that module was already loaded, you need to turn it into an async function if you want to check if that module is available.
have a look here: https://github.com/webpack/webpack/issues/526
you can write a function to simplyfy everything:
function moduleExists(moduleId) {
return new Promise((resolve, reject) => {
// check if that module was already loaded
if(__webpack_modules__[require.resolveWeak(moduleId)]) {
return resolve();
}
return import(moduleId)
.then(() => resolve(), () => reject())
;
});
}
moduleExists('foobaz' /* take care of absolute paths */ )
.then(() => alert('yes'))
.catch(() => alert('noope'))
;
const exists = await moduleExists('bar');
if(exists) { /* do stuff */ }
import(/* webpackIgnore: true */ 'ignored-module.js');
https://webpack.js.org/api/module-methods/#magic-comments

JS modules: How implement sort of an interface?

I'm working with JS modules bundled with Webpack.
Suppose I have a common module, used everywhere. This module require another module, let's say it is an output for errors
var err = require("./errors.js");
var common = {
doSomething: function() {
var a = 1;
if (a == 1) {
err.output('An error occured');
}
}
}
module.exports = common;
Now this error management module could be somthing like
var $ = require("jquery");
var errors = {
output: function(msg) {
$('<div class="someClass">'+msg+'</div>).appendTo('body');
}
}
module.exports = errors;
And finally I have my entry point:
var common = require("./common.js");
common.doSomething();
My question is: since I have got two applications, let's call them backend and frontend, I would like different implementation of errors.output, because it's view-bounded. Maybe in backend I want to use a class different from "someClass", or maybe I don't want to use a DIV, but a P, or else.
I have multi entry points, actually. So I wouldn't like to have each of them passing around lots of callbacks or configuration. I would like to have only one implementation of errors module for all the entry point of the backend and only one for all the entry point of the frontend, without any code repetition.
This is something that I would implement with interface, in PHP.
Which is the best approach for Javascript?
Thank you

Categories

Resources