With these 7 upcoming built-in Set methods, we could find ourselves using them a LOT more often.
1. union()
The new Set union() method gives us all the unique items in both sets.
JavaScriptCopied!
const creation = new Set(['coding', 'writing', 'painting']);
const joy = new Set(['crying', 'laughing', 'coding']);
console.log(creation.union(joy));
// Set { 'coding', 'crying', 'writing', 'laughing', 'painting' }
And since it’s immutable and returns a copy, you can chain it indefinitely:
JavaScriptCopied!
const odd = new Set([21, 23, 25]);
const even = new Set([20, 22, 24]);
const prime = new Set([23, 29]);
console.log(odd.union(even).union(prime));
// Set(7) { 21, 23, 25, 20, 22, 24, 29 }
2. intersection()
What elements are in both sets?
JavaScriptCopied!
const mobile = new Set(['javascript', 'java', 'swift', 'dart']);
const backend = new Set(['php', 'python', 'javascript', 'java']);
const frontend = new Set(['javascript', 'dart']);
console.log(mobile.intersection(backend));
// Set { javascript, java }
console.log(mobile.intersection(backend).intersection(frontend));
// Set { javascript }
3. difference()
difference() does A – B to return all the elements in A that are not in B:
JavaScriptCopied!
const joy = new Set(['crying', 'laughing', 'coding']);
const pain = new Set(['crying', 'screaming', 'coding']);
console.log(joy.difference(pain));
// Set { 'laughing' }
4. symmetricDifference()
As symmetric implies, this method gets the set difference both ways. That’s (A – B) U (B – A).
All the items in 1 and only 1 of the sets:
JavaScriptCopied!
const joy = new Set(['crying', 'laughing', 'coding']);
const pain = new Set(['crying', 'screaming', 'coding']);
console.log(joy.symmetricDifference(pain));
// Set { 'laughing', 'screaming' }
5. isSubsetOf()
Purpose is clear: check if all elements of a set are in another set.
JavaScriptCopied!
const colors = new Set(['indigo', 'teal', 'cyan', 'violet']);
const purpleish = new Set(['indigo', 'violet']);
const secondary = new Set(['orange', 'green', 'violet']);
console.log(purpleish.isSubsetOf(colors)); // true
console.log(secondary.isSubsetOf(colors)); // false
console.log(colors.isSubsetOf(colors)); // true
6. isSupersetOf()
Check if one set contains all the elements in another set: As good as swapping the two sets in isSubsetOf():
JavaScriptCopied!
const colors = new Set(['salmon', 'cyan', 'yellow', 'aqua']);
const blueish = new Set(['cyan', 'aqua']);
const primary = new Set(['red', 'yellow', 'blue']);
console.log(colors.isSupersetOf(blueish)); // true
console.log(colors.isSupersetOf(primary)); // false
console.log(colors.isSupersetOf(colors)); // true
7. isDisjointFrom()
isDisjointFrom: Do these sets share zero common elements?
JavaScriptCopied!
const ai = new Set(['python', 'c++']);
const mobile = new Set(['java', 'js', 'dart', 'kotlin']);
const frontend = new Set(['js', 'dart']);
console.log(ai.isDisjointFrom(mobile)); // true
console.log(mobile.isDisjointFrom(frontend)); // false
In JavaScript, working with the Document Object Model (DOM) often involves iterating through child elements of a parent element. This technique is essential for tasks such as:
Manipulating elements based on their content or attributes
Dynamically adding or removing elements
Handling events for multiple elements
JavaScript offers several methods to achieve this, each with its own advantages and considerations.
Methods for looping
1. Use children property
Access the children property of the parent element to obtain a live NodeList of its direct child elements.
Iterate through the NodeList using a for loop or other methods:
JavaScriptCopied!
const parent = document.getElementById("myParent");
const children = parent.children;
for (let i = 0; i < children.length; i++) {
const child = children[i];
// Perform actions on the child element
console.log(child.textContent);
}
2. Use for..of loop
Directly iterate over the NodeList using the for...of loop:
JavaScriptCopied!
const parent = document.getElementById("myParent");
for (const child of parent.children) {
// Perform actions on the child element
console.log(child.tagName);
}
3. Use Array.from() method
Convert the NodeList into an array using Array.from(), allowing the use of array methods like forEach():
JavaScriptCopied!
const parent = document.getElementById("myParent");
const childrenArray = Array.from(parent.children);
childrenArray.forEach(child => {
// Perform actions on the child element
child.style.color = "red";
});
Key considerations
Live NodeList: The children property returns a live NodeList, meaning changes to the DOM are reflected in the NodeList.
Text Nodes: The children property includes text nodes, while childNodes includes all types of nodes (elements, text, comments, etc.). Choose the appropriate property based on your needs.
Performance: For large DOM trees, using Array.from() might have a slight performance overhead due to array creation.
Choosing the right method
For simple iterations, the for...of loop or the children property with a for loop are often sufficient.
If you need to use array methods or want to create a static copy of the child elements, use Array.from().
Consider performance implications if dealing with large DOM structures.
By understanding these methods and their nuances, you’ll be able to effectively loop through child elements in JavaScript for various DOM manipulation tasks.
These 10 amazing features were all about writing shorter, safer, and more expressive code.
1. Private methods and fields
We need our privacy. There’s no two ways about it.
And so do OOP classes; but in JavaScript it was once impossible to strictly declare private members.
It was once impossible to declare private members in a JavaScript class.
A member was traditionally prefixed with an underscore (_) to indicate that it was meant to be private, but it could still be accessed and modified from outside the class.
JavaScriptCopied!
class Person {
_firstName = 'Coding';
_lastName = 'Beauty';
get name() {
return `${this._firstName} ${this._lastName}`;
}
}
const person = new Person();
console.log(person.name); // Coding Beauty
// Members intended to be private can still be accessed
// from outside the class
console.log(person._firstName); // Coding
console.log(person._lastName); // Beauty
// They can also be modified
person._firstName = 'Debugging';
person._lastName = 'Nightmares';
console.log(person.name); // Debugging Nightmares
With ES2022, we can now add private fields and members to a class, by prefixing it with a hashtag (#). Trying to access them from outside the class will cause an error:
JavaScriptCopied!
class Person {
#firstName = 'Coding';
#lastName = 'Beauty';
get name() {
return `${this.#firstName} ${this.#lastName}`;
}
}
const person = new Person();
console.log(person.name);
// SyntaxError: Private field '#firstName' must be
// declared in an enclosing class
console.log(person.#firstName);
console.log(person.#lastName);
Note that the error thrown here is a syntax error, which happens at compile time; the code doesn’t run at all; the compiler doesn’t expect you to even try to access private fields from outside a class, so it assumes you’re trying to declare one.
“Ergonomic brand” checks for private fields
With private fields come a new keyword to safely check if a class object contains a particular one — the in keyword:
JavaScriptCopied!
class Car {
#color;
hasColor() {
return #color in this;
}
}
const car = new Car();
console.log(car.hasColor()); // true;
It correctly distinguishes private fields with the same names from different classes:
JavaScriptCopied!
class Car {
#color;
hasColor() {
return #color in this;
}
}
class House {
#color;
hasColor() {
return #color in this;
}
}
const car = new Car();
const house = new House();
console.log(car.hasColor()); // true;
console.log(car.hasColor.call(house)); // false
console.log(house.hasColor()); // true
console.log(house.hasColor.call(car)); // false
And don’t ask me about the name; I also have no idea why they’re called that (do you?).
Ergonomics as far as I’m concerned is all about keeping good sitting posture while using your computer (?) 🤔.
Although I guess you could twist this definition to allow for this new feature — or any new feature for that matter. They’re all about comfort, right? Less pain writing code.
But I guess English isn’t a closed language and you can always add new words and additional definitions (just ask Shakespeare).
2. Immutable sort(), splice(), and reverse()
ES2023 came fully packed with immutable versions of these 3 heavily used array methods.
Okay maybe splice() isn’t used as much as the others, but they all mutate the array in place.
Did you know: F# was the first language to introduce async/await? As far back as 2007! But it took JavaScript 10 good years to catch up.
await pauses execution in the async context until a Promise resolves.
Previously we could only use this operator in an async function, but it could never work in the global scope.
JavaScriptCopied!
function setTimeoutAsync(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
// SyntaxError: await is only valid in async functions
await setTimeoutAsync(3000);
With ES2022, now we can:
JavaScriptCopied!
function setTimeoutAsync(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
// ✅ Waits for timeout - no error thrown
await setTimeoutAsync(3000);
4. Promise.any()
If you know Promise.all(), then you can easily guess what this does: wait for one Promise to resolve and return the result.
JavaScriptCopied!
async function getHelpQuickly() {
const response = await Promise.any([
cautiousHelper(),
kindHelper(),
wickedHelper(),
]);
console.log(response); // Of course!
}
async function cautiousHelper() {
await new Promise((resolve) => {
setTimeout(() => {
resolve('Uum, oohkaay?');
}, 2000);
});
}
async function kindHelper() {
return 'Of course!';
}
function wickedHelper() {
return Promise.reject('Never, ha ha ha!!!');
}
Point to note: Promise.any() still waits for *all* the promises in the current async context to resolve, even though it only returns the result of the first one.
JavaScriptCopied!
await getHelpQuickly(); // outputs "Of course!" immediately
// Still waits for 2 seconds
5. Array find from last
Arrayfind() searches for an array element that passes a specified test condition, and findIndex() gets the index of such an element.
While find() and findIndex() both start searching from the first element of the array, there are instances where it would be preferable to start the search from the last element instead.
There are scenarios where we know that finding from the last element might achieve better performance. For example, here we’re trying to get the item in the array with the value prop equal to y. With find() and findIndex():
This works, but as the target object is closer to the tail of the array, we might be able to make this program run faster if we use the new ES2022 findLast() and findLastIndex() methods to search the array from the end.
We could call the reverse() method on the array to reverse the order of the elements before calling find() and findIndex(). But this approach would cause unnecessary mutation of the array; reverse() reverses the elements of an array in place.
The only way to avoid this mutation would be to make a new copy of the entire array, which could cause performance problems for large arrays.
Also findIndex() still wouldn’t on the reversed array, as reversing the elements would also mean changing the indexes they had in the original array. To get the original index, we would need to perform an additional calculation, which means writing more code.
JavaScriptCopied!
const nums = [7, 14, 3, 8, 10, 9];
// Copying the entire array with the spread syntax before
// calling reverse()
const reversed = [...nums].reverse();
// correctly gives 10
const lastEven = reversed.find((value) => value % 2 === 0);
// gives 1, instead of 4
const reversedIndex = reversed.findIndex((value) => value % 2 === 0);
// Need to re-calculate to get original index
const lastEvenIndex = reversed.length - 1 - reversedIndex;
console.log(lastEven); // 10
console.log(reversedIndex); // 1
console.log(lastEvenIndex); // 4
It’s cases like where the findLast() and findLastIndex() methods come in handy.
This code is shorter and more readable. Most importantly, it produces the correct result.
6. StringreplaceAll()
We already had replace() for quickly replace a substring within a string.
JavaScriptCopied!
const str =
'JavaScript is so terrible, it is unbelievably terrible!!';
const result = str.replace('terrible', 'wonderful');
console.log(result);
// JavaScript is so wonderful, it is unbelievably terrible!!
// Huh?
But it only does so for the first occurrence of the substring unless you use a regex; now we have replaceAll() to replace every single instance of that substring.
JavaScriptCopied!
const str =
'JavaScript is so terrible, it is unbelievably terrible.';
const result = str.replaceAll('terrible', 'wonderful');
console.log(result);
// JavaScript is wonderful, it is unbelievably wonderful.
// Now you're making sense!
7. Arraywith() and at()
at() came first and with() came a year after that in 2023.
They are the functional and immutable versions of single-element array modification and access.
The cool thing about these new methods is how they let you get and change element values with negative indexing.
JavaScriptCopied!
// index -N is same as index arr.length - N
const fruits = ['banana', 'apple', 'orange', 'butter???'];
console.log(fruits.at(-3)); // apple
console.log(fruits.at(-1)); // butter???
console.log(fruits.with(-1, 'watermelon'));
// ['banana', 'apple', 'orange', 'watermelon'] ✅
8. static static static
Static class fields, static private methods (2022).
Static methods access other private/public static members in the class using the this keyword; instance methods with this.constructor:
JavaScriptCopied!
class Person {
static #count = 0;
static getCount() {
return this.#count;
}
// Instance method
constructor() {
this.constructor.#incrementCount();
}
static #incrementCount() {
this.#count++;
}
}
const person1 = new Person();
const person2 = new Person();
console.log(Person.getCount()); // 2
Static blocks.
Executed only once when the *class* is created. It’s like static constructors in other OOP languages like C# and Java.
When they’re multiple static blocks, they’re executed in the order they’re declared, along with any static fields in between. The super property in a static block to access properties of the superclass.
9. Logical assignment operators
They let a variable perform a logical operation with another variable and re-assign the result to itself.
We use them like this:
JavaScriptCopied!
left ??= right;
left ||= right;
left &&= right;
They’re as good as:
JavaScriptCopied!
// More like exactly the same as
left = (left ?? right);
left = (left || right);
left = (left && right);
??=. Quickly assign a value to a variable *if* it is null or undefined (“nullish”).
JavaScriptCopied!
user.preferredName ??= generateDumbUserName();
||=. Like ??=, but assigns the value for any falsy value (0, undefined, null, '', NaN, or false).
JavaScriptCopied!
user.profilePicture ||= "/angry-stranger.png";
And then &&=. Something like the reverse; only assigns when the value is truthy (not falsy).
Tiny new addition to make big number literals more readable and human-friendly.
JavaScriptCopied!
const isItPi = 3.1_415_926_535;
const isItAvagadro = 602_214_076_000_000_000_000_000;
const isItPlanck = 6.626_070_15e-34;
const isItG = 6.674_30e-11;
// Works for other number bases too...
The compiler completely ignores those pesky underscores — they’re all for you, the human!
Final thoughts
These are the juicy new JavaScript features that arrived in the last 3 years. Use them to boost your productivity as a developer and write cleaner code with greater conciseness, expressiveness and clarity.
With the pipeline operator you’ll stop writing code like this:
and start writing code like this:
So refreshingly clean — and elegant! All those temporary variables are gone — not to mention the time it took to come up with those names *and* type them (not everyone types like The Flash, unfortunately).
You may have heard this partially true quote attributed to Phil Karlton: “There are only two hard things in computer science: cache invalidation and naming things“.
Using the JavaScript pipeline operator clears out the clutter to boost readability and write data transforming code (basically all code) in a more intuitive manner.
Verbosity should be avoided as much as possible, and this works so much better to compact code than reusing short-named variables:
Hopefully, almost no one codes like this on a regular basis. It’s a pretty horrible technique when done in a large scale; a perfect example showing why we embrace immutability and type systems.
Unlike the pipeline operator, there’s no certainty that the variable always contains the value you set at any given point; you’ll need to climb up the scope to look for re-assignments. We can have used the _ at an earlier point in the code; the value it has at various points in the code is simply not guaranteed.
Now we’re just using an underscore, so without checking out the right-hand side of those re-assignments you can’t quickly know what the type of the variable is, unless you have a smart editor like VS Code (although I guess you could say that doesn’t matter since they’re supposed to be “temporary” — at least until they’re not!).
All in all, poor readability. Fragile and Unstable. 5 times harder for someone new to understand. Also, some would say underscores are “ugly”, especially in languages like JavaScript where they hardly show up.
Okay, so why don’t we just avoid this infestation of temporary underscores, and nest them into one gigantic one-liner?
It’s a mess. The underscore is gone, but who in the world can understand this at a glance? How easy is it to tell how the data flows throughout this code, and make any necessary adjustments.
Understanding, at a glance — this is what we should strive for with every line of code we write.
The pipeline operator greatly outshines every other method, giving us both freedom from temporary variables and readability. It was designed for this.
Here the % only exists within this particular pipeline.
Method chaining?
Who hasn’t used and combined heavily popular array methods like map, filter, and sort? Very hard to avoid in applications involving any form of list manipulation.
This is actually great. There aren’t any temporary variables or unreadable nesting here either and we can easily follow the chain from start to finish.
The formatting lets us easily add more methods at any point in the chain; feature-packed editor like VS Code can easily swap the processing order of two methods, with the Ctrl + Up and Ctrl + Down shortcuts.
There’s a reason why libraries like core http and jQuery are designed like this:
The problem with method chaining is that, we simply can’t use it everywhere. If the class wasn’t designed like that we’re stuck and out in the cold.
It doesn’t work very well with generator methods, async/await and function/method calls outside the object, like we saw here:
But all this and more work with the pipeline operator; even object literals and asyncimport function.
Could have been F# pipes
We would have been using the pipeline operator very similarly to F# pipes, with the above turning out like this instead:
There was an alternative design. But you can already see how this makes for an inferior alternative: Only single-function arguments are allowed and the operation is more verbose. Unless the operation is already a single-argument function call.
It’s weird handling of async/await was also a key reason why it got rejected — along with memory usage concerns. So, forget about F# pipes in JS!
Use the pipeline operator right now
Yes you can — with Babel.
Babel has a nice habit of implementing features before they’re officially integrated in the language; it did this for top-level await, optional chaining, and many others. The pipeline operator couldn’t be an exception.
Just use the @babel/plugin-proposal-pipeline-operatorplugin and you’re good to.
It’s optional of course — but not for long.
Prettier the code formatter is already prepared.
Even though we can’t say the same about VS Code or Node.js.
Right now there’s even speculation that % won’t be the final symbol pass around in the pipeline; let’s watch and see how it all plays out.
Final thoughts
It’s always great to see new and exciting features come to the language. With the JavaScript pipeline operator, you’ll cleanse your code of temporary variables and cryptic nesting, greatly boost code readability, efficiency, and quality.
You will be an expert on JavaScript generators by the time you’re done reading this.
JavaScript generators are way more than just a fancy feature and we are going to discover many powerful use cases for them, including creating engaging animations, and streaming videos over the internet.
If you’ve never heard of them you may be missing out.
Generators are simply functions that you can pause and resume whenever you want — they don’t execute continuously.
The asterisk * marks the function as a generator, and yield generates values on demand from a .next() call, until the generator is done.
It’s just like how a physical generator produces electricity not all at once, but as time goes on.
Instead of calling next() you can use the for..of loop, which is great for when the generator generates a lot of data.
JavaScriptCopied!
function* countTo100() {
for (let i = 0; i < 100; i++) {
yield i;
}
}
for (const item of countTo100()) {
console.log(item);
}
// 1, 2, ... 100
Lazy evaluation
“Calculate only when necessary.”
Much unlike regular functions in JavaScript that execute entirely and return the result.
Let’s say you want a sequence of numbers, but you’re not sure how many. Here’s how a generator helps:
JavaScriptCopied!
function* numberGenerator() {
let number = 1;
// infinite loop won't cause freeze in generator
// -- execution pauses after `yield`
while (true) {
yield number++;
}
}
const numbers = numberGenerator();
console.log(numbers.next().value); // 1
console.log(numbers.next().value); // 2
// you can continue this as long as you need
With generators, you get the next number only when you ask for it.
Better memory utilization
Generators don’t hold all the results in memory, they generate them on the fly.
Imagine you need a sequence of a million numbers. With a regular function, you’d need to store all these numbers in an array, using up significant memory.
A generator is much more efficient:
JavaScriptCopied!
function* bigNumberGenerator() {
let number = 1;
while (number <= 100000000) {
yield number++;
}
}
const bigNumbers = bigNumberGenerator();
const chunk = 10;
for (let i = 0; i < chunk; i++) {
const value = bigNumbers.next().value;
// Use next 10 values...
}
Handling asynchronous tasks
Did you know that Babel transpiles async/await to generators for JavaScript versions that don’t support it natively?
Babel tranforms this:
JavaScriptCopied!
this.it('is a test', async function () {
const name = await 'coding beauty'
const num = await new Promise(resolve => resolve(10));
console.log(`Name: ${name}, Num: ${num}`);
});
To this:
JavaScriptCopied!
function _asyncToGenerator(fn) {
return function () {
var gen = fn.apply(this, arguments);
return new Promise(function (resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
function (value) {
return step('next', value);
},
function (err) {
return step('throw', err);
}
);
}
}
return step('next');
});
};
}
myFunc(
'generator async/await example',
_asyncToGenerator(function* () {
const name = yield 'coding beauty'; // yield, not await
const num = yield new Promise((resolve) => resolve(10));
console.log(`Name: ${name}, Num: ${num}`);
})
);
Typing animations
Typing animations grab the attention of users and make your website more visually appealing.
They add personality and character to a website by mimicking the typing behavior of a human to create a more human-like experience and establish a unique brand identity.
So with all these benefits you’re feeling excited about infusing your webpages with these energetic visual effects.
Here would be a decent way to go about it, using recursion and setTimeout():
JavaScriptCopied!
function typeAnimation(text, index = 0) {
if (index < text.length) {
document.body.innerHTML += text.charAt(index);
index++;
setTimeout(typeAnimation, 500);
}
}
This is such a powerful tool for streaming data in web app in a structured, readable manner — just look at this function that buffers and streams data for a video-sharing app like YouTube:
import createSagaMiddleware from 'redux-saga';
import { createStore, applyMiddleware } from 'redux';
import mySaga from './sagas';
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(mySaga)
Whenever the USER_FETCH_REQUESTED action is dispatched, redux-saga runs the generator which in turn calls fetchData() to perform the asynchronous network request.
A note on return
What happens when you return a value in a generator function? Let’s see:
JavaScriptCopied!
function* soccerPlayers() {
yield 'Ronaldo';
yield 'Messi';
return 'Neymar';
}
for (const player of soccerPlayers()) {
console.log(player);
}
// Ronaldo
// Messi
Why isn’t Neymar part of the generated values?
Let’s use .next() to find out if the done property has something to do with it:
You can see that generators only produce values until, but not including when done is true.
So return completes the generator and terminates the function (like any other).
JavaScriptCopied!
function* myGenerator() {
yield 'Hello';
return 'End';
yield 'This will not be executed';
}
Final thoughts
JavaScript generators offer powerful solutions for control flow, memory efficiency, and asynchronous handling. They enhance web development with dynamic animations, streaming data, and managing side effects.
Let’s embrace the versatility of generators for elegant and efficient JavaScript programming.
Are you currently experiencing the “Cannot use import statement outside a module” error in JavaScript?
This is a well-known error that happens when you use the import keyword to load a file or package that is not a module.
Let’s learn how to easily fix this error in Node.js or the browser.
Fix “Cannot use import statement outside a module” in browser
Fix: Set type="module" in <script> tag
The “Cannot use import statement outside a module” error happens in a browser when you import a file that is a module without indicating this in the <script> tag.
index.htmlCopied!
<!DOCTYPE html>
<html>
<head>
<title>Coding Beauty</title>
<link rel="icon" href="favicon.ico" />
</head>
<body>
A site to make you enjoy coding
<!-- ❌ SyntaxError: Cannot use import statement outside a module -->
<script src="index.js"></script>
</body>
</html>
To fix it, add type="module" to the <script> tag.
index.htmlCopied!
<!DOCTYPE html>
<html>
<head>
<title>Coding Beauty</title>
<link rel="icon" href="favicon.ico" />
</head>
<body>
A site to make you enjoy coding
<!-- ✅ Loads script successfully -->
<script type="module" src="index.js"></script>
</body>
</html>
Fix “Cannot use import statement outside a module” in Node.js
The “Cannot use import statement outside a module” error happens when you use the import keyword in a Node.js project that doesn’t use the ES module import format.
index.jsCopied!
// ❌ SyntaxError: Cannot use import statement outside a module
import axios from 'axios';
const { data } = (
await axios.post('https://api.example.com/hi', {
hello: 'world',
})
).data;
console.log(data);
Fix: Set type: "module" in package.json
To fix the error in Node.js, set the package.jsontype field to “module”.
package.jsonCopied!
{
// ...
"type": "module",
// ...
}
Now you can use the import statement with no errors:
If there’s no package.json in your project, you can initialize one with the npm init -y command.
ShellCopied!
npm init -y
The -y flags creates the package.json with all the default options – no user prompts for the fields.
Fix: Use require instead of import
Alternatively, you can fix the “Cannot use import statement outside a module” error in JavaScript by using the require() function in place of the import syntax:
index.jsCopied!
// ✅ Works - require instead of import
const axios = require('axios');
const { data } = (
await axios.post('https://api.example.com/hi', {
hello: 'world',
})
).data;
console.log(data);
But require() only works on the older, Node-specific CommonJS module system, and these days more and more modules are dropping support for CommonJS in favor of ES6+ modules.
Or, you can downgrade to an earlier version of the package that supported CommonJS and require().
ShellCopied!
npm install chalk@4
# Yarn
yarn add got@4
Here are the versions you should install for various well-known NPM packages to avoid this ERR_REQUIRE_ESM error:
Fix “Cannot use import statement outside a module” in TypeScript
If the module field in tsconfig.json is set to commonjs, any import statement in the TypeScript source will change to require() calls after the compilation and potentially cause this error.
tsconfig.jsonCopied!
{
//...
"type": "module"
}
Prevent this by setting module to esnext or nodenext
tsconfig.jsonCopied!
{
"type": "module"
}
nodenext indicates to the TypeScript compiler that the project can emit files in either ESM or CommonJS format.
A JavaScript function would change the href to a new URL with several parameters including the original URL, as soon as you start clicking on it.
JavaScriptCopied!
import express from 'express';
const app = express();
app.get('/url', (req, res) => {
// Record click and stuff...
res.redirect(req.query);
});
app.listen(3000);
So even though the browser would show the actual URL at the bottom-left on hover, once you clicked on it to copy, the href would change instantly.
Why mousedown over click? Probably because there won’t be a click event when users open the link in a new tab, which is something that happens quite often.
And so after right-clicking to copy like I did, mousedown would fire and the href would change, which would even update that preview URL at the bottom-left.
The new www.google.com/url page would log the visit and move out of the way so fast you’d barely notice it — unless your internet moves at snail speed.
They use this data for tools like Google Analytics and Search Console so site owners can improve the quality of their search results and pages by analyzing click-rate — something probably also using as a Search ranking factor. Not to mention recording clicks on Search ads to rake all the billions of yearly ad revenue.
But Google got smarter.
They realized this URL tracking method had a serious issue for a certain group. For their users with slower internet speeds, the annoying redirect technique added a non-trivial amount of delay to the request and increased bounce rate.
So they did something new.
Now, instead of that cryptic www.google.com/url stuff, you get… the same exact URL?
With the <a>ping attribute, they have now successfully moved their tracking behind the scenes.
The ping attribute specifies one or more URLs that will be notified when the user visits the link. When a user opens the link, the browser asynchronously sends a short HTTP POST request to the URLs in ping.
The keyword here is asynchronously — www.google.com/url quietly records the click in the background without ever notifying the user, avoiding the redirect and keeping the user experience clean.
Browsers don’t visually indicate the ping attribute in any way to the user, which appears to go against the specification
When the ping attribute is present, user agents should clearly indicate to the user that following the hyperlink will also cause secondary requests to be sent in the background, possibly including listing the actual target URLs.
Not to mention a privacy concern, which is why browsers like Firefox refuse to enable this feature by default.
In Firefox Google sticks with the mousedown event approach:
There are many reasons not to disable JavaScript in 2023, but even if you do, Google will simply replace the href with a direct link to www.google.com/url.
HTMLCopied!
<a href="/url?sa=t&source=web&rct=j&url=https://www.codingbeautydev.com/blog/vscode-tips-tricks...">10 essential VS Code tips and tricks for greater productivity</a>
So, there’s really no built-in way to avoid this mostly invisible tracking.
Even the analytics are highly beneficial for Google and site owners in improving result relevancy and site quality, as users we should be aware of the existence and implications of these tracking methods.
It raises important questions about online privacy and the control we have over our personal information. As technology continues to advance, it’s crucial to critically evaluate the trade-offs between convenience and privacy in our digital lives.
You can also install the package as a development dependency, which indicates that the package is only used for development, and won’t be needed by the app itself. Packages like nodemon and ts-node fit this category:
If it’s a third-party module, installing the type definitions from NPM should help. For example:
JavaScriptCopied!
npm i @types/express
5. Ensure package.jsonmain file exists
You may encounter the “Cannot find module” error in Node.js if the main field of your package.json file doesn’t exist.
6. npm link package
You can also try the npm link command on the package to fix the MODULE_NOT_FOUND error, for example:
ShellCopied!
npm link create-react-app
npm link webpack
npm link is a command that connects a globally installed package with a local project using a symbolic link.
It enables working on a package locally without publishing it to the npm registry or reinstalling it for every change. Executing npm link in the package directory establishes a symbolic link in the global node_modules directory, directing to the local package.
Afterwards, npm link <package-name> can be used in the project to link the global package with your local project.
7. Ensure correct NODE_PATH
In older Node.js versions, you may be able to fix the “Cannot find module” error by setting the NODE_PATH environment variable to correct node_modules installation folder.
NODE_PATH is a string of absolute paths separated by colons used by Node.js to locate modules when they can’t be found elsewhere.
It was initially created to enable the loading of modules from different paths when there was no defined module resolution algorithm.
And it’s still supported, but it’s not as important anymore since the we’ve established a convention for finding dependent modules in Node.js community.
The spread syntax (...) converts the set to an array for filter() to work.
The Set() constructor converts the result of filter() back to an Set.
Get symmetric difference between two sets
The method above only gives the elements in the second set that aren’t in the first.
JavaScriptCopied!
function getDifference(setA, setB) {
return new Set(
[...setA].filter((element) => !setB.has(element))
);
}
const set1 = new Set([2, 4]);
const set2 = new Set([1, 2, 3, 4]);
// Every item in set1 is also in set2, but the sets are different
console.log(getDifference(set1, set2)); // {}
Sometimes you want this, especially if set2 is supposed to be a set1‘s subset.
But other times you may want to find the symmetric difference between the sets, regardless of which one comes first.
To do that, we simply merge the results of two getDifference() calls, each with the order of the Sets reversed.
JavaScriptCopied!
function getDifference(setA, setB) {
return new Set(
[...setA].filter((element) => !setB.has(element))
);
}
function getSymmetricDifference(setA, setB) {
return new Set([
...getDifference(setA, setB),
...getDifference(setB, setA),
]);
}
const set1 = new Set([2, 4]);
const set2 = new Set([1, 2, 3, 4]);
console.log(getSymmetricDifference(set1, set2)); // {1, 3}
console.log(getSymmetricDifference(set2, set1)); // {1, 3}