Using require('...') with a variable vs. using a string in webpack - javascript

I have a problem that doesn't make much sense to me.
I'm mapping an array of objects that have a "name" and a "href" property.
let appleIcons = _.map(appleIcons, appleIcon => {
appleIcon.href = require(appleIcon.href);
return appleIcon;
});
Inside of the loop I want to require the image but it throws an error ".*$:11 Uncaught Error: Cannot find module".
When I print the value of appleIcon.href and i try to put it directly into the require('') it works.
appleIcons = _.map(appleIcons, appleIcon => {
appleIcon.href = require('./../../mobile-config/apple-icon-57x57.png');
return appleIcon;
});
So can you explain me why the second example works and the first one throws an error? How do i put a variable inside of require('')?
Thanks!

Since Webpack is running in build-time, it can't figure out which modules to bundle when the name is a dynamic variable. You can give it hints by specifying part of the path (for example, if you know all the modules are in a single directory).
This answer can help:
https://stackoverflow.com/a/33048000
(Also check require.context by Webpack. Another example is karma tests, here.)
Alternatively - if you know the filenames in advanced, it's better to add another build step to output them a strings to the file, that way Webpack can bundle them.

Adding an empty string fixed the problem for me. So, below code should work:
let appleIcons = _.map(appleIcons, appleIcon => {
appleIcon.href = require('' + appleIcon.href);
return appleIcon;
});

Related

Change syntax for protractor step definitions from promises to async syntax

I have a protractor-cucumber framework whose step definitions are somewhat structured as per this: https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/step_definitions.md
I use a return and chain the promises together. Recently, I came across a different syntax called the async function. But, when I try to convert my step definitions to async, all the help files in the framework where I use say module.exports and require() display the following warning:
[ts] File is a CommonJS module; it may be converted to an ES6 module.
When I run test cases since I can't access these helper files due to the error my tests cases fail. Like, my page object files, I am not able to access them from my tests. I think they don't get exported like they used to.
Could someone please advice me as to how I can change my test cases to async syntax without breaking them? How do I resolve the above issue without disrupting my tests in a major way.
Adding code
Here is a step from my step definition before the change
let { Given, Then, When } = require('cucumber');
Given(/^I am on the "([^"]*)" page$/, function (home) {
home = this.url.FDI_HOME;
return browser.get(home);
});
Here is a step definition, after I change it to an async function
let { Given, Then, When } = require('cucumber');
Given(/^I am on the "([^"]*)" page$/, async function (home) {
home = this.url.HOME
await browser.get(home);
});
And I will change my other steps in similar fashion. Problem arises when I try to run the above step it fails saying that it is not able to access this.url.HOME. I have another file to supply URLs called the urls.js looks something like this
let targetStore = browser.params.store || 'bestbuy';
let FDI_HOST = browser.params.fdi;
module.exports = {
HOME Page: 'https://homepage.com',
Shop_Page: 'https://shop.com',
storeLink: `http://www.${targetStore}.com`,
};
I see three dots under the word "module.exports" in VS code and when I hover over it, it displays an error saying: [ts] File is a CommonJS module; it may be converted to an ES6 module.
I have tried to find a resolution to this but not been able to successfully make it. if I use the syntax as "async()=>{}" the test cases fails but when I use "async function(){}" then a few of the steps pass but not the other.
These are suggestions/hints. They visually indicate that vscode can perform an action to possibly refactor/improve your code, but they are not treated as errors.
You can disable them by adding "javascript.suggestionActions.enabled": false to your user/workspace settings.
Source: https://github.com/Microsoft/vscode/issues/47299

NodeJS - Can I detect when called from command line (ES6 + Babel)..?

In my module I need to detect when it's being called from either the command line, or from another module.
const isFromCLI = '????'
I'm using Babel/ES6, so when called from a command line, index.js is called (with the babel code), which hands off to script.js (with ES6 code). So from the script file, module.parent returns module (the index.js file). So I can't use module.parent!
Also, module.main is undefined (in script.js) when called from either the command line or from another module. So I can't use module.main!
Those are the two solutions that others are suggesting, but they don't work for me.
Is there a simple to detect this when using Babel/ES6..?
Update
require.main returns module when called from either the command line or from another module.
You could use Process in Node.
https://nodejs.org/api/process.html#process_process_argv
Check the value of the second parameter (do a contains type match). Not sure if this is the only way but it's a straight forward way to achieve what you need
A code snippet might be:
const isFromCLI = (process.argv[1].indexOf('my-script.js') !== -1);
You can use Node Environment Variables.
You can set an environment variable like this:
CLI=true node app.js
and then get the environment variable like this:
const isFromCLI = process.env.CLI === 'true'
Note: process.env.CLI will be a string.
Update:
If you want to do something like node app.js --cli, you can do the following:
let isFromCLI
process.argv.forEach(function (val, index, array) {
if (array[index] === '--cli') {
isFromCLI = true
}
})
console.log(isFromCLI)

ES6 Modules - Global Variables

I was trying to create a quick pub-sub system based out of localStorage. The process made me realize that my understanding of how ES6 modules work is incomplete.
const subscribers = {};
export default {
subscribe (key, callback) {
if (!Array.isArray(subscribers[key])) {
subscribers[key] = [callback];
} else {
subscribers[key] = [...subscribers[key], callback];
}
},
publish (key, value) {
window.localStorage[key] = value;
subscribers[key].forEach(cb => cb(value));
}
};
I imported this module whenever I wanted to subscribe/publish to a key in localStorage. The problem is that the subscribers object gets reinitialized everytime the module is imported.
Is there a way to do retain the subscribers object without polluting window? I assumed that the import statement will only execute the file once only for the first time it is imported.
Thanks.
This is an oversight at my end.
I made a typo when importing this module (capitalization), I specified the wrong filename.
There is another module with an equal name when case is ignored. This
can lead to unexpected behavior when compiling on a filesystem with
other case-semantic. Rename module if multiple modules are expected or
use equal casing if one module is expected.
This caused the module to reinitialize.
Please correct me if I am wrong, but I believe a module will be only executed once for the entire application, when imported for the first time.
Thanks.

Can I export/require a module in Node.js to be used without a var holding its objects?

I am creating my own error library to have a custom catalog of specific and well documented errors to return on my API. I am doing something like this:
module.exports = CError;
function CError () {
}
// CUSTOM ERROR TYPES
CError.EmptyParamError = createErrorType(...);
CError.InvalidFormatError = createErrorType(...);
A sample of how I use my custom error types right now:
CError = require('cerror');
if(!passwd)
callback(new CError.EmptyParamError(passwd, ...));
I will use this errors through my entire project and I wish to have a cleaner code like this: (without the CError reference)
if(!passwd)
callback(new EmptyParamError(passwd, ...);
Is there a way to export the module or to require it that allows me to do this?
I googled without finding any answer, I also checked all this interface design patterns for Node.js modules but no one applies.
You can set it as a global, though as always when using globals, beware of the side-effects.
EmptyParamError = createErrorType(...);
That's it. Just leave off the var keyword, and don't set it as a property.
If it's only one or two types, you can skip the CError variable like this:
var EmptyParamError = require('cerror').EmptyParamError;
if(!passwd)
callback(new EmptyParamError(passwd, ...));
If you have multiple types in a single file, there will be multiple require('cerror') statements, but I believe there's no significant performance hit there because (if I understand correctly) Node will cache it the first time.

Nodejs: Global variables across multiple files

I have written my code across several files for my node server.
If I have a file, say basket.js:
var Basket = {
fruits : 0,
addFruit : function() {
fruits++;
},
removeFruit : function() {
fruits--;
},
printFruit : function() {
console.log(this.fruits);
}
}
module.export = Basket;
And I have another file called give.js:
var Basket1 = require("./basket.js");
Basket1.addFruit();
Basket1.printFruit();
And another file called take.js:
var Basket2 = require("./basket.js");
Basket2.removeFruit();
Basket2.printFruit();
Will both files write into the same instance of Basket?
In other words, will they both have control over the property, fruits?
Does node manage race conditions on its own? i.e. if two commands to modify fruit come in at the same time from add and sub, does node know how to handle it?
If I want to make a way in which two files can look at a singleton at the same time and access it, is this the way to go?? Or how else does one do it?
Yes, they will access the same object.
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
– Modules docs
No, node does not manage race conditions on its own, because race conditions will not be caused by node itself. Node is single-threaded and thus no code can be executed at the same time as other code. See for example this answer for some more explanation.
I'm a beginner but I think the correct syntax is module.exports not modules.export - if you may correct so that people don't wonder why it does not work like I just did :)

Categories

Resources