A node.js module of mine got too big, so I split it into several smaller (sub)modules.
I copy & pasted all relevant objects into each of the submodules, which now look like
var SOME_CONSTANT = 10;
function my_func() { etc... };
Now I want to export everything in each submodule, en masse, without having to explicitly say exports.SOME_CONSTANT = SOME_CONSTANT a million times (I find that both ugly and error prone).
What is the best way to achieve this?
I assume you do not want to export every local variable.
I will get around to automating this one of these days, but for now I often use this technique.
var x1 = { shouldExport: true } ;
// create a macro in your favorite editor to search and replace so that
x1.name = value ; // instead of var name = value
and
name becomes x1.name
// main body of module
for ( var i in x1) { exports.better_longer_name[i] = x1[i] ;}
//or if you want to add all directly to the export scope
for ( var i in x1) { exports[i] = x1[i] ; }
module.exports = {
SOME_CONSTANT_0 : SOME_CONSTANT_1 ,
SOME_CONSTANT_1 : SOME_CONSTANT_2 ,
SOME_CONSTANT_2 : SOME_CONSTANT_3
}
so why you need that "million" constant to exports?
Related
I need help with my project. I am creating CLI game with Node.js using ESM (not CJS).
In my randomHealth.js file, I have a function that generates a random number:
let randomHealth = () => {
return Math.floor(Math.random() * 300 + 1)
}
export default randomHealth
In my stats.js file I need to import and display that number. However, I needs to be fixed there, because I need that same number in another file:
import random from "./random/random.js"
import randomHealth from "./random/randomHealth.js"
let stats = () => {
console.log("STATS")
let playerHealth = randomHealth()
console.log("Health - " + playerHealth)
}
export default stats
I stored it in a playerHealth variable because I need to take that one generated number.
Now, I need that variable in another file, fight.js to use it.
If I call randomHealth() it's just gonna generate a new number, and I need a number that was already generated in stats.js file.
How to get that number from stats.js to use it in fight.js ?
I tried exporting that variable and importing it in fight.js, but once I do console.log() it displays undefined. I tried many different things but none worked. It returns either undefined, either NaN either nothing. I also tried immediatelly storing it in a variable in randomHealth.js and then displaying it, but that didn't work either. If I do console.log in randomHealth.js then I need to do it again when I want to display it in another file and a double console.log displays undefined. And if I don't to console.log in randomHealth.js then it always regenerates a new random number and I need the number that gets displayed in stats.js to use in fight.js.
Any ideas ? This was just my idea, if there is an even better way of doing it that storing it in a varible in stats.js then by all means tell me.
Thanks in advance.
Your problem is that by calling randomHealth() every time, you redefine the health points. In order to patch it, I recommend that you store the values outside the function and export them.
stats.js :
import randomHealth from './randomHealth.js'
export var healthPlayer1 = randomHealth();
export var healthPlayer2 = randomHealth();
export var healthPlayer3 = randomHealth();
export let stats = () => {
console.log("STATS")
console.log("Player 1 - " + healthPlayer1)
console.log("Player 2 - " + healthPlayer2)
console.log("Player 3 - " + healthPlayer3)
}
main.js
import { stats } from './stats.js';
import { healthPlayer1, healthPlayer2, healthPlayer3 } from './stats.js';
stats();
// Player 1 - 211
// Player 2 - 98
// Player 3 - 240
console.log(healthPlayer1);// 211
console.log(healthPlayer2);// 98
console.log(healthPlayer3);// 240
Now you can just use the exported HP, maybe you should create functions that will modify the HP in the same script so you can centralize all related functions in the same script, making it more clean and easy to use.
Hope it helped you out
Try exporting the result of the randomHealth function:
const randomHealth = () => {
return Math.floor(Math.random() * 300 + 1)
}
export default randomHealth()
In my ReactJS application I am getting the mobile numbers as a string which I need to break and generate a link for them to be clickable on the mobile devices. But, instead I am getting [object Object], [object Object] as an output, whereas it should be xxxxx, xxxxx, ....
Also, I need to move this mobileNumbers function to a separate location where it can be accessed via multiple components.
For example: Currently this code is located in the Footer component and this code is also need on the Contact Us component.
...
function isEmpty(value) {
return ((value === undefined) || (value === null))
? ''
: value;
};
function mobileNumbers(value) {
const returning = [];
if(isEmpty(value))
{
var data = value.split(',');
data.map((number, index) => {
var trimed = number.trim();
returning.push(<NavLink to={`tel:${trimed}`} key={index}>{trimed}</NavLink>);
});
return returning.join(', ');
}
return '';
};
...
What am I doing wrong here?
Is there any way to create a separate file for the common constants / functions like this to be accessed when needed?
First question:
What am I doing wrong here?
The issue what you have is happening because of Array.prototype.join(). If creates a string at the end of the day. From the documentation:
The join() method creates and returns a new string by concatenating all of the elements in an array (or an array-like object), separated by commas or a specified separator string. If the array has only one item, then that item will be returned without using the separator.
Think about the following:
const navLinks = [{link:'randomlink'}, {link:'randomlink2'}];
console.log(navLinks.join(','))
If you would like to use concatenate with , then you can do similarly like this:
function mobileNumbers(value) {
if(isEmpty(value)) {
const data = value.split(',');
return data.map((number, index) => {
const trimed = number.trim();
return <NavLink to={`tel:${trimed}`} key={index}>{trimed}</NavLink>;
}).reduce((prev, curr) => [prev, ', ', curr]);
}
return [];
};
Then you need to use map() in JSX to make it work.
Second question:
Is there any way to create a separate file for the common constants / functions like this to be accessed when needed?
Usually what I do for constants is that I create in the src folder a file called Consts.js and put there as the following:
export default {
AppLogo: 'assets/logo_large.jpg',
AppTitle: 'Some app name',
RunFunction: function() { console.log(`I'm running`) }
}
Then simply import in a component when something is needed like:
import Consts from './Consts';
And using in render for example:
return <>
<h1>{Consts.AppTitle}</h1>
</>
Similarly you can call functions as well.
+1 suggestion:
Array.prototype.map() returns an array so you don't need to create one as you did earlier. From the documentation:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
I hope this helps!
Update: scroll to see my solution, can it be improved?
So I have this issue, I am building a word translator thats translates english to 'doggo', I have built this in vanilla JS but would like to do it React.
My object comes from firebase like this
dictionary = [
0: {
name: "paws",
paws: ["stumps", "toes beans"]
}
1: {
name: "fur",
fur: ["floof"]
}
2: {
name: "what"
what: ["wut"]
}
]
I then convert it to this format for easier access:
dictionary = {
what : ["wut"],
paws : ["stumps", "toe beans"],
fur : ["floof"]
}
Then, I have two text-area inputs one of which takes input and I would like the other one to output the corresponding translation. Currently I am just logging it to the console.
This works fine to output the array of the corresponding word, next I have another variable which I call 'levelOfDerp' which is basically a number between 0 - 2 (set to 0 by default) which I can throw on the end of the console.log() as follows to correspond to the word within the array that gets output.
dictionary.map(item => {
console.log(item[evt.target.value][levelOfDerp]);
});
When I do this I get a "TypeError: Cannot read property '0' of undefined". I am trying to figure out how to get past this error and perform the translation in real-time as the user types.
Here is the code from the vanilla js which performs the translation on a click event and everything at once. Not what I am trying to achieve here but I added it for clarity.
function convertText(event) {
event.preventDefault();
let text = inputForm.value.toLowerCase().trim();
let array = text.split(/,?\s+/);
array.forEach(word => {
if (dictionary[word] === undefined) {
outputForm.innerHTML += `${word} `;
noTranslationArr.push(word);
} else {
let output = dictionary[word][levelOfDerp];
if (output === undefined) {
output = dictionary[word][1];
if (output === undefined) {
output = dictionary[word][0];
}
}
outputForm.innerHTML += `${output} `;
hashtagArr.push(output);
}
});
addData(noTranslationArr);
}
Also here is a link to the translator in vanilla js to get a better idea of the project https://darrencarlin.github.io/DoggoSpk/
Solution, but could be better..
I found a solution but I just feel this code is going against the reason to use react in the first place.. My main concern is that I am declaring variables to store strings inside of an array within the function (on every keystroke) which I haven't really done in React, I feel this is going against best practice?
translate = evt => {
// Converting the firebase object
const dict = this.state.dictionary;
let dictCopy = Object.assign(
{},
...dict.map(item => ({ [item["name"]]: item }))
);
let text = evt.target.value.toLowerCase().trim();
let textArr = text.split(/,?\s+/);
let translation = "";
textArr.forEach(word => {
if (dictCopy[word] === undefined) {
translation += `${word} `;
} else {
translation += dictCopy[word][word][this.state.derpLvl];
}
});
this.setState({ translation });
};
levelOfDerp is not defined, try to use 'levelOfDerp' as string with quotes.
let output = dictionary[word]['levelOfDerp' ];
The problem happens because setState() is asynchronous, so by the time it's executed your evt.target.value reference might not be there anymore. The solution is, as you stated, to store that reference into a variable.
Maybe consider writing another function that handles the object conversion and store it in a variable, because as is, you're doing the conversion everytime the user inputs something.
I am working on the stencil platform on big commerce. this platform uses the handlebars syntax. I need to be able to set a value based on one of the parameters in my URL, more that like the 'window.location.pathname', and i need to be able to access this new variable across the site. I am able to make something work two different ways using regular JavaScript, but i do not want to recreate my script in every place throughout the site. So basically, I could use some help getting one of my 2 vanilla scripts into a handlebars for formatting. What i have that works is shown below:
<p id="BrandLogo"></p>
<script>
var directory = window.location.pathname;
var branding;
var str = directory.includes("blackvue");
if (str === false) {
branding = value one;
} else {
branding = value 2
}
document.getElementById("BrandLogo").innerHTML = branding;
</script>
or
<p id="BrandLogo"></p>
<script>
var directory = window.location.pathname;
var branding;
if (str == '/URL-I-Want-To-Focus-On/') {
branding = value one;
} else {
branding = value 2
}
document.getElementById("BrandLogo").innerHTML = branding;
</script>
Thanks in advance
If you are trying to set and use a local variable within handlebars try something like this:
First, create a helper function named 'setVar':
var handlebars = require('handlebars');
handlebars.registerHelper("setVar", function(varName, varValue, options) {
options.data.root[varName] = varValue;
});
Next, set your variable(s) using the function you created in the first step.
{{setVar "greeting" "Hello World!"}}
{{#if some-condition}}
{{setVar "branding" "Value one"}}
{{else}}
{{setVar "branding" "Value 2"}}
{{/if}}
Finally, use the variable(s) on your page:
<div>
<h1 id="BrandLogo">{{greeting}}</h1>
</div>
document.getElementById("BrandLogo").innerHTML = {{branding}};
If you are trying to add a serial number inside a nested 'each' or based on a condition inside nested each following helper works good:
hbs.registerHelper('serialNo', function (options) {
var currentSerialNo = options.data.root['serialNo'];
console.log("############Current serial No is:"+currentSerialNo);
if (currentSerialNo === undefined) {
currentSerialNo = 1;
} else {
currentSerialNo++;
}
options.data.root['serialNo'] = currentSerialNo;
return currentSerialNo;
});
Now inside your template you can simply use it like:
{{serialNo}}
Everytime {{serialNo}} is encountered it prints a serial number one greater than before.
I want to refactor Snippet 1 to Snippet 2. I don't think performance is quite an issue here considering the size, but I wanted to understand what was going on as far as memory use goes regarding this refactor to the module pattern.
The module pattern ensures that I only pull in this data from the DOM once which is what I want and it also forms a mini-registry pattern in that the data is private.
Both snippets have been tested and basically work.
Snippet 1 // Replace SUniverisals w/ SU
var SUniversals = function () {
// Pull from Server
this.universals.path = document.getElementById('universals').getAttribute('data-path');
this.universals.load = document.getElementById('universals').getAttribute('data-load');
// Set Manually
this.universals.debug = false;
};
SUniversals.prototype.universals = {};
SUniversals.prototype.get = function( key ) {
return this.universals[ key ];
};
SUniversals.prototype.set = function( key, value ) {
this.universals[ key ] = value;
};
Snippet 2
var SU = ( function ()
{
// private SU.get('load');
var universals = {};
universals.path = document.getElementById('universals').getAttribute('data-path');
universals.load = document.getElementById('universals').getAttribute('data-load');
universals.debug = false;
// pubulic
var publik = {};
publik.get = function( key )
{
return universals[ key ];
};
publik.set = function( key, value )
{
universals[ key ] = value;
};
return publik;
}());
There are few things which are different. Snippet 2 is essentially creating a singleton. Snippet 1 can be looked at like a 'class'. You can create multiple instances/objects of 'SUniversals' and do different things with them.
Actually, snippet 1 is more efficient in terms of memory. By adding to the object's prototype, you essentially will have only 1 copy of each function irrespective of the number of objects you create. The module pattern will create separate entities.
Not enough to worry about ;-)
Seriously, the only thing you need to worry about with the module pattern is creating memory leaks; by itself the pattern uses basically nothing.