NodeJs
NodeJs 相关的包
mono-jsx ---> <html> as a Response
mono-jsx 是一个 JSX 运行时,在 nodeJs,deno,bun,bun,cloudflare worker 等中,在 JS Runtime 中呈现响应对象的<html> 元素。
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "mono-jsx"
}
}NodeJs 中的使用示例,利用 srvx 启动:
// app.tsx
import { serve } from "srvx";
serve({
port: 3000,
fetch: (req) => (
<html>
<h1>Welcome to mono-jsx!</h1>
</html>
),
});synckit ---> worker_threads 同步执行异步工作
在 vitepress 的一个 commit 中,使用了这个库,取得了不错的性能提升
// runner.js
import { createSyncFn } from 'synckit'
// the worker path must be absolute
const syncFn = createSyncFn(require.resolve('./worker'), {
tsRunner: 'tsx', // optional, can be `'ts-node' | 'esbuild-register' | 'esbuild-runner' | 'tsx'`
})
// do whatever you want, you will get the result synchronously!
const result = syncFn(...args)// worker.js
import { runAsWorker } from 'synckit'
runAsWorker(async (...args) => {
// do expensive work
return result
})std-env ---> 检测当前运行的环境
// ESM
import {
hasTTY,
hasWindow,
isDebug,
isDevelopment,
isLinux,
isMacOS,
isMinimal,
isProduction,
isTest,
isWindows,
platform,
isColorSupported,
nodeVersion,
nodeMajorVersion
} from "std-env";verdaccio ---> 私有 npm registry
安装和启动:
$ npm install -g verdaccio
$ verdaccio # start a server at http://localhost:4873安装包的时候指定本地代理:
$ npm install lodash --registry http://localhost:4873crossws ---> 跨平台的 WebSocket 库
优雅、类型化且简单的工具包,用于实现跨平台 WebSocket 服务器。
import { defineHooks } from "crossws";
import crossws from "crossws/adapters/<adapter>";
const ws = crossws({
hooks: {
open(peer) {
console.log("[ws] open", peer);
},
message(peer, message) {
console.log("[ws] message", peer, message);
if (message.text().includes("ping")) {
peer.send("pong");
}
},
close(peer, event) {
console.log("[ws] close", peer, event);
},
error(peer, error) {
console.log("[ws] error", peer, error);
},
},
});forge ---> TLS 的 native 实现
可以用于生成证书,例如 vitejs/vite-plugin-basic-ssl 的底层实现就是使用了这个库
// @ts-ignore
import forge from 'node-forge/lib/forge'
// @ts-ignore
import 'node-forge/lib/pki'
const keyPair = forge.pki.rsa.generateKeyPair(keySize)
const cert = forge.pki.createCertificate()connect ---> 一个 Node.js 的中间件层
算比较老的包
var connect = require('connect');
var http = require('http');
var app = connect();
// gzip/deflate outgoing responses
var compression = require('compression');
app.use(compression());
// store session state in browser cookie
var cookieSession = require('cookie-session');
app.use(cookieSession({
keys: ['secret1', 'secret2']
}));
// parse urlencoded request bodies into req.body
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: false}));
// respond to all requests
app.use(function(req, res){
res.end('Hello from Connect!\n');
});
//create node.js http server and listen on port
http.createServer(app).listen(3000);fdir ---> 目录读取和 glob 模式抓取
类似 fs.readdir 的功能,但是它可以在不到 1 秒的时间内轻松抓取包含 100 万个文件的目录。详细 Benchmark
import { fdir } from "fdir";
// create the builder
const api = new fdir().withFullPaths().crawl("path/to/dir");
// get all files in a directory synchronously
const files = api.sync();
// or asynchronously
api.withPromise().then((files) => {
// do something with the result here.
});knip ---> 检测项目中无用的代码
检测没用到的导出,文件,甚至是 NPM 依赖...,目前内置了 .vue 的支持
$ pnpm create @knip/config # 安装
$ pnpm knip # 使用此外,有一个专注于 ts 代码的移除 tsr,功能更少但更加专注。详情查看:line/tsr
bundlesize ---> 检验打包产物大小
保证产物的大小不超过预期值
$ npm i bundlesize{
"scripts": {
"test": "bundlesize"
},
"bundlesize": [
{
"path": "./build/vendor.js",
"maxSize": "3 kB"
}
]
}tmp ---> 临时文件和目录的创建器
随机创建一个目录或者文件,并自动或者手动在合适的时机清除。更推荐使用 promise 版本的 benjamingr/tmp-promise
import { file } from 'tmp-promise'
(async () => {
const {fd, path, cleanup} = await file();
// work with file here in fd
cleanup();
})();exegesis ---> 用于实现服务器端 OpenAPI 3.0.0 的工具
简而言之,就是通过读取 OpenAPI 的 yaml 文件信息,直接启动一个 NodeJs 服务器, 此外,也提供了 express 版本的服务
import * as path from 'path';
import * as http from 'http';
import * as exegesis from 'exegesis';
// See https://github.com/exegesis-js/exegesis/blob/master/docs/Options.md
const options = {
controllers: path.resolve(__dirname, './src/controllers'),
};
// `compileApi()` can either be used with a callback, or if none is provided,
// will return a Promise.
exegesis.compileApi(
path.resolve(__dirname, './openapi/openapi.yaml'),
options,
(err, middleware) => {
if (err) {
console.error('Error creating middleware', err.stack);
process.exit(1);
}
const server = http.createServer((req, res) =>
middleware(req, res, (err) => {
if (err) {
res.writeHead(err.status || 500);
res.end(`Internal error: ${err.message}`);
} else {
res.writeHead(404);
res.end();
}
})
);
server.listen(3000);
}
);import express from "express";
import path from "path";
import http from "http";
import * as exegesisExpress from "exegesis-express";
async function createServer() {
// See https://github.com/exegesis-js/exegesis/blob/master/docs/Options.md
const options = {
controllers: path.resolve(__dirname, "./controllers"),
};
const exegesisMiddleware = await exegesisExpress.middleware(
path.resolve(__dirname, "./openapi.yaml"),
options
);
const app = express();
// If you have any body parsers, this should go before them.
app.use(exegesisMiddleware);
app.use((req, res) => {
res.status(404).json({ message: `Not found` });
});
app.use((err, req, res, next) => {
res.status(500).json({ message: `Internal error: ${err.message}` });
});
const server = http.createServer(app);
server.listen(3000);
}volta ---> 工具版本固定
打开项目时候,自动切换对于的 node 版本和 yarn 版本
$ volta pin node@16mem ---> 缓存结果
缓存相同的输入,以便更快的输出
import mem from 'mem';
import got from 'got';
import delay from 'delay';
const memGot = mem(got, {maxAge: 1000});
await memGot('https://sindresorhus.com');
// This call is cached
await memGot('https://sindresorhus.com');
await delay(2000);
// This call is not cached as the cache has expired
await memGot('https://sindresorhus.com');depark ---> 通过PangRank算法计算最重要文件
$ npx deprank ./fixtures
cosmiconfig ---> 加载配置文件
| Filename | Lines | Dependents | PageRank |
----------------------------------------------------------
| fixtures/core.js | 3 | 1 | 0.284098 |
| fixtures/utils.js | 4 | 3 | 0.268437 |
| fixtures/user/user.js | 4 | 1 | 0.132253 |
| fixtures/todo.js | 6 | 1 | 0.089796 |
| fixtures/user/index.js | 1 | 1 | 0.089796 |
| fixtures/concepts.js | 4 | 1 | 0.079694 |
| fixtures/index.js | 4 | 0 | 0.055926 |cosmiconfig ---> 加载配置文件
dotenv ---> 添加环境变量到node进程中
const { cosmiconfig, cosmiconfigSync } = require('cosmiconfig');
// ...
const explorer = cosmiconfig(moduleName);
// Search for a configuration by walking up directories.
// See documentation for search, below.
explorer.search()
.then((result) => {
// result.config is the parsed configuration object.
// result.filepath is the path to the config file that was found.
// result.isEmpty is true if there was nothing to parse in the config file.
})
.catch((error) => {
// Do something constructive.
});socket.io ---> 双向通信
依赖于 Engine.IO,并不是 websocket。尽管 Socket.IO 确实尽可能使用 WebSocket 作为传输,但它会为每个数据包添加一些元数据:数据包类型、名称空间和需要消息确认时的 ack id。这就是为什么 WebSocket 客户端将无法成功连接到 Socket.IO 服务器,而 Socket.IO 客户端也将无法连接到 WebSocket 服务器
tinypool ---> nodejs workers pool
线程池,也可以试试尤的 yyx990803/okie
birpc ---> 基于消息的双向远程过程调用
基于消息的双向远程过程调用。对 WebSockets 和 Workers 通信很有用
compare-versions ---> semver 版本比较器
比较大小,验证条件等功能
write-file-atomic ---> 原子化写文件
import { compareVersions, compare, satisfies, validate } from 'compare-versions';
compareVersions('11.1.1', '10.0.0'); // 1
compare('10.1.8', '10.0.4', '>'); // true
satisfies('10.0.1', '~10.0.0'); // true
validate('1.0.0-rc.1'); // trueconnect ---> 中间件 HTTP 框架
(async () => {
try {
await writeFileAtomic('message.txt', 'Hello Node', {chown:{uid:100,gid:50}});
console.log('It\'s saved!');
} catch (err) {
console.error(err);
process.exit(1);
}
})();get-node ---> 下载指定版本的 NodeJs
var connect = require('connect');
var http = require('http');
var app = connect();
// gzip/deflate outgoing responses
var compression = require('compression');
app.use(compression());
// store session state in browser cookie
var cookieSession = require('cookie-session');
app.use(cookieSession({
keys: ['secret1', 'secret2']
}));
// parse urlencoded request bodies into req.body
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: false}));
// respond to all requests
app.use(function(req, res){
res.end('Hello from Connect!\n');
});
//create node.js http server and listen on port
http.createServer(app).listen(3000);crawlee ---> NodeJs 爬虫
支持 cheerio、playwright、puppeteer
lucia ---> Authentication 库
import { PlaywrightCrawler, Dataset } from 'crawlee';
// PlaywrightCrawler crawls the web using a headless
// browser controlled by the Playwright library.
const crawler = new PlaywrightCrawler({
// Use the requestHandler to process each of the crawled pages.
async requestHandler({ request, page, enqueueLinks, log }) {
const title = await page.title();
log.info(`Title of ${request.loadedUrl} is '${title}'`);
// Save results as JSON to ./storage/datasets/default
await Dataset.pushData({ title, url: request.loadedUrl });
// Extract links from the current page
// and add them to the crawling queue.
await enqueueLinks();
},
// Uncomment this option to see the browser window.
// headless: false,
});
// Add first URL to the queue and start the crawl.
await crawler.run(['https://crawlee.dev']);Lucia 是一个用 TypeScript 编写的 auth 库,它抽象化了处理会话的复杂
winston ---> logger 工具
ponycode ---> 域名编码
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'user-service' },
transports: [
// - Write all logs with importance level of `error` or less to `error.log`
// - Write all logs with importance level of `info` or less to `combined.log`
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple(),
}));
}ponycode ---> 域名编码
hono ---> Web 框架
支持 deno 和 bun,速度快,支持 JSX
nodemailer ---> Send Email with NodeJs
发送邮件服务
发送邮件服务
下面是我写的一个例子,填入你的邮箱,按下按钮之后,你的邮箱将会收到一封来自我的邮件
codspeed ---> benchmark 测试
除此之外,你可以用这个网站来进行可视化的 HTML 电子邮件设计
例如可以结合 Vitest 做 benchmark
sharp ---> 高性能NodeJs图片加工
典型用例是将常见格式的大图像转换为更小的、对 Web 友好的、不同尺寸的 JPEG、PNG、WebP、GIF 和 AVIF 图像
相似库:jimp-dev/jimp
nock ---> 基于NodeJs的http服务模拟
got ---> 友好的NodeJs的http请求库
import got from 'got';
import nock from 'nock';
const scope = nock('https://sindresorhus.com')
.get('/')
.reply(500, 'Internal server error')
.persist();
try {
await got('https://sindresorhus.com')
} catch (error) {
console.log(error.response.body);
//=> 'Internal server error'
console.log(error.response.retryCount);
//=> 2
}
scope.persist(false);got ---> 友好的NodeJs的http请求库
qnm ---> 查看依赖的详情信息
shx ---> node的便携式shell命令
无关平台,执行shell命令,只需要加上前缀,例如:
无关平台,执行shell命令,只需要加上前缀,例如:
playwright ---> e2e测试框架
适合在没有shell的环境,如windows上使用
- 支持chromium、firefox、webkit
- 页面截图
- 模拟手机型号与地理位置
- 获取浏览器上下文信息
- 拦截网络请求
happy-dom ---> 更加轻量和快速的DOM环境
相比于JSDOM,更加轻量和快速,常用于测试框架、SSR框架中
jsdom ---> 在NodeJs提供DOM环境
属于比较早期的库,很可惜不支持esm
chokidar ---> 监听文件修改
基于NodeJs的fs.watch,但是有着更多的优点
vite-node ---> 给 node 程序 vite 转换的能力
命令行方式使用,直接执行一个 TS 文件
$ npx vite-node index.ts
命令行方式使用,直接执行一个 TS 文件
local-pkg ---> find message of local package
tinybench ---> for benchmark
测试方法的运行时长
import {
getPackageInfo,
importModule,
isPackageExists,
resolveModule,
} from 'local-pkg'
isPackageExists('local-pkg') // true
isPackageExists('foo') // false
await getPackageInfo('local-pkg')
/* {
* name: "local-pkg",
* version: "0.1.0",
* rootPath: "/path/to/node_modules/local-pkg",
* packageJson: {
* ...
* }
* }
*/
// similar to `require.resolve` but works also in ESM
resolveModule('local-pkg')
// '/path/to/node_modules/local-pkg/dist/index.cjs'
// similar to `await import()` but works also in CJS
const { importModule } = await importModule('local-pkg')tinybench ---> for benchmark
why-is-node-running ---> 检测导致进程没结束的原因
import { Bench } from 'tinybench';
const bench = new Bench({ time: 100 });
bench
.add('faster task', () => {
console.log('I am faster')
})
.add('slower task', async () => {
await new Promise(r => setTimeout(r, 1)) // we wait 1ms :)
console.log('I am slower')
})
.todo('unimplemented bench')
await bench.run();
console.table(bench.table());AdminJS ---> admin pane for NodeJs
framework: such as
express、koa、nestjsdatabase adapter: such as
mongoose、sequelize、typeorm
$ npm i adminjs @adminjs/[your framework] @adminjs/[your database adapter]
find-up ---> find a file or directory
Find a file or directory for walking up the parent directories
expect-type ---> Unit test for TS type
node-cron ---> cron for NodeJs
Find a file or directory for walking up the parent directories
/
└── Users
└── sindresorhus
├── unicorn.png
└── foo
└── bar
├── baz
└── example.jssupertest ---> HTTP 测试框架
autocannon ---> HTTP/1.1 Beachmark
Benchmark for http, supports output tables
import cron from 'node-cron';
cron.schedule('* * * * *', () => {
console.log('running a task every minute');
});exit-hook ---> run code when process exit
Support async tasks, But must use with gracefulExit