npm
Using JSDoc instead of TypeScript on the server
If you are running a lightweight service via Nodejs, I'd recommend trying to use JSDoc instead of TypeScript due to how lightweight it is. This is particularly useful if you are using VSCode as your IDE, since you will get all the same compiler warnings and errors inline same as you would if you were using TS. Coupling this with the #Nodejs test runner will get you a long way towards a low-dependency lightweight servers.
Using express
and ws
to support WebSockets and normal HTTP requests
I am struggling a bit to determine the ordering of things here, but it appears that the way to do this begin by inferring that the app
from const app = express()
is actually a function that satisfies the requirements of the node:http
http.createServer
requestListener
parameter. Thus, you can do the following.
const app = express()
const server = http.createServer(app)
server.listen(8080)
This means that you are not using the builtin express
functions to initiate server listening, but instead working with the underlying http.Server primitive itself.
Now that you have a nodejs server entity, you can also setup the ws
websocket server. (I am adapting this from some ws
docs.)
const app = express()
const server = http.createServer(app)
const wss = new WebSocketServer()
server.on('upgrade', (request, socket, head) => {
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request)
})
})
wss.on('connection', (ws, request) => {
console.log('connection!')
ws.on('message', (message) => {
console.log('message received', message)
})
})
server.listen(8080)
This is establishing the core websocket setup. You can learn more in my note on WebSockets.
The end result is an express app
for handling common HTTP requests and ws
for handling WebSocket connections, all via the base http.Server
.
log full objects
You can use util
and the depth: Infinity
option. You still have to call console.log
.
import util from 'node:util'
const obj = {}
console.log(util.inspect(out, { depth: Infinity }));
directories
process.cwd()
is the directory the node process is currently being ran in.
But maybe you want to write a cli lib and want to access static assets/files within your npm library. For that, you can use __direname
and __filename
, which aren't quite globals, and only work in .cjs
(common js) files. Importantly, symlinks are resolved before filename resolution. This means that even though the script is likely executed from node_modules/.bin/<script>
, since that is a symlink to the package.bin
field, it will actually display that file path. From there, you can construct relative paths to reach your desired static asset.
Nodejs test runner
Nodejs test runner tips and tricks
Nodejs test setup in VSCode
Nodejs test runner setup in VSCode
conditional exports seem great for package authors
To begin with, you should be familiar with the exports
key, which seems to be intended to supercede the main
key in package.json
files:
With conditional exports The exports
key seems to be intended to supercede the main
key in package.json
:
When a package has an
"exports"
field, this will take precedence over the"main"
field when importing the package by name.
Now, within the exports
key, you can defined conditional exports, which can target different module types.
For example, let's say we are writing a package in TypeScript using esm files. We can use tsup
to easily bundle our exports into multiple formats, and then point to each module type bundle within the exports
key.
{
// source code is in esm
"type": "module",
// tsup outputs ts types
"types": "dist/index.d.ts",
// tsup bundles/builds
"scripts": {
"build": "tsup src/index.ts --dts --formats esm,cjs"
},
// conditional exports
"exports": {
"import": "dist/index.js",
"require": "dist/index.cjs"
}
}
Now, packages that depend on your package can require('package')
or import _ from 'package'
.
Finally, you can also include "types" within "exports". This is considered a community condition. For some reason it must come first. I have not move the types
key in the example above because I cannot get it to work with the vscode typescript engine.
package.json spec is in multiple locations
- npm specific spec is at npmjs.com (for v9)
- node specific spec is at nodejs.org (for current version)
- typescript specific spec is at typescriptlang.org