JS Modules
This is how I personally like to approach authoring JavaScript code these days. The approach here is largely downstream making decisions that minimize maintenance by prioritizing stability and longevity. You might make different decisions with different goals. That's ok. The primary strength of the JavaScript ecosystem is diversity. Options are good and there are many paths up the mountain. That said, I think the goals I have are unfortunately uncommon, so you may find you disagree with this approach.
First of all, we need to understand our scope. Publishing a utity function module to npm and jsr is goinkg to be different than publishing a website driven by a dynamic backend runtime like node or deno. In either cases, however, I start with the simplest thing that could possibly work and iterate from there.
Part 1: Boilerplate
Create a directory for our module, with a readme.md
and package.json
.
# in your terminal of choice
mkdir flatten
echo "# flatten" > readme.md
echo {} > package.json
A lowercase reademe.md
is chill; no need to SHOUT! Besides, some operating systems are case sensitive while others are not. Its always a lot safer to keep files and directories lowcase, and dasherized. Another benefit is all our paths are URL friendly when they get published to the web on Github later on.
Part 2: Code
JavaScript is a famously loose language. That flexability can be a source of bugs. It is worth noting that tools can also be a source of bugs. Its really easy to sucked into adding too many guardrails.
Lint and Format
In the past I've mostly used eslint
but with the recent 9.x upgrade configuration changed and that invited me to evaluate other options given I was starting fresh anyhow. I found that I really like the speed and output of Biome. Special mention: OXC and deno lint
; both of these tools felt a bit immature but worth watching. End of the day it probably isn't super important which tools you use as long as you remain consistent in their usage.
npm i -D @biomejs/biome
Typesafety
TypeScript (TS) makes JavaScript more rigid which can prevent some bugs, and make refactoring easier. Arguably by being more rigid TS also makes code more brittle. Finding issues early is always the name of the game so this tradeoff is often deemed worthwhile. That said, it is very tempting to go overboard on TS tooling. I personally prefer using TS with JSDoc. We get the autocompletion and the intellisense hinting without suffering through the nightmare of configuring and debugging transpiled code. TS notoriously ships breaking changes on semver minor which also can make maintenance more difficult, and by using JSDoc I can avoid this problem too.
Tests
I like to start basic. `node:test` is great for this.
stub in our function/** @type {(o: object) => object} */
export default function flatten (obj) {
const copy = {...obj}
return copy
}