Link to Local Package With npm link

When developing a local Node module, we might want to point another project’s package.json at the local module. Here’s how you do that. First, change directory to your local module and run npm link: cd ~/code/my-module npm link This creates a global symlink pointing at your module: npm ls -g --depth=0 --link /opt/homebrew/lib └── my-module@1.0.0 -> ./../../../Users/jake/code/my-module Then, change directory into the place you want to install the module and link the package: ...

September 2, 2026

Don't Use npm init on an Existing Project

npm init is a nice tool for initializing a package.json. Today I learned that you should not use it on an existing JavaScript project! This blog is a Go project, but I use JavaScript dependencies for development. My manifest looks like this: // package.json { "scripts": { "test:e2e": "cypress run", "push": "npm run test:e2e && git push" }, "devDependencies": { "cypress": "^15.20.1", "prettier": "^3.8.3" }, "allowScripts": { "cypress@15.20.1": true } } I thought I could get away with running npm init on it to standardize the file. When I did, the program looked in my node_modules directory and saw ~170 dependencies, most belonging to Cypress. ...

August 25, 2026

Enumerate on promise resolved

For the golfers out there, we can combine these two lines into one: const items = await getCollection(); return items.sort(); This doesn’t work because sort() is being called on the promise returned by getCollection(): return await getCollection().sort(); // `sort()` runs on the Promise Instead, wrap the await expression in parentheses so sort() is called on the resolved value: return (await getCollection()).sort(); // `sort()` runs on the resolved array Promise documentation - MDN

July 24, 2026

4321 is Astro

Astro’s default port is 4321. Like Vite, this project is trying to convey its (rocket-launch) branding, even in this small detail. The proposal for this change includes an interesting argument. By choosing a non-3000 port, the developer’s browser is unlikely to already have a favicon cached. This gives the Astro favicon and branding a solid chance of being seen every time by the developer. Astro 4321 proposal

July 21, 2026

Node's Timeout _destroyed Private Method

Node Timeout timers have a private boolean attribute called _destroyed. It tells you if the function has been cleared: timer._destroyed; One way to make it true it is to let the function be called: > const timer = setTimeout(() => { | console.log("Done!"); | }, 5000); > timer._destroyed false // Alive > Done! // Function is called > timer._destroyed // Destroyed 💥 true Another is to call clearTimeout: > const timer = setTimeout(() => { | console.log("We'll destroy before this is called!"); | }, 5000); > clearTimeout(timer) // Destroying the timer undefined > timer._destroyed // Destroyed! 💥 true Timeout class docs

July 20, 2026

Uncheck Buttons With JavaScript

Today I used JavaScript to mass-unsubscribe from a website’s email notifications. Here’s the code, followed by what I did and why. document .querySelectorAll('[role="switch"]') .forEach((element) => element.click()); Today I was interacting with a website that specializes in job postings. To unsubscribe to their emails, you must visit a notifications page and un-check a toggle to opt out of each kind of email you’d like to not receive. Perusing the DOM taught me that each button has a role of “switch.” This JavaScript unsubscribed me from every mailing list in a single line of code. ...

July 20, 2026

JavaScript Reflection with toString

Reflection is an important tool in programming; it lets us examine a language’s structure. Can we reflect in JavaScript? Sort of. Some functions can be reflected with toString(): const one = () => 1; // undefined one.toString(); // '() => 1' Very cool! But native functions only return this: > Math.max.toString() 'function max() { [native code] }' You must read the ECMAScript specification to know what the function is required to do. The actual implementation is written in the JavaScript engine, which for Node is Torque, which is why Node can’t show it via toString().

July 10, 2026

Focus a JS Test

A vital testing skill is focusing a test. When iterating on a failing test, we want that test under microscope. The way I do this in JavaScript is .only: import {describe, expect, test} from 'vitest'; import {sum} from './sum.js'; test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); describe.only('adding fours', () => { test('adds 4 + 4 to equal 8', () => { expect(sum(4, 4)).toBe(8); }); }); When this test runs, only the describe will run, the other is skipped. ...

July 10, 2026

JSDoc Deprecations in TypeScript

JSDoc has a @deprecated tag that you can use in TypeScript, too. Here’s an example. // App.tsx interface User { fullName: string; /** @deprecated use fullName field instead */ lastName: string; } function App() { const user: User = {fullName: 'jake worth', lastName: 'worth'}; return <>{user.lastName}</>; } export default App; In my Vim text editor, COC’s TypeScript server prints this when hover on the use of user.lastName: "lastName" is deprecated. Related information: * App.tsx#6,7: The declaration was marked as deprecated here. (tsserver 6385) TypeScript Playground

July 10, 2026

NPM List Packages

When upgrading a dependency for a security issue, we might upgrade and move on: npm install <dependency>@<version> But wait! Was every <dependency> version upgraded, or just the version in package.json? Check with: npm list // or npm ls Packages like Prettier might only be in your lockfile once: npm list prettier hugo@ /Users/dev/code/hugo └── prettier@3.8.3 -> ./node_modules/.pnpm/prettier@3.8.3/node_modules/prettier But packages like lodash are used by many dependency libraries, even in production: npm list lodash fe@0.1.0 /dev/frontend ├─┬ @testing-library/jest-dom@5.17.0 │ └── lodash@4.18.1 overridden ├─┬ antd@4.16.3 │ ├─┬ @ant-design/icons@4.8.3 │ │ └── lodash@4.18.1 deduped │ ├─┬ @ant-design/react-slick@0.28.4 │ │ └── lodash@4.18.1 deduped │ └── lodash@4.18.1 deduped # ...hundreds of lines omitted 😅 Just because you’ve upgraded it in package.json, it might be installed in your project as a dependency of a dependency on the vulnerable version. Check it.

July 7, 2026