In JavaScript, closing a line of code with a semicolon is not mandatory.
This is because JavaScript uses a set of rules called ASI (Automatic Semicolon Insertion) to, as the name implies, automatically place a semicolon if it determines that a line break is also the end of a statement.
For example:

Will be interpreted as:

And not as:

In the example, JavaScript uses ASI to place a semicolon automatically before the line break (immediately after a).
The problem is that sometimes ASI doesn’t interpret our code as it should and fails to insert a semicolon where is needed.
Common pitfalls when omitting semicolons
A common use case is when we start a line with parentheses, since parentheses can be concatenated with the previous line:

To anticipate this, in the case you opt to not use semicolons at the end of each statement, make it a habit to, at least, put a semicolon in the begging of a statement that starts with parenthesis.

Another example of ASI not working as expected is when the next line starts with a statement that is produced on multiple lines.

Here, the previous rule about parenthesis also applies:

So having in mind that ASI is a tool that sometimes get it wrong, a lot of developers think “hey I want to take things on my own hands, explicitly inserting the semicolons myself, and stop relying on a tool to make the job for me.”
The thing is that similar problems can as well occur by inserting semicolons, since ASI is not a tool that can be turned off.
It makes its job, regardless of our formatting style preferences. Regardless of explicitly placing a semicolon, it is still in use. It is part of the JavaScript standard.
Let’s see an example:

That is because ASI inserts a semicolon just after the return keyword, so JavaScript returns the function immediately without defining an object.
If we’d insert return and the opening bracket in the same line, the engine would check the rest of the statement and would return the expected result.
Although we opted to explicitly use semicolons in our example, ASI worked anyway.
What is the solution to buggy ASI implementation?
What we can do is to be alert for cases like this, and never forget that ASI does its thing which can cause bugs in our code.
It is also helpful to have some use cases of common pitfalls in mind and follow some simple rules.
When returning something, always place it on the same line as the return keyword (same rule applies with the break, continue, and throw keywords).
If you prefer not to use semicolons, when starting a line with parenthesis, place a semicolon in front of them in order to avoid concatenated with previous line’s code.
What I do
I prefer to use semicolons in JavaScript.
The main reason is that I am used to switching a lot between PHP code bases and JavaScript ones. In PHP, the use of semicolons is mandatory except for the last line in a PHP block. In that case is optional.
Also, I write code for CSS and in CSS semicolons are needed to separate each statement, with the insertion being optional in the last statement of a block of statements.
I use no exceptions in these languages to avoid cognitive load. And I do the same with JavaScript. This way, the switch of context becomes easier and more harmonious. I put semicolon at the end of every statement. So nothing to think about. Zero cognitive load.
But is it a chore having to add an extra character and checking if a semicolon is in place all the time, right?
It definitely is.
That is why I use Prettier.
Prettier is a VS code formatting extension.
We can set up Prettier to add semicolons for us or even remove them if a formatting styling of a project dictates so. We can toggle between the two options.
This tool is quite opinionated, which is good for some developers and bad for others. The fact that it is opinionated makes it easy to use and creates consistency across different projects. It is exactly that opinionated nature that makes a lot of developers to avoid it.
I think prettier being opinionated is an acceptable trade-off for helping to format my code and removing the chore of having to check for semicolon placement all the time.
What is the conclusion?
Use every styling you like, just make sure it is consistent across the entire project
Remember, there is not such a thing as a best practice for omitting or not semicolon in JavaScript.
There is really not a universal consensus in JavaScript community about it. But it is best practice to adopt some kind of consistent styling that everybody on the same project uses.
At the end of the day, inserting or not semicolons is a matter of personal taste or what you and your team decide about it.